using Amphora; using System; using System.Collections.Generic; using System.IO; using UnitTestSharp; namespace Glass.UnitTests { public class DiskFileSystemTests : TestFixture { public class TempDirectory : IDisposable { public string Path { get; } public TempDirectory() { Path = System.IO.Path.Combine( System.IO.Path.GetTempPath(), "GlassDiskFileSystemTests-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(Path); } public string In(string name) { return System.IO.Path.Combine(Path, name); } public void Dispose() { Directory.Delete(Path, recursive: true); } } public class UserFolderTests : TestFixture { public void IsTheNamedFolderDirectlyInsideTheUsersHome() { string folder = DiskFileSystem.UserFolder("SomeGame"); CheckEqual("SomeGame", System.IO.Path.GetFileName(folder)); CheckEqual(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), System.IO.Path.GetDirectoryName(folder)); } } public class RootsTests : TestFixture { public void IsNotEmpty() { CheckGreater(new DiskFileSystem().Roots.Count, 0); } public void EveryRoot_IsATidyPath() { var fileSystem = new DiskFileSystem(); foreach (string root in fileSystem.Roots) { CheckNull(fileSystem.GetParent(root)); } } } public class GetParentTests : TestFixture { public void OfAFile_IsItsDirectory() { using (var temp = new TempDirectory()) { CheckEqual(temp.Path, new DiskFileSystem().GetParent(temp.In("a.txt"))); } } public void OfARoot_IsNull() { var fileSystem = new DiskFileSystem(); CheckNull(fileSystem.GetParent(Path.GetPathRoot(Path.GetTempPath()))); } public void OfAChildOfARoot_IsTheRoot() { var fileSystem = new DiskFileSystem(); string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(root, fileSystem.GetParent(Path.Combine(root, "x"))); } public void Null_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentNullException)); fileSystem.GetParent(null); } public void Empty_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.GetParent(""); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.GetParent("docs"); } public void WithDotDotPart_Throws() { var fileSystem = new DiskFileSystem(); string path = Path.Combine(Path.GetTempPath(), "a", "..", "b"); CheckThrow(typeof(ArgumentException)); fileSystem.GetParent(path); } public void WithTrailingSeparator_IsTheSameAsWithout() { var fileSystem = new DiskFileSystem(); string path = Path.Combine(Path.GetTempPath(), "a"); CheckEqual(fileSystem.GetParent(path), fileSystem.GetParent(path + Path.DirectorySeparatorChar)); } public void WithTwoTrailingSeparators_Throws() { var fileSystem = new DiskFileSystem(); string path = Path.Combine(Path.GetTempPath(), "a") + Path.DirectorySeparatorChar; CheckThrow(typeof(ArgumentException)); fileSystem.GetParent(path + Path.DirectorySeparatorChar); } public void WithInvalidCharacter_Throws() { var fileSystem = new DiskFileSystem(); string path = Path.GetTempPath() + "a|b"; CheckThrow(typeof(ArgumentException)); fileSystem.GetParent(path); } public void DriveRelative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.GetParent("C:docs"); } } public class CombineTests : TestFixture { public void JoinsDirectoryAndName() { using (var temp = new TempDirectory()) { CheckEqual(temp.In("a.txt"), new DiskFileSystem().Combine(temp.Path, "a.txt")); } } public void DirectoryWithTrailingSeparator_JoinsLikeWithout() { using (var temp = new TempDirectory()) { CheckEqual(temp.In("a.txt"), new DiskFileSystem().Combine(temp.Path + Path.DirectorySeparatorChar, "a.txt")); } } public void OntoARoot_DoesNotDoubleTheSeparator() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(root + "x", new DiskFileSystem().Combine(root, "x")); } public void BadName_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Combine(Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar), "a/b"); } public void BadDirectory_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Combine("docs", "a"); } } public class GetNameTests : TestFixture { public void OfAFile_IsItsLastPart() { using (var temp = new TempDirectory()) { CheckEqual("a.txt", new DiskFileSystem().GetName(temp.In("a.txt"))); } } public void OfARoot_IsEmpty() { CheckEqual("", new DiskFileSystem().GetName(Path.GetPathRoot(Path.GetTempPath()))); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.GetName("docs"); } } public class ValidateFileNameTests : TestFixture { [IgnoreTest] private InvalidFileName ProblemWith(string name) { return FileSystemFailures.InvalidName.Read(new DiskFileSystem().ValidateFileName(name)); } public void OrdinaryName_IsOk() { CheckEqual(Status.Ok, new DiskFileSystem().ValidateFileName("readme.txt")); } public void NameWithSpacesInside_IsOk() { CheckEqual(Status.Ok, new DiskFileSystem().ValidateFileName("my file.txt")); } public void NameStartingWithADot_IsOk() { CheckEqual(Status.Ok, new DiskFileSystem().ValidateFileName(".hidden")); } public void NameStartingWithAReservedStem_IsOk() { CheckEqual(Status.Ok, new DiskFileSystem().ValidateFileName("console.txt")); } public void Null_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentNullException)); fileSystem.ValidateFileName(null); } public void Empty_IsBlank() { CheckEqual(FileNameProblem.Blank, ProblemWith("").Problem); } public void Spaces_AreBlank() { CheckEqual(FileNameProblem.Blank, ProblemWith(" ").Problem); } public void Dot_IsADotName() { CheckEqual(FileNameProblem.DotName, ProblemWith(".").Problem); } public void DotDot_IsADotName() { CheckEqual(FileNameProblem.DotName, ProblemWith("..").Problem); } public void Separator_IsForbiddenAndNamed() { InvalidFileName problem = ProblemWith("a/b"); CheckEqual(FileNameProblem.ForbiddenCharacter, problem.Problem); CheckEqual('/', problem.Character); } public void Colon_IsForbidden() { CheckEqual(FileNameProblem.ForbiddenCharacter, ProblemWith("a:b").Problem); } public void Tab_IsAControlCharacter() { InvalidFileName problem = ProblemWith("a\tb"); CheckEqual(FileNameProblem.ControlCharacter, problem.Problem); CheckEqual('\t', problem.Character); } public void TrailingPeriod_IsRejected() { CheckEqual(FileNameProblem.TrailingSpaceOrPeriod, ProblemWith("a.").Problem); } public void TrailingSpace_IsRejected() { CheckEqual(FileNameProblem.TrailingSpaceOrPeriod, ProblemWith("a ").Problem); } public void DeviceName_IsReserved() { CheckEqual(FileNameProblem.ReservedName, ProblemWith("NUL").Problem); } public void DeviceNameInAnyCase_IsReserved() { CheckEqual(FileNameProblem.ReservedName, ProblemWith("com1").Problem); } public void DeviceNameWithExtension_IsReserved() { CheckEqual(FileNameProblem.ReservedName, ProblemWith("con.txt").Problem); } public void DeviceNameWithSpaceBeforeExtension_IsReserved() { CheckEqual(FileNameProblem.ReservedName, ProblemWith("aux .txt").Problem); } } public class ResolveTests : TestFixture { private static readonly string Root = Path.GetPathRoot(Path.GetTempPath()); private static readonly string Directory = Path.Combine(Root, "alpha", "beta"); [IgnoreTest] private ResolvedPath Resolved(string text) { return new DiskFileSystem().Resolve(Directory, text).Value; } [IgnoreTest] private StatusOr Attempt(string text) { return new DiskFileSystem().Resolve(Directory, text); } [IgnoreTest] private Status ReasonFor(string name) { return new DiskFileSystem().ValidateFileName(name); } public void Name_JoinsOntoTheDirectory() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "c.txt"), NamesDirectory: false), Resolved("c.txt")); } public void Name_InADirectoryWithATrailingSeparator_HasOneSeparator() { string directory = Directory + Path.DirectorySeparatorChar; CheckEqual(Path.Combine(Directory, "c"), new DiskFileSystem().Resolve(directory, "c").Value.Path); } public void ForwardSlashes_SeparateParts() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "x", "y"), NamesDirectory: false), Resolved("x/y")); } public void AbsolutePath_IgnoresTheDirectory() { string path = Path.Combine(Root, "gamma", "delta"); CheckEqual(new ResolvedPath(path, NamesDirectory: false), Resolved(path)); } public void TheRoot_IsADirectory() { CheckEqual(new ResolvedPath(Root, NamesDirectory: true), Resolved(Root)); } public void LeadingSeparator_IsTheRootOfTheDirectorysDrive() { CheckEqual(new ResolvedPath(Path.Combine(Root, "x"), NamesDirectory: false), Resolved(Path.DirectorySeparatorChar + "x")); } public void TrailingSeparator_NamesADirectory() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "x"), NamesDirectory: true), Resolved("x\\")); } public void Dot_IsTheDirectory() { CheckEqual(new ResolvedPath(Directory, NamesDirectory: false), Resolved(".")); } public void DotDot_IsTheParent() { CheckEqual(new ResolvedPath(Path.Combine(Root, "alpha"), NamesDirectory: false), Resolved("..")); } public void DotDot_PastTheRoot_StaysAtTheRoot() { CheckEqual(new ResolvedPath(Root, NamesDirectory: false), Resolved("..\\..\\..\\..")); } public void DotDot_AfterAName_CancelsIt() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "b"), NamesDirectory: false), Resolved("a\\..\\b")); } public void DoubledSeparators_AreSkipped() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "a", "b"), NamesDirectory: false), Resolved("a\\\\b")); } public void NothingNeedsToExist() { CheckEqual(new ResolvedPath(Path.Combine(Directory, "no", "such"), NamesDirectory: false), Resolved("no\\such")); } public void DriveLetter_StartsAtThatDrivesRoot() { CheckEqual(new ResolvedPath("Z:\\x\\y", NamesDirectory: false), Resolved("Z:\\x\\y")); } public void DriveLetterWithForwardSlash_StartsAtThatDrivesRoot() { CheckEqual(new ResolvedPath("z:\\x", NamesDirectory: false), Resolved("z:/x")); } public void BareDriveLetter_IsThatDrivesRoot() { CheckEqual(new ResolvedPath("Z:\\", NamesDirectory: false), Resolved("Z:")); } public void DriveLetterThenAName_FailsOnTheColon() { CheckEqual(ReasonFor("Z:x"), Attempt("Z:x").Status); } public void ShareOnTheNetwork_IsNotFound() { CheckEqual(FileSystemFailures.NotFound.Fail("\\\\server\\share\\x"), Attempt("\\\\server\\share\\x").Status); } public void PartEndingInAPeriod_GivesTheReasonForIt() { CheckEqual(ReasonFor("x."), Attempt("ok\\x.").Status); } public void ReservedDeviceName_GivesTheReasonForIt() { CheckEqual(ReasonFor("con"), Attempt("con").Status); } public void Empty_FailsAsBlank() { CheckEqual(ReasonFor(""), Attempt("").Status); } public void NullText_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentNullException)); fileSystem.Resolve(Directory, null); } public void NullDirectory_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentNullException)); fileSystem.Resolve(null, "a"); } public void RelativeDirectory_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Resolve("docs", "a"); } } public class GetKindTests : TestFixture { public void Directory_IsDirectory() { using (var temp = new TempDirectory()) { CheckEqual(FileKind.Directory, new DiskFileSystem().GetKind(temp.Path)); } } public void File_IsFile() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), "hi"); CheckEqual(FileKind.File, new DiskFileSystem().GetKind(temp.In("a.txt"))); } } public void Missing_IsNone() { using (var temp = new TempDirectory()) { CheckEqual(FileKind.None, new DiskFileSystem().GetKind(temp.In("missing"))); } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.GetKind("docs"); } } public class ListTests : TestFixture { public void Empty_GivesNothing() { using (var temp = new TempDirectory()) { CheckEqual(0, new DiskFileSystem().List(temp.Path).Value.Count); } } public void DirectoryWithTrailingSeparator_ListsLikeWithout() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); IReadOnlyList entries = new DiskFileSystem().List(temp.Path + Path.DirectorySeparatorChar).Value; CheckEqual(1, entries.Count); CheckEqual("a.txt", entries[0].Name); } } public void GivesFilesWithSizeAndDirectoriesWithout() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), "hello"); Directory.CreateDirectory(temp.In("sub")); IReadOnlyList entries = new DiskFileSystem().List(temp.Path).Value; CheckEqual(2, entries.Count); CheckEqual("a.txt", entries[0].Name); CheckFalse(entries[0].IsDirectory); CheckEqual(5L, entries[0].Size); CheckNotNull(entries[0].Modified); CheckEqual("sub", entries[1].Name); CheckTrue(entries[1].IsDirectory); CheckNull(entries[1].Size); } } public void AHiddenFile_IsListedWithTheHiddenAttribute() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("shown.txt"), ""); File.WriteAllText(temp.In("hidden.txt"), ""); File.SetAttributes(temp.In("hidden.txt"), FileAttributes.Hidden); IReadOnlyList entries = new DiskFileSystem().List(temp.Path).Value; CheckEqual(2, entries.Count); CheckEqual("hidden.txt", entries[0].Name); CheckEqual(FileEntryAttributes.Hidden, entries[0].Attributes); CheckEqual("shown.txt", entries[1].Name); CheckEqual(FileEntryAttributes.None, entries[1].Attributes); } } public void ASystemFile_IsListedWithTheHiddenAttribute() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("system.txt"), ""); File.SetAttributes(temp.In("system.txt"), FileAttributes.System); CheckEqual( FileEntryAttributes.Hidden, new DiskFileSystem().List(temp.Path).Value[0].Attributes); } } public void AHiddenDirectory_IsListedWithTheHiddenAttribute() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("secret")); File.SetAttributes(temp.In("secret"), FileAttributes.Hidden | FileAttributes.Directory); CheckEqual( FileEntryAttributes.Hidden, new DiskFileSystem().List(temp.Path).Value[0].Attributes); } } public void Missing_FailsAsNotFound() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().List(temp.In("missing")).Status); } } public void AFile_FailsAsNotADirectory() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(FileSystemFailures.NotADirectory.Fail(temp.In("a.txt")), new DiskFileSystem().List(temp.In("a.txt")).Status); } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.List("docs"); } } public class CreateDirectoryTests : TestFixture { public void MakesTheDirectory() { using (var temp = new TempDirectory()) { CheckEqual(Status.Ok, new DiskFileSystem().CreateDirectory(temp.In("new"))); CheckTrue(Directory.Exists(temp.In("new"))); } } public void ParentMissing_FailsAsNotFoundForTheParent() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().CreateDirectory(temp.In("missing\\new"))); CheckFalse(Directory.Exists(temp.In("missing"))); } } public void ParentIsAFile_FailsAsNotADirectoryForTheParent() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(FileSystemFailures.NotADirectory.Fail(temp.In("a.txt")), new DiskFileSystem().CreateDirectory(temp.In("a.txt\\new"))); } } public void DirectoryAlreadyThere_FailsAsAlreadyExists() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.AlreadyExists.Fail(temp.Path), new DiskFileSystem().CreateDirectory(temp.Path)); } } public void FileAlreadyThere_FailsAsAlreadyExists() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(FileSystemFailures.AlreadyExists.Fail(temp.In("a.txt")), new DiskFileSystem().CreateDirectory(temp.In("a.txt"))); } } public void Root_FailsAsAlreadyExists() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.AlreadyExists.Fail(root), new DiskFileSystem().CreateDirectory(root)); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.CreateDirectory("docs"); } } public class OpenReadTests : TestFixture { public void ReadsTheFileContents() { using (var temp = new TempDirectory()) { File.WriteAllBytes(temp.In("a.bin"), new byte[] { 1, 2, 3 }); CheckEqual(new byte[] { 1, 2, 3 }, InMemoryFileSystemTests.ReadAll(new DiskFileSystem().OpenRead(temp.In("a.bin")).Value)); } } public void Stream_CanSeekAndCannotWrite() { using (var temp = new TempDirectory()) { File.WriteAllBytes(temp.In("a.bin"), new byte[] { 1, 2, 3 }); using (Stream stream = new DiskFileSystem().OpenRead(temp.In("a.bin")).Value) { stream.Seek(2, SeekOrigin.Begin); CheckEqual(3, stream.ReadByte()); CheckFalse(stream.CanWrite); } } } public void Missing_FailsAsNotFound() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().OpenRead(temp.In("missing")).Status); } } public void MissingParent_FailsAsNotFound() { using (var temp = new TempDirectory()) { string path = temp.In("missing\\a.bin"); CheckEqual(FileSystemFailures.NotFound.Fail(path), new DiskFileSystem().OpenRead(path).Status); } } public void Directory_FailsAsIsADirectory() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.IsADirectory.Fail(temp.Path), new DiskFileSystem().OpenRead(temp.Path).Status); } } public void FileOpenedForWriting_FailsAsIoError() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); using (fileSystem.OpenWrite(temp.In("a.bin")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.bin")), fileSystem.OpenRead(temp.In("a.bin")).Status); } } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.OpenRead("a.bin"); } } public class OpenWriteTests : TestFixture { public void MakesTheFileWithWhatWasWritten() { using (var temp = new TempDirectory()) { InMemoryFileSystemTests.WriteAll(new DiskFileSystem().OpenWrite(temp.In("a.bin")).Value, 4, 5); CheckEqual(new byte[] { 4, 5 }, File.ReadAllBytes(temp.In("a.bin"))); } } public void ExistingFile_IsReplaced() { using (var temp = new TempDirectory()) { File.WriteAllBytes(temp.In("a.bin"), new byte[] { 1, 2, 3, 4 }); InMemoryFileSystemTests.WriteAll(new DiskFileSystem().OpenWrite(temp.In("a.bin")).Value, 9); CheckEqual(new byte[] { 9 }, File.ReadAllBytes(temp.In("a.bin"))); } } public void Stream_CanSeek() { using (var temp = new TempDirectory()) { using (Stream stream = new DiskFileSystem().OpenWrite(temp.In("a.bin")).Value) { stream.Write(new byte[] { 1, 2, 3 }, 0, 3); stream.Seek(1, SeekOrigin.Begin); stream.WriteByte(9); } CheckEqual(new byte[] { 1, 9, 3 }, File.ReadAllBytes(temp.In("a.bin"))); } } public void ParentMissing_FailsAsNotFoundForTheParent() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().OpenWrite(temp.In("missing\\a.bin")).Status); } } public void ParentIsAFile_FailsAsNotADirectoryForTheParent() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(FileSystemFailures.NotADirectory.Fail(temp.In("a.txt")), new DiskFileSystem().OpenWrite(temp.In("a.txt\\b.bin")).Status); } } public void Directory_FailsAsIsADirectory() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.IsADirectory.Fail(temp.Path), new DiskFileSystem().OpenWrite(temp.Path).Status); } } public void Root_FailsAsIsADirectory() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.IsADirectory.Fail(root), new DiskFileSystem().OpenWrite(root).Status); } public void FileAlreadyOpenForWriting_FailsAsIoError() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); using (fileSystem.OpenWrite(temp.In("a.bin")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.bin")), fileSystem.OpenWrite(temp.In("a.bin")).Status); } } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.OpenWrite("a.bin"); } } public class DeleteTests : TestFixture { public void File_RemovesIt() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(Status.Ok, new DiskFileSystem().Delete(temp.In("a.txt"))); CheckFalse(File.Exists(temp.In("a.txt"))); } } public void EmptyDirectory_RemovesIt() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("sub")); CheckEqual(Status.Ok, new DiskFileSystem().Delete(temp.In("sub"))); CheckFalse(Directory.Exists(temp.In("sub"))); } } public void DirectoryWithContents_FailsAndKeepsIt() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); CheckEqual(FileSystemFailures.DirectoryNotEmpty.Fail(temp.In("sub")), new DiskFileSystem().Delete(temp.In("sub"))); CheckTrue(File.Exists(temp.In("sub\\a.txt"))); } } public void Missing_FailsAsNotFound() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().Delete(temp.In("missing"))); } } public void FileOpenForReading_FailsAsIoError() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); using (fileSystem.OpenRead(temp.In("a.txt")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.txt")), fileSystem.Delete(temp.In("a.txt"))); } } } public void Root_FailsAsAccessDenied() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.AccessDenied.Fail(root), new DiskFileSystem().Delete(root)); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Delete("a.txt"); } } public class TrashTests : TestFixture { public void File_LeavesItsDirectory() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), "hello"); CheckTrue(new DiskFileSystem().Trash(temp.In("a.txt")).IsOk); CheckFalse(File.Exists(temp.In("a.txt"))); } } public void File_GivesAnItemThatNamesItsPath() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(temp.In("a.txt"), new DiskFileSystem().Trash(temp.In("a.txt")).Value.OriginalPath); } } public void NonEmptyDirectory_TakesEverythingInsideWithIt() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); CheckTrue(new DiskFileSystem().Trash(temp.In("sub")).IsOk); CheckFalse(Directory.Exists(temp.In("sub"))); } } public void TheTrashFolder_IsHidden() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); new DiskFileSystem().Trash(temp.In("a.txt")); CheckTrue((File.GetAttributes(temp.In(".GlassTrash")) & FileAttributes.Hidden) != 0); } } public void TheTrashFolder_NeverShowsInAListing() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); File.WriteAllText(temp.In("b.txt"), ""); fileSystem.Trash(temp.In("a.txt")); CheckEqual(1, fileSystem.List(temp.Path).Value.Count); } } public void Missing_FailsAsNotFound() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().Trash(temp.In("missing")).Status); } } public void TheTrashFolderItself_FailsAsAccessDenied() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); fileSystem.Trash(temp.In("a.txt")); CheckEqual(FileSystemFailures.AccessDenied.Fail(temp.In(".GlassTrash")), fileSystem.Trash(temp.In(".GlassTrash")).Status); } } public void Root_FailsAsAccessDenied() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.AccessDenied.Fail(root), new DiskFileSystem().Trash(root).Status); } public void FileOpenForReading_FailsAsIoErrorAndLeavesNothingBehind() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); using (fileSystem.OpenRead(temp.In("a.txt")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.txt")), fileSystem.Trash(temp.In("a.txt")).Status); } CheckTrue(File.Exists(temp.In("a.txt"))); CheckFalse(Directory.Exists(temp.In(".GlassTrash"))); } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Trash("a.txt"); } } public class RestoreTests : TestFixture { public void File_ComesBackWithItsContents() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), "hello"); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; CheckEqual(Status.Ok, fileSystem.Restore(item)); CheckEqual("hello", File.ReadAllText(temp.In("a.txt"))); } } public void Directory_ComesBackWithEverythingInside() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("sub")).Value; CheckEqual(Status.Ok, fileSystem.Restore(item)); CheckTrue(File.Exists(temp.In("sub\\a.txt"))); } } public void TheLastItemOut_TakesTheTrashFolderWithIt() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; fileSystem.Restore(item); CheckFalse(Directory.Exists(temp.In(".GlassTrash"))); } } public void WithAnotherItemStillIn_KeepsTheTrashFolder() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); File.WriteAllText(temp.In("b.txt"), ""); TrashedItem first = fileSystem.Trash(temp.In("a.txt")).Value; TrashedItem second = fileSystem.Trash(temp.In("b.txt")).Value; fileSystem.Restore(first); CheckEqual(Status.Ok, fileSystem.Restore(second)); CheckTrue(File.Exists(temp.In("b.txt"))); } } public void PathNowTaken_FailsAndCanBeRestoredOnceItIsFree() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), "old"); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; File.WriteAllText(temp.In("a.txt"), "new"); CheckEqual(FileSystemFailures.AlreadyExists.Fail(temp.In("a.txt")), fileSystem.Restore(item)); File.Delete(temp.In("a.txt")); CheckEqual(Status.Ok, fileSystem.Restore(item)); CheckEqual("old", File.ReadAllText(temp.In("a.txt"))); } } public void Twice_FailsAsNotFoundTheSecondTime() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; fileSystem.Restore(item); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("a.txt")), fileSystem.Restore(item)); } } public void AfterItsDirectoryWasTrashed_FailsAsNotFound() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("sub\\a.txt")).Value; fileSystem.Trash(temp.In("sub")); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("sub\\a.txt")), fileSystem.Restore(item)); } } public void IdThatIsNotOneWeHandedOut_FailsAsNotFound() { using (var temp = new TempDirectory()) { var item = new TrashedItem(temp.In("a.txt"), "..\\x"); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("a.txt")), new DiskFileSystem().Restore(item)); } } public void ItemWithoutAnId_FailsAsNotFound() { using (var temp = new TempDirectory()) { var item = new TrashedItem(temp.In("a.txt"), null); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("a.txt")), new DiskFileSystem().Restore(item)); } } public void Root_FailsAsNotFound() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.NotFound.Fail(root), new DiskFileSystem().Restore(new TrashedItem(root, "1"))); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Restore(new TrashedItem("a.txt", "1")); } } public class PurgeTests : TestFixture { public void File_IsGoneForGood() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; CheckEqual(Status.Ok, fileSystem.Purge(item)); CheckFalse(Directory.Exists(temp.In(".GlassTrash"))); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("a.txt")), fileSystem.Restore(item)); } } public void Directory_GoesWithEverythingInside() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("sub")).Value; CheckEqual(Status.Ok, fileSystem.Purge(item)); CheckFalse(Directory.Exists(temp.In(".GlassTrash"))); } } public void WithAnotherItemStillIn_KeepsTheTrashFolder() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); File.WriteAllText(temp.In("b.txt"), ""); TrashedItem first = fileSystem.Trash(temp.In("a.txt")).Value; TrashedItem second = fileSystem.Trash(temp.In("b.txt")).Value; fileSystem.Purge(first); CheckEqual(Status.Ok, fileSystem.Restore(second)); } } public void Twice_FailsAsNotFoundTheSecondTime() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; fileSystem.Purge(item); CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("a.txt")), fileSystem.Purge(item)); } } public void FileOpenForReading_FailsAsIoErrorAndStaysRestorable() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); TrashedItem item = fileSystem.Trash(temp.In("a.txt")).Value; string waiting = Path.Combine(temp.Path, ".GlassTrash", item.Id); using (new FileStream(waiting, FileMode.Open, FileAccess.Read, FileShare.None)) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.txt")), fileSystem.Purge(item)); } CheckEqual(Status.Ok, fileSystem.Restore(item)); } } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Purge(new TrashedItem("a.txt", "1")); } } public class RenameTests : TestFixture { public void File_TakesTheNameAndKeepsItsContents() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), "hello"); CheckEqual(Status.Ok, new DiskFileSystem().Rename(temp.In("a.txt"), "b.txt")); CheckFalse(File.Exists(temp.In("a.txt"))); CheckEqual("hello", File.ReadAllText(temp.In("b.txt"))); } } public void Directory_TakesItsContentsWithIt() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("sub")); File.WriteAllText(temp.In("sub\\a.txt"), ""); CheckEqual(Status.Ok, new DiskFileSystem().Rename(temp.In("sub"), "other")); CheckTrue(File.Exists(temp.In("other\\a.txt"))); CheckFalse(Directory.Exists(temp.In("sub"))); } } public void TheNameItHas_ChangesNothing() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(Status.Ok, new DiskFileSystem().Rename(temp.In("a.txt"), "a.txt")); CheckTrue(File.Exists(temp.In("a.txt"))); } } public void OnlyTheCaseOfAFile_Changes() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), "hello"); CheckEqual(Status.Ok, new DiskFileSystem().Rename(temp.In("a.txt"), "A.txt")); CheckEqual("A.txt", Path.GetFileName(Directory.GetFiles(temp.Path)[0])); CheckEqual("hello", File.ReadAllText(temp.In("A.txt"))); } } public void OnlyTheCaseOfADirectory_Changes() { using (var temp = new TempDirectory()) { Directory.CreateDirectory(temp.In("sub")); CheckEqual(Status.Ok, new DiskFileSystem().Rename(temp.In("sub"), "SUB")); CheckEqual("SUB", Path.GetFileName(Directory.GetDirectories(temp.Path)[0])); } } public void NameOfAnotherEntry_FailsAndKeepsBoth() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); Directory.CreateDirectory(temp.In("sub")); CheckEqual(FileSystemFailures.AlreadyExists.Fail(temp.In("sub")), new DiskFileSystem().Rename(temp.In("a.txt"), "sub")); CheckTrue(File.Exists(temp.In("a.txt"))); CheckTrue(Directory.Exists(temp.In("sub"))); } } public void NameOfAnotherEntryInADifferentCase_FailsAndKeepsBoth() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); File.WriteAllText(temp.In("B.txt"), ""); CheckEqual(FileSystemFailures.AlreadyExists.Fail(temp.In("b.txt")), new DiskFileSystem().Rename(temp.In("a.txt"), "b.txt")); } } public void NameTheSystemRefuses_GivesTheReasonAndChangesNothing() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); CheckEqual(fileSystem.ValidateFileName("a\\b"), fileSystem.Rename(temp.In("a.txt"), "a\\b")); CheckTrue(File.Exists(temp.In("a.txt"))); } } public void Missing_FailsAsNotFoundBeforeJudgingTheName() { using (var temp = new TempDirectory()) { CheckEqual(FileSystemFailures.NotFound.Fail(temp.In("missing")), new DiskFileSystem().Rename(temp.In("missing"), " ")); } } public void FileOpenForReading_FailsAsIoErrorAndKeepsItsName() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); using (fileSystem.OpenRead(temp.In("a.txt")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.txt")), fileSystem.Rename(temp.In("a.txt"), "b.txt")); } CheckTrue(File.Exists(temp.In("a.txt"))); } } public void CaseChangeOfAFileOpenForReading_FailsAndKeepsItsName() { using (var temp = new TempDirectory()) { var fileSystem = new DiskFileSystem(); File.WriteAllText(temp.In("a.txt"), ""); using (fileSystem.OpenRead(temp.In("a.txt")).Value) { CheckEqual(FileSystemFailures.IoError.Fail(temp.In("a.txt")), fileSystem.Rename(temp.In("a.txt"), "A.txt")); } CheckEqual("a.txt", Path.GetFileName(Directory.GetFiles(temp.Path)[0])); } } public void Root_FailsAsAccessDenied() { string root = Path.GetPathRoot(Path.GetTempPath()); CheckEqual(FileSystemFailures.AccessDenied.Fail(root), new DiskFileSystem().Rename(root, "x")); } public void Relative_Throws() { var fileSystem = new DiskFileSystem(); CheckThrow(typeof(ArgumentException)); fileSystem.Rename("a.txt", "b.txt"); } public void NullName_Throws() { using (var temp = new TempDirectory()) { File.WriteAllText(temp.In("a.txt"), ""); CheckThrow(typeof(ArgumentNullException)); new DiskFileSystem().Rename(temp.In("a.txt"), null); } } } } }