Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Diagnostics.CodeAnalysis;

namespace Testably.Abstractions.Testing.Helpers;

/// <summary>
/// Provides extension methods on <see cref="char" />.
/// </summary>
[ExcludeFromCodeCoverage]
internal static class CharExtensionMethods
{
/// <summary>Indicates whether a character is categorized as an ASCII letter.</summary>
/// <param name="c">The character to evaluate.</param>
/// <returns>true if <paramref name="c" /> is an ASCII letter; otherwise, false.</returns>
/// <remarks>
/// This determines whether the character is in the range 'A' through 'Z', inclusive,
/// or 'a' through 'z', inclusive.
/// </remarks>
public static bool IsAsciiLetter(this char c) => (uint)((c | 0x20) - 'a') <= 'z' - 'a';
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ namespace Testably.Abstractions.Testing.Statistics;
internal class CallStatistics : IStatistics
{
private readonly ConcurrentQueue<MethodStatistic> _methods = new();
private readonly string _name;
private readonly ConcurrentQueue<PropertyStatistic> _properties = new();
private readonly IStatisticsGate _statisticsGate;

public CallStatistics(IStatisticsGate statisticsGate)
public CallStatistics(IStatisticsGate statisticsGate, string name)
{
_statisticsGate = statisticsGate;
_name = name;
}

#region IStatistics Members
Expand All @@ -24,6 +26,10 @@ public CallStatistics(IStatisticsGate statisticsGate)

#endregion

/// <inheritdoc cref="object.ToString()" />
public override string ToString()
=> _name;

/// <summary>
/// Registers the method <paramref name="name" /> with <paramref name="parameters" />.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ internal sealed class FileSystemStatistics : IFileSystemStatistics, IStatisticsG
{
private static readonly AsyncLocal<bool> 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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string, CallStatistics> _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;
Expand All @@ -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}]"));
}
}

Expand All @@ -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);
}

Expand All @@ -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('/', '\\');
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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]");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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:]");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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]");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");
}
}
Loading