Approvaltests and PDF - c#

Can I use ApprovalTests with PDF's? I tried using the FileLauncher but it seems the identical PDF's are slightly different at file (bit) level. Or did I use it wrongly?
[TestMethod]
[UseReporter(typeof(FileLauncherReporter))]
public void TestPdf()
{
var createSomePdf = PdfCreate();
ApprovalTests.Approvals.Verify(new FileInfo(createSomePdf.FileName));
}

The Pdf is most likely being created with a timestamp. Depending on the method used to create the pdf, you might be able to mock out the created time. but I had to scrub it.
Here's the code I used to do that.
public static void VerifyPdf(string coverFile)
{
ScrubPdf(coverFile);
Approvals.Verify(new ExistingFileWriter(coverFile));
}
private static void ScrubPdf(string coverFile)
{
long location;
using (var pdf = File.OpenRead(coverFile))
{
location = Find("/CreationDate (", pdf);
}
using (var pdf = File.OpenWrite(coverFile))
{
pdf.Seek(location, SeekOrigin.Begin);
var original = "/CreationDate (D:20110426104115-07'00')";
var desired = new System.Text.ASCIIEncoding().GetBytes(original);
pdf.Write(desired, 0, desired.Length);
pdf.Flush();
}
}

I found a command-line tool, diff-pdf. Compares 2 PDFs and returns exit code 0 if they're the same, 1 if they differ. Download + extract + add it to your PATH.
Downside - it must render both PDFs to perform the diff. If they're big, perf hit.
Approver (based heavily on ApprovalTests.Approvers.FileApprover):
public class DiffPdfApprover : IApprovalApprover
{
public static void Verify(byte[] bytes)
{
var writer = new ApprovalTests.Writers.BinaryWriter(bytes, "pdf");
var namer = ApprovalTests.Approvals.GetDefaultNamer();
var reporter = ApprovalTests.Approvals.GetReporter();
ApprovalTests.Core.Approvals.Verify(new DiffPdfApprover(writer, namer), reporter);
}
private DiffPdfApprover(IApprovalWriter writer, IApprovalNamer namer)
{
this.writer = writer;
this.namer = namer;
}
private readonly IApprovalNamer namer;
private readonly IApprovalWriter writer;
private string approved;
private ApprovalException failure;
private string received;
public virtual bool Approve()
{
string basename = string.Format(#"{0}\{1}", namer.SourcePath, namer.Name);
approved = Path.GetFullPath(writer.GetApprovalFilename(basename));
received = Path.GetFullPath(writer.GetReceivedFilename(basename));
received = writer.WriteReceivedFile(received);
failure = Approve(approved, received);
return failure == null;
}
public static ApprovalException Approve(string approved, string received)
{
if (!File.Exists(approved))
{
return new ApprovalMissingException(received, approved);
}
var process = new Process();
//settings up parameters for the install process
process.StartInfo.FileName = "diff-pdf";
process.StartInfo.Arguments = String.Format("\"{0}\" \"{1}\"", received, approved);
process.Start();
process.WaitForExit();
if (process.ExitCode != 0)
{
return new ApprovalMismatchException(received, approved);
}
return null;
}
public void Fail()
{
throw failure;
}
public void ReportFailure(IApprovalFailureReporter reporter)
{
reporter.Report(approved, received);
}
public void CleanUpAfterSucess(IApprovalFailureReporter reporter)
{
File.Delete(received);
if (reporter is IApprovalReporterWithCleanUp)
{
((IApprovalReporterWithCleanUp)reporter).CleanUp(approved, received);
}
}
}
To Verify:
DiffPdfApprover.Verify(pdfBytes);
diff-pdf can visually show diffs as well. I rolled a Reporter for this, but don't use it much. I think it'll come in handy if there are regressions after initial report dev (which is where I'm at right now).
public class DiffPdfReporter : GenericDiffReporter
{
private static readonly string Path = FindFullPath("diff-pdf.exe");
public DiffPdfReporter() : base(Path,
GetArgs(),
"Please put diff-pdf.exe in your %PATH%. https://github.com/vslavik/diff-pdf. And restart whatever's running the tests. Everything seems to cache the %PATH%.") { }
private static string GetArgs()
{
return "--view \"{0}\" \"{1}\"";
}
private static string FindFullPath(string programInPath)
{
foreach (var path in from path in Environment.GetEnvironmentVariable("path").Split(';')
select path)
{
var fullPath = System.IO.Path.Combine(path, programInPath);
if (File.Exists(fullPath))
return fullPath;
}
return null;
}
}

Looks like this is built in to ApprovalTests now.
usage:
Approvals.VerifyPdfFile(pdfFileLocation);
See the source:
public static void VerifyPdfFile(string pdfFilePath)
{
PdfScrubber.ScrubPdf(pdfFilePath);
Verify(new ExistingFileWriter(pdfFilePath));
}

Related

C# How to use lambda expression with dictionary's value which is a method

I'm creating a program which will execute a command after user input.
Some commands I want to implement are: creating, reading a file, getting current working directory etc.
I created a dictionary which will store user input and corresponding command:
public static Dictionary<string, Action<string[]>> Commands { get; set; } = new Dictionary<string, Action<string[]>>()
{
{"pwd", PrintWorkingDirectory },
{"create", CreateFile },
{"print", ReadFile },
};
Unfortunately I have issues with triggering the method:
public void Run()
{
Console.WriteLine("Welcome, type in command.");
string input = null;
do
{
Console.Write("> ");
input = Console.ReadLine();
Execute(input);
} while (input != "exit");
}
public int Execute(string input)
{
if(Commands.Keys.Contains(input))
{
var action = Commands.Values.FirstOrDefault(); //doesn't work, gives '{command} not found'
}
Console.WriteLine($"{input} not found");
return 1;
}
Also I noticed that this solution would not work with method which is not void, but returns something, as for example CreateFile.
public static string CreateFile(string path)
{
Console.WriteLine("Create a file");
string userInput = Console.ReadLine();
try
{
string[] file = userInput.Split(new char[] { ' ' }).Skip(1).ToArray();
string newPath = Path.GetFullPath(Path.Combine(file));
using (FileStream stream = new FileStream(newPath, FileMode.Create, FileAccess.ReadWrite))
{
stream.Close();
}
using (StreamWriter sw = new StreamWriter(newPath))
{
Console.WriteLine("Please type the content.Press Enter to save.");
sw.WriteLine(Console.ReadLine());
sw.Close();
Console.WriteLine("File {0} has been created", newPath);
}
}
catch (Exception)
{
throw;
}
return path;
}
public static void ReadFile(string[] args)
{
Console.WriteLine("Reading file");
string userInput = Console.ReadLine();
string[] file = userInput.Split(new char[] { ' ' }).Skip(1).ToArray();
string newPath = Path.GetFullPath(Path.Combine(file));
string[] lines = File.ReadAllLines(newPath);
foreach (string line in lines)
Console.WriteLine(line);
}
public static void PrintWorkingDirectory(string[] args)
{
var currentDirectory = Directory.GetCurrentDirectory();
Console.WriteLine(currentDirectory);
}
Could somebody advise me how to deal with these issues?
Is it that this dictionary I created does not make much sense at all?
First problem: You're always fetching the first element of the dictionary and are not using the index operator to retrieve the correct value. Therefore change:
if(Commands.Keys.Contains(input))
{
var action = Commands.Values.FirstOrDefault(); //doesn't work, gives '{command} not found'
}
to:
public int Execute(string input)
{
if (Commands.Keys.Contains(input))
{
var action = Commands[input]; //doesn't work, gives '{command} not found'
action?.Invoke(new string[] { });
}
else
{
Console.WriteLine($"{input} not found");
}
return 1;
}
Regarding to your second question about dictionary usage. I think it is ok to use a dictionary to map different commands based on a given key. The alternative would be switch or if constructs, which can be prevented in Object Oriented Programming.
Regarding to your question about string CreateFile(string path). Since C# is strongly typed language your dictionary can only contain objects of type Action<string[]>, so you can't use methods with another signature than that. One solution is to add another dictionary in the form of Dictionary<string,Func<string[], string>. As a result you'll get more and more dictionaries depending on your method signatures. From here on you should think to build to encapsulate your commands in an e.g. CommandInterpreter class, that could offer an API like that:
void Request(string cmdName, string[] cmdParameters);
string GetLastResult();
int GetLastCode();
Update:
Below code shows a possible object oriented solution (I've left out interfaces to make the code more compact):
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
public class Command<T>
{
public string Name { get; }
public T TheCommand { get; }
public Command(string name, T theCommand)
{
Name = name;
TheCommand = theCommand;
}
}
public interface ICommandResult
{
void Ok(Action<ICommandResult> yes, Action<ICommandResult> no);
int Code { get; }
string Description { get; }
}
public abstract class CommandResult : ICommandResult
{
public int Code { get; }
public string Description { get; }
protected CommandResult(int code, string description)
{
Code = code;
Description = description;
}
public abstract void Ok(Action<ICommandResult> yes, Action<ICommandResult> no);
}
public class NullCommandResult : CommandResult
{
public NullCommandResult() : base(-1, "null")
{
}
public override void Ok(Action<ICommandResult> yes, Action<ICommandResult> no) => no?.Invoke(this);
}
public class SuccessCommandResult : CommandResult
{
public SuccessCommandResult(string description) : base(0, description)
{
}
public override void Ok(Action<ICommandResult> yes, Action<ICommandResult> no) => yes?.Invoke(this);
}
public class CommandInterpreter
{
private Dictionary<string, Func<IEnumerable<string>, ICommandResult>> Commands = new Dictionary<string, Func<IEnumerable<string>, ICommandResult>>();
public void RegisterCommand(Command<Func<IEnumerable<string>, ICommandResult>> cmd)
=> Commands.Add(cmd.Name, cmd.TheCommand);
public ICommandResult RunCommand(string name, IEnumerable<string> parameters)
=> Commands.Where(kvp => kvp.Key.Equals(name))
.Select(kvp => kvp.Value)
.DefaultIfEmpty(strArr => new NullCommandResult())
.Single()
.Invoke(parameters);
}
class Program
{
private CommandInterpreter _cmdInterpreter;
private Program()
{
_cmdInterpreter = new CommandInterpreter();
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("pwd", PrintWorkingDirectory));
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("create", CreateFile));
_cmdInterpreter.RegisterCommand(new Command<Func<IEnumerable<string>, ICommandResult>>("print", ReadFile));
}
private static CommandResult ReadFile(IEnumerable<string> arg) => new SuccessCommandResult("File read");
private static CommandResult CreateFile(IEnumerable<string> arg) => new SuccessCommandResult("File xyz created");
private static CommandResult PrintWorkingDirectory(IEnumerable<string> arg) => new SuccessCommandResult("Printed something");
static void Main() => new Program().Run();
private void Run()
{
Console.WriteLine("Welcome, type in command.");
string input;
do
{
Console.Write("> ");
input = Console.ReadLine();
var cmdResult = _cmdInterpreter.RunCommand(input, Enumerable.Empty<string>());
cmdResult.Ok(
r => Console.WriteLine($"Success: {cmdResult.Code}, {cmdResult.Description}"),
r => Console.WriteLine($"FAILED: {cmdResult.Code}, {cmdResult.Description}"));
} while (input != "exit");
}
}
}
Output:
Welcome, type in command.
> pwd
Success: 0, Printed something
> create
Success: 0, File xyz created
> abc
FAILED: -1, null
>
You can just copy the code and play around with it.

