diff --git a/Source/Testably.Abstractions.Testing/Helpers/CharExtensionMethods.cs b/Source/Testably.Abstractions.Testing/Helpers/CharExtensionMethods.cs new file mode 100644 index 000000000..dcdbadb95 --- /dev/null +++ b/Source/Testably.Abstractions.Testing/Helpers/CharExtensionMethods.cs @@ -0,0 +1,19 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Testably.Abstractions.Testing.Helpers; + +/// +/// Provides extension methods on . +/// +[ExcludeFromCodeCoverage] +internal static class CharExtensionMethods +{ + /// Indicates whether a character is categorized as an ASCII letter. + /// The character to evaluate. + /// true if is an ASCII letter; otherwise, false. + /// + /// This determines whether the character is in the range 'A' through 'Z', inclusive, + /// or 'a' through 'z', inclusive. + /// + public static bool IsAsciiLetter(this char c) => (uint)((c | 0x20) - 'a') <= 'z' - 'a'; +} diff --git a/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs b/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs index 757811959..4a4ff594c 100644 --- a/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs +++ b/Source/Testably.Abstractions.Testing/Statistics/CallStatistics.cs @@ -6,12 +6,14 @@ namespace Testably.Abstractions.Testing.Statistics; internal class CallStatistics : IStatistics { private readonly ConcurrentQueue _methods = new(); + private readonly string _name; private readonly ConcurrentQueue _properties = new(); private readonly IStatisticsGate _statisticsGate; - public CallStatistics(IStatisticsGate statisticsGate) + public CallStatistics(IStatisticsGate statisticsGate, string name) { _statisticsGate = statisticsGate; + _name = name; } #region IStatistics Members @@ -24,6 +26,10 @@ public CallStatistics(IStatisticsGate statisticsGate) #endregion + /// + public override string ToString() + => _name; + /// /// Registers the method with . /// diff --git a/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs b/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs index d092204bf..fc6de6f1d 100644 --- a/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs +++ b/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs @@ -8,25 +8,25 @@ internal sealed class FileSystemStatistics : IFileSystemStatistics, IStatisticsG { private static readonly AsyncLocal IsDisabled = new(); internal readonly CallStatistics Directory; - internal readonly FileSystemEntryStatistics DirectoryInfo; - internal readonly FileSystemEntryStatistics DriveInfo; + internal readonly PathStatistics DirectoryInfo; + internal readonly PathStatistics DriveInfo; internal readonly CallStatistics File; - internal readonly FileSystemEntryStatistics FileInfo; - internal readonly FileSystemEntryStatistics FileStream; - internal readonly FileSystemEntryStatistics FileSystemWatcher; + internal readonly PathStatistics FileInfo; + internal readonly PathStatistics FileStream; + internal readonly PathStatistics FileSystemWatcher; internal readonly CallStatistics Path; private int _counter; public FileSystemStatistics(MockFileSystem fileSystem) { - DirectoryInfo = new FileSystemEntryStatistics(this, fileSystem); - DriveInfo = new FileSystemEntryStatistics(this, fileSystem); - FileInfo = new FileSystemEntryStatistics(this, fileSystem); - FileStream = new FileSystemEntryStatistics(this, fileSystem); - FileSystemWatcher = new FileSystemEntryStatistics(this, fileSystem); - File = new CallStatistics(this); - Directory = new CallStatistics(this); - Path = new CallStatistics(this); + DirectoryInfo = new PathStatistics(this, fileSystem, nameof(IFileSystem.DirectoryInfo)); + DriveInfo = new PathStatistics(this, fileSystem, nameof(IFileSystem.DriveInfo)); + FileInfo = new PathStatistics(this, fileSystem, nameof(IFileSystem.FileInfo)); + FileStream = new PathStatistics(this, fileSystem, nameof(IFileSystem.FileStream)); + FileSystemWatcher = new PathStatistics(this, fileSystem, nameof(IFileSystem.FileSystemWatcher)); + File = new CallStatistics(this, nameof(IFileSystem.File)); + Directory = new CallStatistics(this, nameof(IFileSystem.Directory)); + Path = new CallStatistics(this, nameof(IFileSystem.Path)); } #region IFileSystemStatistics Members diff --git a/Source/Testably.Abstractions.Testing/Statistics/FileSystemEntryStatistics.cs b/Source/Testably.Abstractions.Testing/Statistics/PathStatistics.cs similarity index 69% rename from Source/Testably.Abstractions.Testing/Statistics/FileSystemEntryStatistics.cs rename to Source/Testably.Abstractions.Testing/Statistics/PathStatistics.cs index ef73e9037..1d45ac3fc 100644 --- a/Source/Testably.Abstractions.Testing/Statistics/FileSystemEntryStatistics.cs +++ b/Source/Testably.Abstractions.Testing/Statistics/PathStatistics.cs @@ -1,20 +1,22 @@ using System; using System.Collections.Concurrent; using System.IO; +using Testably.Abstractions.Testing.Helpers; namespace Testably.Abstractions.Testing.Statistics; -internal class FileSystemEntryStatistics : CallStatistics, IPathStatistics +internal class PathStatistics : CallStatistics, IPathStatistics { private readonly MockFileSystem _fileSystem; private readonly ConcurrentDictionary _statistics = new(); private readonly IStatisticsGate _statisticsGate; - public FileSystemEntryStatistics( + public PathStatistics( IStatisticsGate statisticsGate, - MockFileSystem fileSystem) - : base(statisticsGate) + MockFileSystem fileSystem, + string name) + : base(statisticsGate, name) { _statisticsGate = statisticsGate; _fileSystem = fileSystem; @@ -28,7 +30,8 @@ public IStatistics this[string path] get { string key = CreateKey(_fileSystem.Storage.CurrentDirectory, path); - return _statistics.GetOrAdd(key, _ => new CallStatistics(_statisticsGate)); + return _statistics.GetOrAdd(key, + k => new CallStatistics(_statisticsGate, $"{ToString()}[{k}]")); } } @@ -43,7 +46,8 @@ internal IDisposable RegisterMethod(string path, string name, { string key = CreateKey(_fileSystem.Storage.CurrentDirectory, path); CallStatistics callStatistics = - _statistics.GetOrAdd(key, _ => new CallStatistics(_statisticsGate)); + _statistics.GetOrAdd(key, + k => new CallStatistics(_statisticsGate, $"{ToString()}[{k}]")); return callStatistics.RegisterMethod(name, parameters); } @@ -56,23 +60,30 @@ internal IDisposable RegisterProperty(string path, string name, PropertyAccess a { string key = CreateKey(_fileSystem.Storage.CurrentDirectory, path); CallStatistics callStatistics = - _statistics.GetOrAdd(key, _ => new CallStatistics(_statisticsGate)); + _statistics.GetOrAdd(key, + k => new CallStatistics(_statisticsGate, $"{ToString()}[{k}]")); return callStatistics.RegisterProperty(name, access); } private static string CreateKey(string currentDirectory, string path) { + string key = string.Empty; if (string.IsNullOrEmpty(path)) { - return "(empty)"; + return key; } - if (Path.IsPathRooted(path)) + if (path.StartsWith("//") || + path.StartsWith(@"\\") || + (path.Length >= 2 && path[1] == ':' && path[0].IsAsciiLetter())) { - return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + key = path; + } + else + { + key = Path.GetFullPath(Path.Combine(currentDirectory, path)); } - return Path.GetFullPath(Path.Combine(currentDirectory, path)) - .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return key.TrimEnd('/', '\\'); } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Helpers/CharExtensionMethodsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Helpers/CharExtensionMethodsTests.cs new file mode 100644 index 000000000..03d64b710 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Helpers/CharExtensionMethodsTests.cs @@ -0,0 +1,35 @@ +using Testably.Abstractions.Testing.Helpers; + +namespace Testably.Abstractions.Testing.Tests.Helpers; + +public sealed class CharExtensionMethodsTests +{ + [Theory] + [InlineData('A')] + [InlineData('Z')] + [InlineData('a')] + [InlineData('z')] + [InlineData('M')] + [InlineData('d')] + public void IsAsciiLetter_WithAsciiLetterChar_ShouldReturnTrue(char c) + { + bool result = c.IsAsciiLetter(); + + result.Should().BeTrue(); + } + + [Theory] + [InlineData((char)64)] + [InlineData((char)91)] + [InlineData((char)96)] + [InlineData((char)123)] + [InlineData((char)55)] + [InlineData((char)0)] + [InlineData((char)127)] + public void IsAsciiLetter_WithNonAsciiLetterChar_ShouldReturnFalse(char c) + { + bool result = c.IsAsciiLetter(); + + result.Should().BeFalse(); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoFactoryStatisticsTests.cs index 2e0531a3a..53c7eb2ae 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoFactoryStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -28,4 +29,14 @@ public void Method_Wrap_DirectoryInfo_ShouldRegisterCall() sut.Statistics.DirectoryInfo.ShouldOnlyContainMethodCall(nameof(IDirectoryInfoFactory.Wrap), directoryInfo); } + + [SkippableFact] + public void ToString_ShouldBeDirectoryInfo() + { + IPathStatistics sut = new MockFileSystem().Statistics.DirectoryInfo; + + string? result = sut.ToString(); + + result.Should().Be("DirectoryInfo"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoStatisticsTests.cs index f15a4ed1e..733dcbb65 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryInfoStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -738,4 +739,14 @@ public void Property_UnixFileMode_Set_ShouldRegisterPropertyAccess() .ShouldOnlyContainPropertySetAccess(nameof(IDirectoryInfo.UnixFileMode)); } #endif + + [SkippableFact] + public void ToString_ShouldBeDirectoryInfoWithPath() + { + IStatistics sut = new MockFileSystem().Statistics.DirectoryInfo[@"\\some\path"]; + + string? result = sut.ToString(); + + result.Should().Be(@"DirectoryInfo[\\some\path]"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryStatisticsTests.cs index 164d4b2a4..6e149232f 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DirectoryStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -702,4 +703,14 @@ public void Method_SetLastWriteTimeUtc_String_DateTime_ShouldRegisterCall() sut.Statistics.Directory.ShouldOnlyContainMethodCall(nameof(IDirectory.SetLastWriteTimeUtc), path, lastWriteTimeUtc); } + + [SkippableFact] + public void ToString_ShouldBeDirectory() + { + IStatistics sut = new MockFileSystem().Statistics.Directory; + + string? result = sut.ToString(); + + result.Should().Be("Directory"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoFactoryStatisticsTests.cs index cda25b165..3f14ded1d 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoFactoryStatisticsTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -39,4 +40,14 @@ public void Method_Wrap_DriveInfo_ShouldRegisterCall() sut.Statistics.DriveInfo.ShouldOnlyContainMethodCall(nameof(IDriveInfoFactory.Wrap), driveInfo); } + + [SkippableFact] + public void ToString_ShouldBeDriveInfo() + { + IPathStatistics sut = new MockFileSystem().Statistics.DriveInfo; + + string? result = sut.ToString(); + + result.Should().Be("DriveInfo"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoStatisticsTests.cs index d2d14f21f..558af657d 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/DriveInfoStatisticsTests.cs @@ -1,4 +1,5 @@ -using Testably.Abstractions.Testing.Tests.TestHelpers; +using Testably.Abstractions.Testing.Statistics; +using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -135,4 +136,14 @@ public void Property_VolumeLabel_Set_ShouldRegisterPropertyAccess() sut.Statistics.DriveInfo["F:"] .ShouldOnlyContainPropertySetAccess(nameof(IDriveInfo.VolumeLabel)); } + + [SkippableFact] + public void ToString_ShouldBeDriveInfoWithPath() + { + IStatistics sut = new MockFileSystem().Statistics.DriveInfo[@"x:"]; + + string? result = sut.ToString(); + + result.Should().Be(@"DriveInfo[x:]"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoFactoryStatisticsTests.cs index 29169202d..217190a06 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoFactoryStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -28,4 +29,14 @@ public void Method_Wrap_FileInfo_ShouldRegisterCall() sut.Statistics.FileInfo.ShouldOnlyContainMethodCall(nameof(IFileInfoFactory.Wrap), fileInfo); } + + [SkippableFact] + public void ToString_ShouldBeFileInfo() + { + IPathStatistics sut = new MockFileSystem().Statistics.FileInfo; + + string? result = sut.ToString(); + + result.Should().Be("FileInfo"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoStatisticsTests.cs index 05dd647b5..a65e5862b 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileInfoStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -634,4 +635,14 @@ public void Property_UnixFileMode_Set_ShouldRegisterPropertyAccess() .ShouldOnlyContainPropertySetAccess(nameof(IFileInfo.UnixFileMode)); } #endif + + [SkippableFact] + public void ToString_ShouldBeFileInfoWithPath() + { + IStatistics sut = new MockFileSystem().Statistics.FileInfo[@"\\some\path"]; + + string? result = sut.ToString(); + + result.Should().Be(@"FileInfo[\\some\path]"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs index ea9819fe1..5d59a866c 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStatisticsTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; #if FEATURE_FILESYSTEM_SAFEFILEHANDLE using Testably.Abstractions.Testing.FileSystem; @@ -1385,4 +1386,14 @@ public async Task path, contents, encoding, cancellationToken); } #endif + + [SkippableFact] + public void ToString_ShouldBeFile() + { + IStatistics sut = new MockFileSystem().Statistics.File; + + string? result = sut.ToString(); + + result.Should().Be("File"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs index 85e13fe21..9fa140baa 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; #if NET6_0_OR_GREATER using Microsoft.Win32.SafeHandles; @@ -193,4 +194,14 @@ public void Method_Wrap_FileStream_ShouldRegisterCall() sut.Statistics.FileStream.ShouldOnlyContainMethodCall(nameof(IFileStreamFactory.Wrap), fileStream); } + + [SkippableFact] + public void ToString_ShouldBeFileStream() + { + IPathStatistics sut = new MockFileSystem().Statistics.FileStream; + + string? result = sut.ToString(); + + result.Should().Be("FileStream"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs index eee17f5e8..8ce4ea31c 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs @@ -2,6 +2,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -534,4 +535,14 @@ public void Property_WriteTimeout_Set_ShouldRegisterPropertyAccess() sut.Statistics.FileStream["foo"] .ShouldOnlyContainPropertySetAccess(nameof(FileSystemStream.WriteTimeout)); } + + [SkippableFact] + public void ToString_ShouldBeFileStreamWithPath() + { + IStatistics sut = new MockFileSystem().Statistics.FileStream[@"\\some\path"]; + + string? result = sut.ToString(); + + result.Should().Be(@"FileStream[\\some\path]"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs index beb7d6afd..d4dae7fd7 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs @@ -1,4 +1,5 @@ using System.IO; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -58,4 +59,14 @@ public void Method_Wrap_FileSystemWatcher_ShouldRegisterCall() nameof(IFileSystemWatcherFactory.Wrap), fileSystemWatcher); } + + [SkippableFact] + public void ToString_ShouldBeFileSystemWatcher() + { + IPathStatistics sut = new MockFileSystem().Statistics.FileSystemWatcher; + + string? result = sut.ToString(); + + result.Should().Be("FileSystemWatcher"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs index 8fb4b1581..7c76e5c9a 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs @@ -2,6 +2,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Testably.Abstractions.Testing.Statistics; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -334,4 +335,14 @@ public void Property_SynchronizingObject_Set_ShouldRegisterPropertyAccess() sut.Statistics.FileSystemWatcher["foo"] .ShouldOnlyContainPropertySetAccess(nameof(IFileSystemWatcher.SynchronizingObject)); } + + [SkippableFact] + public void ToString_ShouldBeFileSystemWatcherWithPath() + { + IStatistics sut = new MockFileSystem().Statistics.FileSystemWatcher[@"\\some\path"]; + + string? result = sut.ToString(); + + result.Should().Be(@"FileSystemWatcher[\\some\path]"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs index 1329d6eee..076dc5513 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/PathStatisticsTests.cs @@ -1,4 +1,5 @@ -using Testably.Abstractions.Testing.Tests.TestHelpers; +using Testably.Abstractions.Testing.Statistics; +using Testably.Abstractions.Testing.Tests.TestHelpers; #if FEATURE_PATH_RELATIVE using System.IO; #endif @@ -633,4 +634,14 @@ public void Property_VolumeSeparatorChar_Get_ShouldRegisterPropertyAccess() sut.Statistics.Path.ShouldOnlyContainPropertyGetAccess(nameof(IPath.VolumeSeparatorChar)); } + + [SkippableFact] + public void ToString_ShouldBePath() + { + IStatistics sut = new MockFileSystem().Statistics.Path; + + string? result = sut.ToString(); + + result.Should().Be("Path"); + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs index 8172ccc68..4a3d28a53 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using Testably.Abstractions.Testing.Statistics; namespace Testably.Abstractions.Testing.Tests.Statistics; @@ -7,10 +8,11 @@ public sealed class MethodStatisticsTests [Fact] public void ToString_ShouldContainName() { - MockFileSystem sut = new(); - sut.Directory.CreateDirectory("foo"); + MockFileSystem fileSystem = new(); + fileSystem.Directory.CreateDirectory("foo"); + MethodStatistic sut = fileSystem.Statistics.Directory.Methods.First(); - string result = sut.Statistics.Directory.Methods.First().ToString(); + string result = sut.ToString(); result.Should() .Contain(nameof(IDirectory.CreateDirectory)).And @@ -21,10 +23,11 @@ public void ToString_ShouldContainName() [Fact] public void ToString_ShouldContainParameters() { - MockFileSystem sut = new(); - sut.File.WriteAllText("foo", "bar"); + MockFileSystem fileSystem = new(); + fileSystem.File.WriteAllText("foo", "bar"); + MethodStatistic sut = fileSystem.Statistics.File.Methods.First(); - string result = sut.Statistics.File.Methods.First().ToString(); + string result = sut.ToString(); result.Should() .Contain(nameof(IFile.WriteAllText)).And diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/PathStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/PathStatisticsTests.cs new file mode 100644 index 000000000..0bb69766a --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/PathStatisticsTests.cs @@ -0,0 +1,124 @@ +using Testably.Abstractions.Testing.Statistics; + +namespace Testably.Abstractions.Testing.Tests.Statistics; + +public sealed class PathStatisticsTests +{ + [Fact] + public void Key_AbsoluteAndRelativePathsShouldMatch() + { + MockFileSystem fileSystem = new(); + fileSystem.InitializeIn("/foo"); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics absolutPath = sut["/foo"]; + IStatistics relativePath = sut["."]; + + absolutPath.Should().Be(relativePath); + } + + [Fact] + public void Key_DifferentDrives_ShouldBeConsideredDifferent() + { + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics result1 = sut[@"C:\"]; + IStatistics result2 = sut[@"D:\"]; + + result1.Should().NotBe(result2); + } + + [Fact] + public void Key_DifferentUncRootPaths_ShouldBeConsideredDifferent() + { + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics result1 = sut[@"\\foo1"]; + IStatistics result2 = sut[@"\\foo2"]; + + result1.Should().NotBe(result2); + } + + [Fact] + public void Key_NullShouldBeSameAsEmptyKey() + { + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics nullKey = sut[null!]; + IStatistics emptyKey = sut[""]; + + nullKey.Should().Be(emptyKey); + } + + [Fact] + public void Key_ShouldSimplifyRelativePaths() + { + MockFileSystem fileSystem = new(); + fileSystem.InitializeIn("/foo/bar"); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics absolutPath = sut["/foo"]; + IStatistics relativePath = sut[".."]; + + absolutPath.Should().Be(relativePath); + } + + [Theory] + [InlineData("/")] + [InlineData("\\")] + public void Key_WithDrives_ShouldIgnoreTrailingSeparator(string separator) + { + const string key = @"C:"; + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics result1 = sut[key]; + IStatistics result2 = sut[key + separator]; + + result1.Should().Be(result2); + } + + [Theory] + [InlineData("/")] + [InlineData("\\")] + public void Key_WithFolderInDrives_ShouldIgnoreTrailingSeparator(string separator) + { + const string key = @"C:\foo"; + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics result1 = sut[key]; + IStatistics result2 = sut[key + separator]; + + result1.Should().Be(result2); + } + + [Theory] + [InlineData("/")] + [InlineData("\\")] + public void Key_WithFolderInUncRootPaths_ShouldIgnoreTrailingSeparator(string separator) + { + const string key = @"\\server1\foo"; + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + IStatistics result1 = sut[key]; + IStatistics result2 = sut[key + separator]; + + result1.Should().Be(result2); + } + + [Fact] + public void Key_WithNull_ShouldNotThrow() + { + MockFileSystem fileSystem = new(); + IPathStatistics sut = fileSystem.Statistics.FileInfo; + + Exception? exception = Record.Exception(() => _ = sut[null!]); + + exception.Should().BeNull(); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/PropertyStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/PropertyStatisticsTests.cs new file mode 100644 index 000000000..1511497eb --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/PropertyStatisticsTests.cs @@ -0,0 +1,39 @@ +using System.Linq; +using Testably.Abstractions.Testing.Statistics; + +namespace Testably.Abstractions.Testing.Tests.Statistics; + +public sealed class PropertyStatisticsTests +{ + [Fact] + public void ToString_Get_ShouldContainNameAndGet() + { + MockFileSystem fileSystem = new(); + fileSystem.Initialize().WithFile("foo"); + IFileInfo fileInfo = fileSystem.FileInfo.New("foo"); + _ = fileInfo.IsReadOnly; + PropertyStatistic sut = fileSystem.Statistics.FileInfo["foo"].Properties.First(); + + string result = sut.ToString(); + + result.Should() + .Contain(nameof(IFileInfo.IsReadOnly)).And + .Contain("{get;}"); + } + + [Fact] + public void ToString_Set_ShouldContainNameAndSet() + { + MockFileSystem fileSystem = new(); + fileSystem.Initialize().WithFile("foo"); + IFileInfo fileInfo = fileSystem.FileInfo.New("foo"); + fileInfo.IsReadOnly = false; + PropertyStatistic sut = fileSystem.Statistics.FileInfo["foo"].Properties.First(); + + string result = sut.ToString(); + + result.Should() + .Contain(nameof(IFileInfo.IsReadOnly)).And + .Contain("{set;}"); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs index fc8b38a1f..d2addcd99 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs @@ -50,7 +50,7 @@ public void FileSystem_Initialize_ShouldNotRegisterStatistics() [InlineData(nameof(MockFileSystem.FileSystemWatcher), true, typeof(IFileSystemWatcher), typeof(FileSystemWatcherStatisticsTests))] [InlineData(nameof(MockFileSystem.Path), false, - typeof(IPath), typeof(PathStatisticsTests))] + typeof(IPath), typeof(FileSystem.PathStatisticsTests))] public void ShouldHaveTestedAllFileSystemMethods(string className, bool requireInstance, Type mockType, Type testType) {