//
// Copyright © 2018 Ranorex All rights reserved
//
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Ranorex.Core.Testing;
namespace Ranorex.AutomationHelpers.UserCodeCollections
{
///
/// A collection of useful file methods.
///
[UserCodeCollection]
public static class FileLibrary
{
private const string libraryName = "FileLibrary";
private const string newLineRegexPattern = "(\r\n)|(\n)|(\r)";
///
/// Creates a log file containing a custom text in the output folder.
///
/// Text that the log file should contain
/// Prefix used for the log filename
/// Extension of the log file
[UserCodeMethod]
public static void WriteToFile(string text, string filenamePrefix, string fileExtension)
{
var now = System.DateTime.Now;
var strTimestamp = now.ToString("yyyyMMdd_HHmmss");
var filename = filenamePrefix + "_" + strTimestamp + "." + fileExtension;
Report.Info(filename);
try
{
//Create the File
using (FileStream fs = File.Create(filename))
{
var info = new UTF8Encoding(true).GetBytes(text);
fs.Write(info, 0, info.Length);
}
}
catch (Exception ex)
{
Utils.ReportException(ex, libraryName);
}
}
///
/// Opens an existing file and adds a new line of text at the end of it.
///
/// The text to add to the file.
/// The Full qualified path to load the file including filename and extension.
/// If true, adds the text on a newline. Otherwise, adds it without a line break.
[UserCodeMethod]
public static void AppendStringToExistingFile(string text, string path, bool addNewLine)
{
Report.Info("Add new text to file: " + path);
if (addNewLine)
{
File.AppendAllText(path, Environment.NewLine + text);
}
else
{
File.AppendAllText(path, text);
}
}
///
/// Checks if files in a directory exist.
///
/// The relative or absolute path to search for the files
/// The pattern to search for in the filename
/// Number of expected files to be found
/// Defines the search timeout in seconds
[UserCodeMethod]
public static void CheckFilesExist(string path, string pattern, int expectedCount, int timeout)
{
var listofFiles = Directory.GetFiles(path, pattern);
var start = System.DateTime.Now;
while (listofFiles.Length != expectedCount && System.DateTime.Now < start.AddSeconds(timeout))
{
listofFiles = Directory.GetFiles(path, pattern);
}
Report.Info("Check if '" + expectedCount + "' file(s) with pattern '" + pattern + "' exist in the directory '" + path + "'. Search time " + timeout + " seconds.");
Validate.AreEqual(listofFiles.Length, expectedCount);
}
///
/// Deletes files.
///
/// The relative or absolute path to search for the files
/// The pattern to search for in the filename
[UserCodeMethod]
public static void DeleteFiles(string path, string pattern)
{
var listofFiles = Directory.GetFiles(path, pattern);
if (listofFiles.Length == 0)
{
Report.Warn("No files have been found in '" + path + "' with the pattern '" + pattern + "'.");
}
foreach (string file in listofFiles)
{
try
{
File.Delete(file);
Report.Info("File has been deleted: " + file.ToString());
}
catch (Exception ex)
{
Utils.ReportException(ex, libraryName);
}
}
}
///
/// Repeatedly checks if files in a directory exist.
///
/// The relative or absolute path to search for the files
/// The pattern to search for in the filename
/// Defines the search timeout in milliseconds
/// Sets the interval in milliseconds at which the files are checked for the pattern
[UserCodeMethod]
public static void WaitForFile(string path, string pattern, int duration, int interval)
{
path = GetPathForFile(path);
var bFound = Directory.GetFiles(path, pattern).Length > 0;
var start = System.DateTime.Now;
while (!bFound && (System.DateTime.Now < start + TimeSpan.FromMilliseconds(duration)))
{
bFound = Directory.GetFiles(path, pattern).Length > 0;
if (bFound)
{
break;
}
Delay.Duration(Duration.FromMilliseconds(interval), false);
}
if (bFound)
{
Report.Success("Validation", "File with pattern '" + pattern + "' was found in directory '" + path + "'.");
}
else
{
Report.Failure("Validation", "File with pattern '" + pattern + "' wasn't found in directory '" + path + "'.");
}
}
///
/// Compares content of two binary files.
///
/// The relative or absolute path of the first file
/// The relative or absolute path of the second file
[UserCodeMethod]
public static void ValidateFilesBinaryEqual(string filePath1, string filePath2)
{
try
{
filePath1 = GetPathForFile(filePath1);
filePath2 = GetPathForFile(filePath2);
if (!FilesExist(filePath1, filePath2))
{
return;
}
var fi1 = new FileInfo(filePath1);
var fi2 = new FileInfo(filePath2);
if (fi1.Length != fi2.Length)
{
Report.Failure("Files '" + filePath1 + "' and '" + filePath2 + "' are not equal because they differ in size.");
return;
}
const int bufferSize = 65536;
using (var fs1 = new FileStream(filePath1, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize))
using (var fs2 = new FileStream(filePath2, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize))
{
var tempBufferSize = sizeof(Int64);
var tempBuffer1 = new byte[tempBufferSize];
var tempBuffer2 = new byte[tempBufferSize];
for (var i = 0L; i < (fi1.Length / tempBufferSize) + 1; i++)
{
fs1.Read(tempBuffer1, 0, tempBufferSize);
fs2.Read(tempBuffer2, 0, tempBufferSize);
if (BitConverter.ToInt64(tempBuffer1, 0) != BitConverter.ToInt64(tempBuffer2, 0))
{
Report.Failure("Files '" + filePath1 + "' and '" + filePath2 + "' are not equal.");
return;
}
}
}
Report.Success("Files '" + filePath1 + "' and '" + filePath2 + "' are equal.");
}
catch (Exception ex)
{
Utils.ReportException(ex, libraryName);
}
}
///
/// Compares content of two text files.
///
/// The relative or absolute path of the first file
/// The relative or absolute path of the second file
[UserCodeMethod]
public static void ValidateFilesTextEqual(string filePath1, string filePath2)
{
ValidateFilesTextEqual(filePath1, filePath2, true);
}
///
/// Compares content of two text files.
///
/// The relative or absolute path of the first file
/// The relative or absolute path of the second file
/// If true, line endings will be normalized before comparison.
/// Original files will not be changed.
[UserCodeMethod]
public static void ValidateFilesTextEqual(string filePath1, string filePath2, bool normalizeLineEndings)
{
try
{
filePath1 = GetPathForFile(filePath1);
filePath2 = GetPathForFile(filePath2);
if (!FilesExist(filePath1, filePath2))
{
return;
}
var fileContent1 = File.ReadAllText(filePath1);
if (normalizeLineEndings)
{
fileContent1 = Regex.Replace(fileContent1, newLineRegexPattern, "\r\n");
}
var fileContent2 = File.ReadAllText(filePath2);
if (normalizeLineEndings)
{
fileContent2 = Regex.Replace(fileContent2, newLineRegexPattern, "\r\n");
}
if (fileContent1 != fileContent2)
{
Report.Failure("Files '" + filePath1 + "' and '" + filePath2 + "' are not equal.");
ValidateFileContentLineByLine(fileContent1, fileContent2);
return;
}
Report.Success("Files '" + filePath1 + "' and '" + filePath2 + "' are equal.");
}
catch (Exception ex)
{
Utils.ReportException(ex, libraryName);
}
}
///
/// Checks line by line if strings are identical.
/// Line separator is "\r\n"
///
/// The string with the content of file 1 using \r\n as line separator.
/// The string with the content of file 2 using \r\n as line separator.
[UserCodeMethod]
public static void ValidateFileContentLineByLine(string fileContent1, string fileContent2)
{
string[] stringSeparators = new string[] { "\r\n" };
string[] lines1 = fileContent1.Split(stringSeparators, StringSplitOptions.None);
string[] lines2 = fileContent2.Split(stringSeparators, StringSplitOptions.None);
if (lines1.Length!=lines2.Length) {
Report.Error("Files have different length. They will be compared line by line until the length of the smallest one.");
Report.Info("Number of lines in file 1: " + lines1.Length);
Report.Info("Number of lines in file 2: " + lines2.Length);
}
var minLength = Math.Min(lines1.Length, lines2.Length);
bool differencesHaveBeenFound = false;
string differencesThatHaveBeenFound = "";
for (int i = 0; i < minLength; i++) {
if (lines1[i]!=lines2[i]) {
differencesThatHaveBeenFound += "File 1: " + lines1[i] + "\r\n" + "File 2: " + lines2[i] + "\r\n \r\n";
differencesHaveBeenFound = true;
}
}
if (differencesHaveBeenFound) {
Report.Error("The differences below have been found between both files.");
Report.Info(differencesThatHaveBeenFound);
}
}
///
/// Checks if file contains text specified.
///
/// The relative or absolute path to the file
/// The text to search for
[UserCodeMethod]
public static void ValidateFileContainsText(string filePath, string text)
{
ValidateFileContainsText(filePath, text, "utf-8");
}
///
/// Checks if file contains text specified.
///
/// The relative or absolute path to the file
/// The text to search for
/// Encoding of a file
[UserCodeMethod]
public static void ValidateFileContainsText(string filePath, string text, string fileEncoding)
{
try
{
var encoding = Encoding.GetEncoding(fileEncoding);
filePath = GetPathForFile(filePath);
if (!FilesExist(filePath))
{
return;
}
var textFound = false;
if (Regex.IsMatch(text, newLineRegexPattern))
{
if (File.ReadAllText(filePath, encoding).Contains(text))
{
Report.Success("Text '" + text + "' was found in file " + filePath + "'.");
textFound = true;
}
}
else
{
using (StreamReader sr = new StreamReader(filePath, encoding))
{
var line = "";
var i = 1;
while ((line = sr.ReadLine()) != null)
{
if (line.IndexOf(text, StringComparison.OrdinalIgnoreCase) != -1)
{
Report.Success("Text '" + text + "' was found on line " + i + ": '" + line + "'.");
textFound = true;
}
++i;
}
}
}
if (!textFound)
{
Report.Failure("Text '" + text + "' was not found in file '" + filePath + "'.");
}
}
catch (Exception ex)
{
Utils.ReportException(ex, libraryName);
}
}
private static string GetPathForFile(string path)
{
return path.StartsWith(".") ? Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, path)) : path;
}
private static bool FilesExist(params string[] filePaths)
{
bool filesExist = true;
foreach (string filePath in filePaths)
{
if (!File.Exists(filePath))
{
Report.Error("The file '" + filePath + "' does not exist.");
filesExist = false;
}
}
return filesExist;
}
}
}