diff --git a/Directory.Packages.props b/Directory.Packages.props index 80b727627..c1ee99a57 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -31,6 +31,7 @@ + diff --git a/Source/Testably.Abstractions.AccessControl/Testably.Abstractions.AccessControl.csproj b/Source/Testably.Abstractions.AccessControl/Testably.Abstractions.AccessControl.csproj index 72082860d..1db38b623 100644 --- a/Source/Testably.Abstractions.AccessControl/Testably.Abstractions.AccessControl.csproj +++ b/Source/Testably.Abstractions.AccessControl/Testably.Abstractions.AccessControl.csproj @@ -25,6 +25,9 @@ <_Parameter1>true <_Parameter1_TypeName>System.Boolean + + <_Parameter1>Testably.Abstractions.AccessControl.Tests + diff --git a/Source/Testably.Abstractions.Compression/Internal/ZipUtilities.cs b/Source/Testably.Abstractions.Compression/Internal/ZipUtilities.cs index 0516470ca..ea3701804 100644 --- a/Source/Testably.Abstractions.Compression/Internal/ZipUtilities.cs +++ b/Source/Testably.Abstractions.Compression/Internal/ZipUtilities.cs @@ -7,6 +7,8 @@ namespace Testably.Abstractions.Internal; internal static class ZipUtilities { + private const string SearchPattern = "*"; + internal static IZipArchiveEntry CreateEntryFromFile( IZipArchive destination, string sourceFileName, @@ -28,7 +30,7 @@ internal static IZipArchiveEntry CreateEntryFromFile( DateTime lastWrite = destination.FileSystem.File.GetLastWriteTime(sourceFileName); - if (lastWrite.Year < 1980 || lastWrite.Year > 2107) + if (lastWrite.Year is < 1980 or > 2107) { lastWrite = new DateTime(1980, 1, 1, 0, 0, 0); } @@ -79,7 +81,7 @@ internal static void CreateFromDirectory(IFileSystem fileSystem, } foreach (IFileSystemInfo file in di - .EnumerateFileSystemInfos("*", SearchOption.AllDirectories)) + .EnumerateFileSystemInfos(SearchPattern, SearchOption.AllDirectories)) { directoryIsEmpty = false; diff --git a/Source/Testably.Abstractions.Compression/Testably.Abstractions.Compression.csproj b/Source/Testably.Abstractions.Compression/Testably.Abstractions.Compression.csproj index 6c3a31a50..b49aa471b 100644 --- a/Source/Testably.Abstractions.Compression/Testably.Abstractions.Compression.csproj +++ b/Source/Testably.Abstractions.Compression/Testably.Abstractions.Compression.csproj @@ -20,4 +20,10 @@ + + + <_Parameter1>Testably.Abstractions.Compression.Tests + + + diff --git a/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs b/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs index e331d5e42..1ec1e0ca4 100644 --- a/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs +++ b/Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs @@ -512,6 +512,15 @@ internal IReadOnlyList GetContainers() .Select(x => x.Value) .ToList(); + /// + /// Removes the drive with the given . + /// + internal IStorageDrive? RemoveDrive(string driveName) + { + _drives.TryRemove(driveName, out IStorageDrive? drive); + return drive; + } + private void CheckAndAdjustParentDirectoryTimes(IStorageLocation location) { IStorageContainer? parentContainer = GetContainer(location.GetParent()); diff --git a/Source/Testably.Abstractions.Testing/Storage/LocationExtensions.cs b/Source/Testably.Abstractions.Testing/Storage/LocationExtensions.cs index d9350087a..dcb7fb617 100644 --- a/Source/Testably.Abstractions.Testing/Storage/LocationExtensions.cs +++ b/Source/Testably.Abstractions.Testing/Storage/LocationExtensions.cs @@ -8,7 +8,8 @@ internal static class LocationExtensions { [return: NotNullIfNotNull("location")] public static IStorageLocation? ThrowIfNotFound( - this IStorageLocation? location, MockFileSystem fileSystem, + this IStorageLocation? location, + MockFileSystem fileSystem, Action fileNotFoundException, Action? directoryNotFoundException = null) { @@ -38,7 +39,8 @@ internal static class LocationExtensions } public static IStorageLocation ThrowExceptionIfNotFound( - this IStorageLocation location, MockFileSystem fileSystem, + this IStorageLocation location, + MockFileSystem fileSystem, bool allowMissingFile = false, Func? onDirectoryNotFound = null, Func? onFileNotFound = null) diff --git a/Tests/Testably.Abstractions.AccessControl.Tests/AccessControlHelperTests.cs b/Tests/Testably.Abstractions.AccessControl.Tests/AccessControlHelperTests.cs new file mode 100644 index 000000000..6d1e368ee --- /dev/null +++ b/Tests/Testably.Abstractions.AccessControl.Tests/AccessControlHelperTests.cs @@ -0,0 +1,48 @@ +using System.IO; + +namespace Testably.Abstractions.AccessControl.Tests; + +// ReSharper disable once PartialTypeWithSinglePart +public abstract partial class AccessControlHelperTests + : FileSystemTestBase + where TFileSystem : IFileSystem +{ + [Fact] + public void GetExtensibilityOrThrow_DirectoryInfo_ShouldNotThrow() + { + IDirectoryInfo sut = FileSystem.DirectoryInfo.New("foo"); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeNull(); + } + + [Fact] + public void GetExtensibilityOrThrow_FileSystemStream_ShouldNotThrow() + { + FileSystemStream sut = FileSystem.FileStream.New("foo", FileMode.Create); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeNull(); + } + + [Fact] + public void GetExtensibilityOrThrow_FileInfo_ShouldNotThrow() + { + IFileInfo sut = FileSystem.FileInfo.New("foo"); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeNull(); + } +} diff --git a/Tests/Testably.Abstractions.AccessControl.Tests/Internal/AccessControlHelperTests.cs b/Tests/Testably.Abstractions.AccessControl.Tests/Internal/AccessControlHelperTests.cs new file mode 100644 index 000000000..83168ce0e --- /dev/null +++ b/Tests/Testably.Abstractions.AccessControl.Tests/Internal/AccessControlHelperTests.cs @@ -0,0 +1,126 @@ +using NSubstitute; +using System.IO; +using Testably.Abstractions.Helpers; + +namespace Testably.Abstractions.AccessControl.Tests.Internal; + +public sealed class AccessControlHelperTests +{ + [Fact] + public void ThrowIfMissing_MissingDirectoryInfo_ShouldThrowDirectoryNotFoundException() + { + MockFileSystem fileSystem = new(); + IDirectoryInfo sut = fileSystem.DirectoryInfo.New("foo"); + + Exception? exception = Record.Exception(() => + { + sut.ThrowIfMissing(); + }); + + exception.Should().BeOfType() + .Which.HResult.Should().Be(-2147024893); + exception!.Message.Should().Contain($"'{sut.FullName}'"); + } + + [Fact] + public void ThrowIfMissing_ExistingDirectoryInfo_ShouldNotThrow() + { + MockFileSystem fileSystem = new(); + IDirectoryInfo sut = fileSystem.DirectoryInfo.New("foo"); + fileSystem.Directory.CreateDirectory("foo"); + + Exception? exception = Record.Exception(() => + { + sut.ThrowIfMissing(); + }); + + exception.Should().BeNull(); + } + + [Fact] + public void ThrowIfMissing_MissingFileInfo_ShouldThrowFileNotFoundException() + { + MockFileSystem fileSystem = new(); + IFileInfo sut = fileSystem.FileInfo.New("foo"); + + Exception? exception = Record.Exception(() => + { + sut.ThrowIfMissing(); + }); + + exception.Should().BeOfType() + .Which.HResult.Should().Be(-2147024894); + exception!.Message.Should().Contain($"'{sut.FullName}'"); + } + + [Fact] + public void ThrowIfMissing_ExistingFileInfo_ShouldNotThrow() + { + MockFileSystem fileSystem = new(); + IFileInfo sut = fileSystem.FileInfo.New("foo"); + fileSystem.File.WriteAllText("foo", "some content"); + + Exception? exception = Record.Exception(() => + { + sut.ThrowIfMissing(); + }); + + exception.Should().BeNull(); + } + + [Fact] + public void GetExtensibilityOrThrow_CustomDirectoryInfo_ShouldThrowNotSupportedException() + { + IDirectoryInfo? sut = Substitute.For(); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeOfType() + .Which.Message.Should() + .Contain(nameof(IFileSystemExtensibility)).And + .Contain(sut.GetType().Name); + } + + [Fact] + public void GetExtensibilityOrThrow_CustomFileSystemStream_ShouldThrowNotSupportedException() + { + FileSystemStream sut = new CustomFileSystemStream(); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeOfType() + .Which.Message.Should() + .Contain(nameof(IFileSystemExtensibility)).And + .Contain(sut.GetType().Name); + } + + [Fact] + public void GetExtensibilityOrThrow_CustomFileInfo_ShouldThrowNotSupportedException() + { + IFileInfo? sut = Substitute.For(); + + Exception? exception = Record.Exception(() => + { + sut.GetExtensibilityOrThrow(); + }); + + exception.Should().BeOfType() + .Which.Message.Should() + .Contain(nameof(IFileSystemExtensibility)).And + .Contain(sut.GetType().Name); + } + + private class CustomFileSystemStream : FileSystemStream + { + /// + public CustomFileSystemStream() : base(Null, ".", false) + { + } + } +} diff --git a/Tests/Testably.Abstractions.AccessControl.Tests/Testably.Abstractions.AccessControl.Tests.csproj b/Tests/Testably.Abstractions.AccessControl.Tests/Testably.Abstractions.AccessControl.Tests.csproj index de9aba0c6..2b163db76 100644 --- a/Tests/Testably.Abstractions.AccessControl.Tests/Testably.Abstractions.AccessControl.Tests.csproj +++ b/Tests/Testably.Abstractions.AccessControl.Tests/Testably.Abstractions.AccessControl.Tests.csproj @@ -12,9 +12,8 @@ - + + diff --git a/Tests/Testably.Abstractions.Compression.Tests/Internal/ExecuteTests.cs b/Tests/Testably.Abstractions.Compression.Tests/Internal/ExecuteTests.cs new file mode 100644 index 000000000..99af40b2b --- /dev/null +++ b/Tests/Testably.Abstractions.Compression.Tests/Internal/ExecuteTests.cs @@ -0,0 +1,34 @@ +using Testably.Abstractions.Internal; + +namespace Testably.Abstractions.Compression.Tests.Internal; + +public sealed class ExecuteTests +{ + [Fact] + public void WhenRealFileSystem_MockFileSystem_ShouldExecuteOnMockFileSystem() + { + bool onRealFileSystemExecuted = false; + bool onMockFileSystemExecuted = false; + MockFileSystem fileSystem = new(); + Execute.WhenRealFileSystem(fileSystem, + () => onRealFileSystemExecuted = true, + () => onMockFileSystemExecuted = true); + + onRealFileSystemExecuted.Should().BeFalse(); + onMockFileSystemExecuted.Should().BeTrue(); + } + + [Fact] + public void WhenRealFileSystem_RealFileSystem_ShouldExecuteOnRealFileSystem() + { + bool onRealFileSystemExecuted = false; + bool onMockFileSystemExecuted = false; + RealFileSystem fileSystem = new(); + Execute.WhenRealFileSystem(fileSystem, + () => onRealFileSystemExecuted = true, + () => onMockFileSystemExecuted = true); + + onRealFileSystemExecuted.Should().BeTrue(); + onMockFileSystemExecuted.Should().BeFalse(); + } +} diff --git a/Tests/Testably.Abstractions.Compression.Tests/ZipArchiveEntry/ExtensionTests.cs b/Tests/Testably.Abstractions.Compression.Tests/ZipArchiveEntry/ExtensionTests.cs index 2fdc5e131..a22f7691b 100644 --- a/Tests/Testably.Abstractions.Compression.Tests/ZipArchiveEntry/ExtensionTests.cs +++ b/Tests/Testably.Abstractions.Compression.Tests/ZipArchiveEntry/ExtensionTests.cs @@ -105,6 +105,37 @@ public void ExtractToFile_WithOverwrite_ShouldOverwriteExistingFile() .Should().Be("FooFooFoo"); } + + [SkippableTheory] + [InlineData("2000-01-01T12:14:15")] + [InlineData("1980-01-01T00:00:00")] + [InlineData("2107-12-31T23:59:59")] + public void ExtractToFile_LastWriteTime_ShouldBeCopiedFromFile(string lastWriteTimeString) + { + DateTime lastWriteTime = DateTime.Parse(lastWriteTimeString); + FileSystem.Initialize() + .WithSubdirectory("foo") + .WithSubdirectory("bar").Initialized(s => s + .WithFile("bar.txt")); + FileSystem.File.WriteAllText("bar/foo.txt", "FooFooFoo"); + FileSystem.File.SetLastWriteTime("bar/foo.txt", lastWriteTime); + FileSystem.ZipFile() + .CreateFromDirectory("foo", "destination.zip", CompressionLevel.NoCompression, + false); + using FileSystemStream stream = FileSystem.File.Open("destination.zip", + FileMode.Open, FileAccess.ReadWrite); + IZipArchive archive = FileSystem.ZipArchive().New(stream, ZipArchiveMode.Update); + archive.CreateEntryFromFile("bar/foo.txt", "foo/bar.txt", + CompressionLevel.NoCompression); + IZipArchiveEntry entry = archive.Entries.Single(); + + entry.ExtractToFile("bar/bar.txt", true); + + FileSystem.File.ReadAllText("bar/bar.txt") + .Should().Be("FooFooFoo"); + FileSystem.FileInfo.New("bar/bar.txt").LastWriteTime.Should().Be(lastWriteTime); + } + [SkippableFact] public void ExtractToFile_IncorrectEntryType_ShouldThrowIOException() { diff --git a/Tests/Testably.Abstractions.Testing.Tests/FileSystemInitializerOptionsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/FileSystemInitializerOptionsTests.cs new file mode 100644 index 000000000..4274b71f6 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/FileSystemInitializerOptionsTests.cs @@ -0,0 +1,15 @@ +#if NET6_0_OR_GREATER +#endif + +namespace Testably.Abstractions.Testing.Tests; + +public sealed class FileSystemInitializerOptionsTests +{ + [Fact] + public void InitializeTempDirectory_ShouldBeInitializedToTrue() + { + FileSystemInitializerOptions sut = new(); + + sut.InitializeTempDirectory.Should().BeTrue(); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemExtensionsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemExtensionsTests.cs new file mode 100644 index 000000000..fcfb71226 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemExtensionsTests.cs @@ -0,0 +1,21 @@ +using Testably.Abstractions.Testing.Helpers; +using Testably.Abstractions.Testing.Storage; + +namespace Testably.Abstractions.Testing.Tests; + +public class MockFileSystemExtensionsTests +{ + [Fact] + public void GetDefaultDrive_WithoutDrives_ShouldThrowInvalidOperationException() + { + MockFileSystem fileSystem = new(); + (fileSystem.Storage as InMemoryStorage)?.RemoveDrive(string.Empty.PrefixRoot()); + + Exception? exception = Record.Exception(() => + { + fileSystem.GetDefaultDrive(); + }); + + exception.Should().BeOfType(); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemTests.cs b/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemTests.cs index 0c18004d9..cea274681 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/MockFileSystemTests.cs @@ -106,6 +106,17 @@ public void FileSystemMock_ShouldInitializeDriveFromCurrentDirectory() drives.Should().Contain(d => d.Name == driveName); } + [SkippableFact] + public void ToString_ShouldContainStorageInformation() + { + MockFileSystem sut = new(); + sut.File.WriteAllText("foo", "bar"); + + string result = sut.ToString(); + + result.Should().Contain("directories: 0, files: 1"); + } + [SkippableTheory] [AutoData] public void WithAccessControl_Denied_CreateDirectoryShouldThrowIOException( diff --git a/Tests/Testably.Abstractions.Testing.Tests/MockRandomSystemTests.cs b/Tests/Testably.Abstractions.Testing.Tests/MockRandomSystemTests.cs new file mode 100644 index 000000000..f075c7b49 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/MockRandomSystemTests.cs @@ -0,0 +1,14 @@ +namespace Testably.Abstractions.Testing.Tests; + +public class MockRandomSystemTests +{ + [Fact] + public void ToString_ShouldContainMockRandomSystem() + { + MockRandomSystem randomSystem = new(); + + string result = randomSystem.ToString(); + + result.Should().Contain(nameof(MockRandomSystem)); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs b/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs index 36ff5f92d..6599b30b2 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests; @@ -89,4 +90,38 @@ public void Sleep_LessThanInfiniteTimeSpan_ShouldThrowArgumentOutOfRangeExceptio exception.Should().BeOfType(); } + + [Fact] + public void ToString_WithFixedContainer_ShouldContainTimeProvider() + { + DateTime now = TimeTestHelper.GetRandomTime(); + MockTimeSystem timeSystem = new(TimeProvider.Use(now)); + + string result = timeSystem.ToString(); + + result.Should().Contain("Fixed"); + result.Should().Contain($"{now.ToUniversalTime()}Z"); + } + + [Fact] + public void ToString_WithNowContainer_ShouldContainTimeProvider() + { + MockTimeSystem timeSystem = new(TimeProvider.Now()); + + string result = timeSystem.ToString(); + + result.Should().Contain("Now"); + result.Should().Contain($"{timeSystem.DateTime.UtcNow}Z"); + } + + [Fact] + public void ToString_WithRandomContainer_ShouldContainTimeProvider() + { + MockTimeSystem timeSystem = new(TimeProvider.Random()); + + string result = timeSystem.ToString(); + + result.Should().Contain("Random"); + result.Should().Contain($"{timeSystem.DateTime.UtcNow}Z"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Storage/InMemoryContainerTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Storage/InMemoryContainerTests.cs index 92fb2c8f7..4968d41c2 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Storage/InMemoryContainerTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Storage/InMemoryContainerTests.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using Testably.Abstractions.Testing.FileSystem; using Testably.Abstractions.Testing.Storage; using Testably.Abstractions.Testing.Tests.TestHelpers; @@ -100,6 +101,18 @@ public void AdjustAttributes_ShouldHaveReparsePointAttributeWhenLinkTargetIsNotN } #endif + [Theory] + [AutoData] + public void Container_ShouldProvideCorrectTimeAndFileSystem(string path) + { + MockFileSystem fileSystem = new(); + IStorageLocation location = InMemoryLocation.New(null, path); + IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + + sut.FileSystem.Should().BeSameAs(fileSystem); + sut.TimeSystem.Should().BeSameAs(fileSystem.TimeSystem); + } + [Theory] [AutoData] public void Decrypt_Encrypted_ShouldDecryptBytes( @@ -177,6 +190,41 @@ public void Encrypt_ShouldEncryptBytes( fileContainer.GetBytes().Should().NotBeEquivalentTo(bytes); } + [Theory] + [AutoData] + public void RequestAccess_ToString_DeleteAccess_ShouldContainAccessAndShare(string path, + FileAccess access, FileShare share) + { + MockFileSystem fileSystem = new(); + fileSystem.Initialize() + .WithFile(path); + IStorageLocation location = fileSystem.Storage.GetLocation(path); + IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + + IStorageAccessHandle result = sut.RequestAccess(access, share, true); + + result.ToString().Should().NotContain(access.ToString()); + result.ToString().Should().Contain("Delete"); + result.ToString().Should().Contain(share.ToString()); + } + + [Theory] + [AutoData] + public void RequestAccess_ToString_ShouldContainAccessAndShare(string path, FileAccess access, + FileShare share) + { + MockFileSystem fileSystem = new(); + fileSystem.Initialize() + .WithFile(path); + IStorageLocation location = fileSystem.Storage.GetLocation(path); + IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + + IStorageAccessHandle result = sut.RequestAccess(access, share); + + result.ToString().Should().Contain(access.ToString()); + result.ToString().Should().Contain(share.ToString()); + } + [Theory] [AutoData] public void RequestAccess_WithoutDrive_ShouldThrowDirectoryNotFoundException( @@ -215,48 +263,60 @@ public void TimeContainer_Time_Set_WithUnspecifiedKind_ShouldSetToProvidedKind( [Theory] [AutoData] - public void Container_ShouldProvideCorrectTimeAndFileSystem(string path) + public void TimeContainer_ToString_ShouldReturnUtcTime( + string path, DateTime time) { + time = DateTime.SpecifyKind(time, DateTimeKind.Local); + string expectedString = time.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ssZ"); MockFileSystem fileSystem = new(); IStorageLocation location = InMemoryLocation.New(null, path); - IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + IStorageContainer fileContainer = InMemoryContainer.NewFile(location, fileSystem); - sut.FileSystem.Should().BeSameAs(fileSystem); - sut.TimeSystem.Should().BeSameAs(fileSystem.TimeSystem); + fileContainer.CreationTime.Set(time, DateTimeKind.Unspecified); + + string? result = fileContainer.CreationTime.ToString(); + + result.Should().Be(expectedString); } - [Theory] - [AutoData] - public void RequestAccess_ToString_ShouldContainAccessAndShare(string path, FileAccess access, - FileShare share) + [Fact] + public void ToString_Directory_ShouldIncludePath() { MockFileSystem fileSystem = new(); - fileSystem.Initialize() - .WithFile(path); - IStorageLocation location = fileSystem.Storage.GetLocation(path); - IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + string expectedPath = fileSystem.Path.GetFullPath("foo"); + fileSystem.Directory.CreateDirectory(expectedPath); + IStorageContainer sut = fileSystem.StorageContainers.Last(); - IStorageAccessHandle result = sut.RequestAccess(access, share); + string? result = sut.ToString(); - result.ToString().Should().Contain(access.ToString()); - result.ToString().Should().Contain(share.ToString()); + result.Should().Be($"{expectedPath}: Directory"); } [Theory] [AutoData] - public void RequestAccess_ToString_DeleteAccess_ShouldContainAccessAndShare(string path, - FileAccess access, FileShare share) + public void ToString_File_ShouldIncludePathAndFileSize(byte[] bytes) { MockFileSystem fileSystem = new(); - fileSystem.Initialize() - .WithFile(path); - IStorageLocation location = fileSystem.Storage.GetLocation(path); - IStorageContainer sut = InMemoryContainer.NewFile(location, fileSystem); + string expectedPath = fileSystem.Path.GetFullPath("foo.txt"); + fileSystem.File.WriteAllBytes(expectedPath, bytes); + IStorageContainer sut = fileSystem.StorageContainers.Single(); - IStorageAccessHandle result = sut.RequestAccess(access, share, true); + string? result = sut.ToString(); - result.ToString().Should().NotContain(access.ToString()); - result.ToString().Should().Contain("Delete"); - result.ToString().Should().Contain(share.ToString()); + result.Should().Be($"{expectedPath}: File ({bytes.Length} bytes)"); + } + + [Fact] + public void ToString_UnknownContainer_ShouldIncludePath() + { + MockFileSystem fileSystem = new(); + string expectedPath = fileSystem.Path.GetFullPath("foo"); + IStorageLocation location = InMemoryLocation.New(null, expectedPath); + IStorageContainer sut = new InMemoryContainer(FileSystemTypes.DirectoryOrFile, location, + fileSystem); + + string? result = sut.ToString(); + + result.Should().Be($"{expectedPath}: Unknown Container"); } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Storage/LocationExtensionsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Storage/LocationExtensionsTests.cs new file mode 100644 index 000000000..f396bff81 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Storage/LocationExtensionsTests.cs @@ -0,0 +1,118 @@ +using System.IO; +using Testably.Abstractions.Testing.Storage; + +namespace Testably.Abstractions.Testing.Tests.Storage; + +public sealed class LocationExtensionsTests +{ + [SkippableFact] + public void ThrowExceptionIfNotFound_MissingDirectory_ShouldThrowDirectoryNotFoundException() + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo/bar.txt"); + + Exception? exception = Record.Exception(() => + { + location.ThrowExceptionIfNotFound(fileSystem); + }); + + exception.Should().BeOfType(); + } + + [SkippableTheory] + [AutoData] + public void + ThrowExceptionIfNotFound_MissingDirectory_WithCustomCallback_ShouldThrowExceptionFromCallback( + Exception expectedException) + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo/bar.txt"); + + Exception? exception = Record.Exception(() => + { + location.ThrowExceptionIfNotFound(fileSystem, + onDirectoryNotFound: _ => expectedException); + }); + + exception.Should().BeSameAs(expectedException); + } + + [SkippableFact] + public void ThrowExceptionIfNotFound_MissingFile_ShouldThrowFileNotFoundException() + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo.txt"); + + Exception? exception = Record.Exception(() => + { + location.ThrowExceptionIfNotFound(fileSystem); + }); + + exception.Should().BeOfType(); + } + + [SkippableTheory] + [AutoData] + public void + ThrowExceptionIfNotFound_MissingFile_WithCustomCallback_ShouldThrowExceptionFromCallback( + Exception expectedException) + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo"); + + Exception? exception = Record.Exception(() => + { + location.ThrowExceptionIfNotFound(fileSystem, onFileNotFound: _ => expectedException); + }); + + exception.Should().BeSameAs(expectedException); + } + + [SkippableTheory] + [AutoData] + public void ThrowIfNotFound_MissingDirectory_ShouldExecuteFileNotFoundAction( + Exception expectedException) + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo/bar.txt"); + + Exception? exception = Record.Exception(() => + { + location.ThrowIfNotFound(fileSystem, () => { }, + directoryNotFoundException: () => throw expectedException); + }); + + exception.Should().BeSameAs(expectedException); + } + + [SkippableTheory] + [AutoData] + public void ThrowIfNotFound_MissingFile_ShouldExecuteFileNotFoundAction( + Exception expectedException) + { + MockFileSystem fileSystem = new(); + IStorageLocation location = fileSystem.Storage.GetLocation("foo"); + + Exception? exception = Record.Exception(() => + { + location.ThrowIfNotFound(fileSystem, () => throw expectedException); + }); + + exception.Should().BeSameAs(expectedException); + } + + [SkippableTheory] + [AutoData] + public void ThrowIfNotFound_Null_ShouldExecuteFileNotFoundAction(Exception expectedException) + { + MockFileSystem fileSystem = new(); + IStorageLocation? location = null; + + Exception? exception = Record.Exception(() => + { + location.ThrowIfNotFound(fileSystem, () => throw expectedException); + }); + + exception.Should().BeSameAs(expectedException); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs index c01444846..9deba7b05 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs @@ -109,7 +109,8 @@ public void Dispose_WithUnknownWaitHandle_ShouldThrowNotSupportedException() timer.Dispose(waitHandle); }); - exception.Should().BeOfType(); + exception.Should().BeOfType() + .Which.Message.Should().Contain(typeof(DummyWaitHandle).ToString()); } [Fact] @@ -217,6 +218,7 @@ public void Wait_InvalidExecutionCount_ShouldThrowArgumentOutOfRangeException() exception.Should().BeOfType() .Which.ParamName.Should().Be("executionCount"); + exception!.Message.Should().Contain("Execution count must be greater than zero."); } [SkippableFact] diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/Directory/CreateDirectoryTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/Directory/CreateDirectoryTests.cs index f7f07919f..6b16919bc 100644 --- a/Tests/Testably.Abstractions.Tests/FileSystem/Directory/CreateDirectoryTests.cs +++ b/Tests/Testably.Abstractions.Tests/FileSystem/Directory/CreateDirectoryTests.cs @@ -24,7 +24,7 @@ public void CreateDirectory_AlreadyExisting_ShouldDoNothing(string path) [SkippableTheory] [AutoData] - public void CreateDirectory_ReadOnlyParent_ShouldStillCreateDirectory(string parent, + public void CreateDirectory_ReadOnlyParent_ShouldStillCreateDirectoryUnderWindows(string parent, string subdirectory) { string subdirectoryPath = FileSystem.Path.Combine(parent, subdirectory);