Not able to write JSON data to file using JSON.Net

I am trying to write data into a json file using C# and JSON.NET referring the accepted answer suggested here (How to write a JSON file in C#?).
When I run the code below I am not getting any error message but also the data is not written to the json file.
Functionally what I am trying to achieve is creating a json file that stores times for actions that are done while executing Nunit test
I have tried to implement the solution suggested here (Deserializing JSON data to C# using JSON.NET) but it did not solve my problem
public static class ActionTimeHelper
{
private static readonly string _actionTimeLogFileName = "ActionTimeLog_" + string.Format("{0:yyyy_MM_dd_hhmmss}", DateTime.Now);
[ThreadStatic] private static FileStream _fileStream = null;
[ThreadStatic] private static StreamWriter _actionStreamWriter = null;
[ThreadStatic] private static JsonWriter _jsonWriter = null;
[ThreadStatic] private static List<ActionTimeInfo> actionList = new List<ActionTimeInfo>();
public static void CreateActionTimeLogFile(string logPath, string testName)
{
string dir = logPath + testName + #"\";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
_fileStream = File.Open(dir + _actionTimeLogFileName + ".json", FileMode.CreateNew);
_actionStreamWriter = new StreamWriter(_fileStream);
_jsonWriter = new JsonTextWriter(_actionStreamWriter);
_jsonWriter.Formatting = Formatting.Indented;
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(_jsonWriter, actionList.ToArray().ToString());
//var jarray = JsonConvert.DeserializeObject<List<ActionTimeInfo>>(actionList.ToArray().ToString());
}
public static void StartActionTime(string actionName)
{
actionList.Add(new ActionTimeInfo()
{
ActionName = actionName,
StartTime = DateTime.Now
});
}
public static void EndActionTime(string actionName)
{
ActionTimeInfo endAction = actionList.Find(actionInfo => actionInfo.ActionName.Equals(actionName));
endAction.EndTime = DateTime.Now;
endAction.ExecutionTime = endAction.EndTime.Subtract(endAction.StartTime);
}
}
public class ActionTimeInfo
{
public string ActionName { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan ExecutionTime { get; set; }
}
Usage of above classes in UUnit test:
[Test, Parallelizable, RequiresThread]
public void TestMethod3()
{
ActionTimeHelper.StartActionTime("Login Action");
ActionTimeHelper.EndActionTime("Login Action");
}
[TearDown]
public void TestTearDown()
{
ActionTimeHelper.CreateActionTimeLogFile(TCRunSettings.LogPath, TestContext.CurrentContext.Test.Name);
}
Actual Result: JSON file created in the directory but no list items written to it
Expected Result: JSON file created in the directory along with list items written to it
I think you're missing flush and close for _jsonWriter?
maybe try
_jsonWriter.Flush();
_jsonWriter.Close();
at the end of the method
or even better, use using to wrap the _fileStream, _actionStreamWriter and _jsonWriter

How to specify an input file to DOM of <input type='file'> using AngleSharp?

Using AngleSharp, how do I specify file to fill in <input type="file" name="myInputFile">? I've read this StackOverflow question, but it seems like different than my intended case. I'm trying to fill a form programmatically while uploading a file of my choice.
Every IHtmlInputElement has a Files property that can be used to add files.
var input = document.QuerySelector<IHtmlInputElement>("input[type=file][name=myInputFile]");
input?.Files.Add(file);
In the previously used example the file variable refers to any IFile instance. AngleSharp is a PCL does not come with a proper implementation out of the box, however, a simple one may look like:
class FileEntry : IFile
{
private readonly String _fileName;
private readonly Stream _content;
private readonly String _type;
private readonly DateTime _modified;
public FileEntry(String fileName, String type, Stream content)
{
_fileName = fileName;
_type = type;
_content = content;
_modified = DateTime.Now;
}
public Stream Body
{
get { return _content; }
}
public Boolean IsClosed
{
get { return _content.CanRead == false; }
}
public DateTime LastModified
{
get { return _modified; }
}
public Int32 Length
{
get
{
return (Int32)_content.Length;
}
}
public String Name
{
get { return _fileName; }
}
public String Type
{
get { return _type; }
}
public void Close()
{
_content.Close();
}
public void Dispose()
{
_content.Dispose();
}
public IBlob Slice(Int32 start = 0, Int32 end = Int32.MaxValue, String contentType = null)
{
var ms = new MemoryStream();
_content.Position = start;
var buffer = new Byte[Math.Max(0, Math.Min(end, _content.Length) - start)];
_content.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, buffer.Length);
_content.Position = 0;
return new FileEntry(_fileName, _type, ms);
}
}
A more sophisticated one would auto-determine the MIME type and have constructor overloads to allow passing in (local) file paths etc.
Hope this helps!

Simplest way to save and load information c#

I have a WPF C# application.
I need it to be able to save 'Products'. These products will have a Product name, Customer name, and firmware location. This is my current code for saving and loading however it is not working. I'm thinking of trying a different approach to it all together:
public class Product
{
private string productName;
private string customerName;
private string firmwareLocation;
public string getProductName()
{
return productName;
}
public bool setProductName(string inputProductName)
{
productName = inputProductName;
return true;
}
public string getCustomerName()
{
return customerName;
}
public bool setCustomerName(string inputCustomerName)
{
customerName = inputCustomerName;
return true;
}
public string getFirmwareLocation()
{
return firmwareLocation;
}
public bool setFirmwareLocation(string inputFirmwareLocation)
{
inputFirmwareLocation = firmwareLocation;
return true;
}
public Product(string inProductName, string inCustomerName, string inFirmwareLocation)
{
inProductName = productName;
inCustomerName = customerName;
inFirmwareLocation = firmwareLocation;
}
public void Save(TextWriter textOut)
{
textOut.WriteLineAsync(productName);
textOut.WriteLineAsync(customerName);
textOut.WriteLineAsync(firmwareLocation);
}
public bool Save(string filename)
{
TextWriter textOut = null;
try
{
textOut = new StreamWriter(filename);
Save(textOut);
}
catch
{
return false;
}
finally
{
if (textOut != null)
{
textOut.Close();
}
}
return true;
}
public static Product Load (string filename)
{
Product result = null;
System.IO.TextReader textIn = null;
try
{
textIn = new System.IO.StreamReader(filename);
string productNameText = textIn.ReadLine();
string customerNameText = textIn.ReadLine();
string firmwareLocationText = textIn.ReadLine();
result = new Product(productNameText, customerNameText, firmwareLocationText);
}
catch
{
return null;
}
finally
{
if (textIn != null) textIn.Close();
}
return result;
}
}
}
It's a little unclear what you mean by "not working" but I'd suggest that you just use the standard .NET serialization/deserialization libraries for this rather than trying to reinvent the wheel. There's no need to do anything custom here. See the following: https://msdn.microsoft.com/en-us/library/mt656716.aspx
As a side note, why are you using getX() and setX() methods instead of properties? It's not standard C#. For example, the following:
private string productName;
public string getProductName()
{
return productName;
}
public bool setProductName(string inputProductName)
{
productName = inputProductName;
return true;
}
should be
public string ProductName
{
get;
set;
}
I'm guessing that one of the reasons your code isn't working is that it has multiple glaring race conditions. For example, all 3 of your writes are asynchronous and fired off right after the other; there's no guarantee that the previous one will be done when you start the next one. It's not even clear to me that you're guaranteed to write the lines in a particular order (which you're counting to be the case in your deserialization logic). It's also completely possible (likely, actually) that you'll close the file in the middle of your write operations.
I'd also suggest a "using" block for the file streams.

Unit Testing methods that delete multiple files from a specified directory using NUnit

I am a novice in Unit and Integration testing. I have a class which contains a few methods for deleting multiple files in a specified directory and moves files to a different directory. In total there are 3 methods. Full class code:
public class FilesUtility : IFilesUtility
{
public void TidyUpXmlFiles(bool isDebug, string XmlFileDirectory)
{
if (isDebug)
{
MoveXmlFiles(XmlFileDirectory);
}
else
{
DeleteXmlFiles(XmlFileDirectory);
}
}
private static void MoveXmlFiles(string XmlFileDirectory)
{
var di = new DirectoryInfo(XmlFileDirectory);
// Create a subdirectory in the parent directory called XmlArchive.
DirectoryInfo destinationDirectory = di.CreateSubdirectory("XmlArchive");
string destinationDir = destinationDirectory.ToString();
if (!Directory.Exists(destinationDir))
{
Directory.CreateDirectory(destinationDir);
}
foreach (string file in Directory.GetFiles(XmlFileDirectory,
"*.Xml"))
{
// Use static Path method to extract only the file name from the path.
string fileName = Path.GetFileName(file);
if (fileName != null)
{
string destFile = Path.Combine(destinationDir, fileName);
//if the same file exists in the destination folder, delete the file and move the new file.
if (File.Exists(file))
{
File.Delete(destFile);
File.Move(file, destFile);
}
}
}
}
private static void DeleteXmlFiles(string XmlFileDirectory)
{
foreach (var file in Directory.GetFiles(XmlFileDirectory,
"*.Xml"))
{
File.Delete(file);
}
}
public void MoveFaultyXml(string XmlFileDirectory, string fileFullPath)
{
var di = new DirectoryInfo(XmlFileDirectory);
// Create a subdirectory in the parent directory called XmlArchive.
var destinationDirectory = di.CreateSubdirectory("FaultyXml");
var faultyXmlFileName = Path.GetFileName(fileFullPath);
var destinationDir = destinationDirectory.ToString();
if (!Directory.Exists(destinationDir))
{
Directory.CreateDirectory(destinationDir);
}
if (faultyXmlFileName != null)
{
string destFile = Path.Combine(destinationDir, faultyXmlFileName);
//if the same file exists in the destination folder, delete the file and move the new file.
if (!File.Exists(fileFullPath)) return;
File.Delete(destFile);
File.Move(fileFullPath, destFile);
}
}
I have created an Interface to this method to use Moq to Mock if that is what I need to do I am not sure.
The Interface code is:
public interface IFilesUtility
{
void TidyUpXbrlFiles(bool isDebug, string xbrlFileDirectory);
void MoveFaultyXbrl(string xbrlFileDirectory, string fileFullPath);
}
Now I want to be able to test the above methods to make sure that they can actually pick up a list of XML files from a directory and delete/move all of them.
I have been reading about Moq and mocking. I have also been reading about Dependency injection but my problem is I have been reading too much on it and now can't think of where to start.
I am hoping somebody can explain to me using the example code posted above how i can construct a sucessful test for this code.
I have read so many questions about this on Stackoverflow and I hope you will not close this as a duplicate because like I said my problem is I have been reading too much about this.
I think I might understand it if somebody could explain it to me using one of the methods in my example.
I don't know how to to do a correct [TestFixtureSetup] which I think I will need in my case where i can get a list of files to use on each test.
Thanks to all that take time to answer :)
Here's what I do to test file-handling methods:
Create the file on the local system. Sometimes I create these manually in the MasterFiles folder and then commit them as part of the source then call UseTestMasterFile to copy it into the test folder. Sometimes I create them within the test itself and save them into the test folder.
Run my test.
Clean up the test files.
Here's the test code...
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using System.IO;
public class FilesUtilityTests {
[Test]
public void TidyUpXmlFilesDeletesXmlFilesWhenNotDebugging() {
string testFilePath = TestFileHelper.UseTestMasterFile("YourXmlFile.xml");
FilesUtility util = new FilesUtility();
util.TidyUpXmlFiles(false, TestFileHelper.TestDirectoryName);
Assert.IsFalse(File.Exists(testFilePath));
// any other tests here.
}
}
// Obviously, this could be in a separate dll that you reference on all test projects.
public static class TestFileHelper {
public const string TestFolderName = #"Testing\UnitTests";
public const string DefaultMasterFilesFolderName = "MasterFiles";
public static string DefaultTestDirectoryName {
get { return Path.Combine(Path.GetDirectoryName(System.Environment.CurrentDirectory), TestFolderName); }
}
public static string TestDirectoryName {
get { return testDirectoryName ?? DefaultTestDirectoryName; }
set { testDirectoryName = value; }
}
private static string testDirectoryName;
public static string MasterFilesFolderName {
get { return masterFilesFolderName ?? DefaultMasterFilesFolderName; }
set { masterFilesFolderName = value; }
}
private static string masterFilesFolderName;
public static string TestFileExtension { get; set; }
public static string BuildTestFileName(string fileName) {
if (String.IsNullOrWhiteSpace(Path.GetPathRoot(fileName)))
fileName = Path.Combine(TestDirectoryName, fileName);
if (String.IsNullOrEmpty(Path.GetExtension(fileName)))
fileName = Path.ChangeExtension(fileName, TestFileExtension);
return fileName;
}
public static string BuildTestMasterFileName(string fileName) {
if (Path.IsPathRooted(fileName))
return Path.Combine(Path.Combine(Path.GetDirectoryName(fileName), MasterFilesFolderName), Path.GetFileName(fileName));
else
return Path.Combine(Path.Combine(TestDirectoryName, MasterFilesFolderName), fileName);
}
public static string UseTestMasterFile(string fileName) {
string dest = BuildTestFileName(fileName);
string source = BuildTestMasterFileName(dest);
DeleteTestFile(dest);
ClearReadOnlyAttributes(source);
File.Copy(source, dest, true);
return dest;
}
public static void DeleteTestFile(string filePath) {
if (String.IsNullOrWhiteSpace(filePath)) { return; }
if (!File.Exists(filePath)) { return; }
ClearReadOnlyAttributes(filePath);
File.Delete(filePath);
}
public static void ClearReadOnlyAttributes(string filePath) {
if (String.IsNullOrWhiteSpace(filePath)) { return; }
if (!File.Exists(filePath)) { return; }
FileAttributes attributes = File.GetAttributes(filePath);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(filePath, attributes ^ FileAttributes.ReadOnly);
}
public static void SetReadOnlyAttributes(string filePath) {
if (String.IsNullOrWhiteSpace(filePath)) { return; }
if (!File.Exists(filePath)) { return; }
FileAttributes attributes = File.GetAttributes(filePath);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(filePath, attributes | FileAttributes.ReadOnly);
}
}
Expanding on the comment that Maess left, generally you do not want to test things that handle file input/output, even in an integration test. The reason is that is the responsibility of the file system, and read/write permissions get involved, plus you'll hammer the drive.
If you absolutely must test that you can delete them, you'll definitely want to do that in an integration test, and you do NOT want to run this thing very often.
Generally, Unit tests are designed to be small, fast, independent, and ran on just about every change. They should generally be isolated to testing your code, not others (like System.IO).
In order to unit test your code, you'll need to mock against the IFilesUtility inteface, and pass this in as a collaborator to the class that would be calling the TidyUp or Move functions.
Then you can verify that these are called, and I think this will provide a lot more value than testing whether or not the system is able to delete files.
Something like
public void WhenDoingActionXthenTidyUpIsCalled(){
var filesUtil = new Mock<IFilesUtility>();
var sut = new YourClassUnderTest( filesUtil.object );
sut.DoSomethingThatTriggersTidyUp();
filesUtil.verify( f => f.TidyUp(), Times.Once());
}

Categories

Resources