From b7062728b5a390aa8db578c6cb8c5692b0d0b353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 10 Mar 2024 12:39:01 +0100 Subject: [PATCH] fix: errors from static code analysis (#477) Fix the errors from the [sonar cloud static code analysis](https://github.com/Testably/Testably.Abstractions/runs/22481531017). --- .../FileSystem/FileMock.cs | 16 ++- .../FileSystem/PathMock.cs | 2 + .../Statistics/FileSystemStatistics.cs | 2 +- .../Statistics/ParameterDescription.cs | 23 ++-- .../Polyfills/StringExtensionMethods.cs | 29 +++++ .../FileStreamFactoryStatisticsTests.cs | 22 ++-- .../FileSystem/FileStreamStatisticsTests.cs | 83 +++++++----- ...FileSystemWatcherFactoryStatisticsTests.cs | 9 +- .../FileSystemWatcherStatisticsTests.cs | 35 +++-- .../Statistics/MethodStatisticsTests.cs | 31 +++++ .../Statistics/ParameterDescriptionTests.cs | 120 ++++++++++++++++++ .../Statistics/StatisticsTests.cs | 2 +- 12 files changed, 290 insertions(+), 84 deletions(-) create mode 100644 Tests/Testably.Abstractions.Testing.Tests/Polyfills/StringExtensionMethods.cs create mode 100644 Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs create mode 100644 Tests/Testably.Abstractions.Testing.Tests/Statistics/ParameterDescriptionTests.cs diff --git a/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs b/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs index 688fabb26..dc5374db9 100644 --- a/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs +++ b/Source/Testably.Abstractions.Testing/FileSystem/FileMock.cs @@ -13,6 +13,7 @@ #if FEATURE_FILESYSTEM_ASYNC using System.Threading; using System.Threading.Tasks; +// ReSharper disable PossibleMultipleEnumeration #endif namespace Testably.Abstractions.Testing.FileSystem; @@ -1359,25 +1360,26 @@ private static void ThrowIfCancelled(CancellationToken cancellationToken) } #endif - private IDisposable Register(string name) - => _fileSystem.StatisticsRegistration.File.Register(name); - - private IDisposable Register(string name, T1 parameter1) + private IDisposable Register(string name, + T1 parameter1) => _fileSystem.StatisticsRegistration.File.Register(name, ParameterDescription.FromParameter(parameter1)); - private IDisposable Register(string name, T1 parameter1, T2 parameter2) + private IDisposable Register(string name, + T1 parameter1, T2 parameter2) => _fileSystem.StatisticsRegistration.File.Register(name, ParameterDescription.FromParameter(parameter1), ParameterDescription.FromParameter(parameter2)); - private IDisposable Register(string name, T1 parameter1, T2 parameter2, T3 parameter3) + private IDisposable Register(string name, + T1 parameter1, T2 parameter2, T3 parameter3) => _fileSystem.StatisticsRegistration.File.Register(name, ParameterDescription.FromParameter(parameter1), ParameterDescription.FromParameter(parameter2), ParameterDescription.FromParameter(parameter3)); - private IDisposable Register(string name, T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) + private IDisposable Register(string name, + T1 parameter1, T2 parameter2, T3 parameter3, T4 parameter4) => _fileSystem.StatisticsRegistration.File.Register(name, ParameterDescription.FromParameter(parameter1), ParameterDescription.FromParameter(parameter2), diff --git a/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs b/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs index 62a83c4dc..eb859a479 100644 --- a/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs +++ b/Source/Testably.Abstractions.Testing/FileSystem/PathMock.cs @@ -524,7 +524,9 @@ private IDisposable Register(string name, T1 parameter1) private IDisposable Register(string name, ReadOnlySpan parameter1) => _fileSystem.StatisticsRegistration.Path.Register(name, ParameterDescription.FromParameter(parameter1)); +#endif +#if FEATURE_PATH_ADVANCED private IDisposable Register(string name, ReadOnlySpan parameter1, ReadOnlySpan parameter2) => _fileSystem.StatisticsRegistration.Path.Register(name, diff --git a/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs b/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs index dc32d92f1..fb9a759fa 100644 --- a/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs +++ b/Source/Testably.Abstractions.Testing/Statistics/FileSystemStatistics.cs @@ -82,7 +82,7 @@ public int GetCounter() #endregion - private class TemporaryDisable : IDisposable + private sealed class TemporaryDisable : IDisposable { public static IDisposable None { get; } = new NoOpDisposable(); diff --git a/Source/Testably.Abstractions.Testing/Statistics/ParameterDescription.cs b/Source/Testably.Abstractions.Testing/Statistics/ParameterDescription.cs index e6d92c17f..41d2467ac 100644 --- a/Source/Testably.Abstractions.Testing/Statistics/ParameterDescription.cs +++ b/Source/Testably.Abstractions.Testing/Statistics/ParameterDescription.cs @@ -45,15 +45,6 @@ public bool Is(T[] value) value.SequenceEqual(d.Value); } - private static bool IsEqual(T value1, T value2) - { - if (value1 is null) - { - return value2 is null; - } - - return value1.Equals(value2); - } #if FEATURE_SPAN /// /// Checks, if the span value of the parameter equals . @@ -111,7 +102,17 @@ public static ParameterDescription FromOutParameter(T value) return new GenericParameterDescription(value, true); } - private class GenericParameterDescription : ParameterDescription + private static bool IsEqual(T value1, T value2) + { + if (value1 is null) + { + return value2 is null; + } + + return value1.Equals(value2); + } + + private sealed class GenericParameterDescription : ParameterDescription { public T Value { get; } @@ -133,7 +134,7 @@ public GenericParameterDescription(T value, bool isOutParameter) : base(isOutPar } #if FEATURE_SPAN - private class SpanParameterDescription : ParameterDescription + private sealed class SpanParameterDescription : ParameterDescription { public T[] Value { get; } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Polyfills/StringExtensionMethods.cs b/Tests/Testably.Abstractions.Testing.Tests/Polyfills/StringExtensionMethods.cs new file mode 100644 index 000000000..0d5a1e8a1 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Polyfills/StringExtensionMethods.cs @@ -0,0 +1,29 @@ +#if NET48 +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace +namespace Testably.Abstractions.Polyfills; + +/// +/// Provides extension methods to simplify writing platform independent tests. +/// +[ExcludeFromCodeCoverage] +internal static class StringExtensionMethods +{ + /// + /// Reports the zero-based index of the first occurrence of the specified string in the current + /// object. A parameter specifies the type of search to use for the specified string. + /// + /// + /// The index position of the parameter if that string is found, or -1 if it is not. + /// If is , the return value is 0. + /// + internal static int IndexOf( + this string @this, + char value, + StringComparison comparison) + { + return @this.IndexOf($"{value}", comparison); + } +} +#endif diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs index 360c7d944..69a77ce08 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamFactoryStatisticsTests.cs @@ -20,7 +20,7 @@ public void New_SafeFileHandle_FileAccess_ShouldRegisterCall() SafeFileHandle handle = new(); FileAccess access = FileAccess.ReadWrite; - sut.FileStream.New(handle, access); + using FileSystemStream result = sut.FileStream.New(handle, access); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), handle, access); @@ -34,7 +34,7 @@ public void New_String_FileMode_ShouldRegisterCall() string path = "foo"; FileMode mode = FileMode.OpenOrCreate; - sut.FileStream.New(path, mode); + using FileSystemStream result = sut.FileStream.New(path, mode); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode); @@ -49,7 +49,7 @@ public void New_String_FileStreamOptions_ShouldRegisterCall() string path = "foo"; FileStreamOptions options = new(); - sut.FileStream.New(path, options); + using FileSystemStream result = sut.FileStream.New(path, options); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, options); @@ -68,7 +68,7 @@ public void New_SafeFileHandle_FileAccess_Int_ShouldRegisterCall() FileAccess access = FileAccess.ReadWrite; int bufferSize = 42; - sut.FileStream.New(handle, access, bufferSize); + using FileSystemStream result = sut.FileStream.New(handle, access, bufferSize); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), handle, access, bufferSize); @@ -83,7 +83,7 @@ public void New_String_FileMode_FileAccess_ShouldRegisterCall() FileMode mode = FileMode.OpenOrCreate; FileAccess access = FileAccess.ReadWrite; - sut.FileStream.New(path, mode, access); + using FileSystemStream result = sut.FileStream.New(path, mode, access); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode, access); @@ -102,7 +102,7 @@ public void New_SafeFileHandle_FileAccess_Int_Bool_ShouldRegisterCall() int bufferSize = 42; bool isAsync = true; - sut.FileStream.New(handle, access, bufferSize, isAsync); + using FileSystemStream result = sut.FileStream.New(handle, access, bufferSize, isAsync); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), handle, access, bufferSize, isAsync); @@ -118,7 +118,7 @@ public void New_String_FileMode_FileAccess_FileShare_ShouldRegisterCall() FileAccess access = FileAccess.ReadWrite; FileShare share = FileShare.ReadWrite; - sut.FileStream.New(path, mode, access, share); + using FileSystemStream result = sut.FileStream.New(path, mode, access, share); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode, access, share); @@ -134,7 +134,7 @@ public void New_String_FileMode_FileAccess_FileShare_Int_ShouldRegisterCall() FileShare share = FileShare.ReadWrite; int bufferSize = 42; - sut.FileStream.New(path, mode, access, share, bufferSize); + using FileSystemStream result = sut.FileStream.New(path, mode, access, share, bufferSize); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode, access, share, bufferSize); @@ -151,7 +151,7 @@ public void New_String_FileMode_FileAccess_FileShare_Int_Bool_ShouldRegisterCall int bufferSize = 42; bool useAsync = true; - sut.FileStream.New(path, mode, access, share, bufferSize, useAsync); + using FileSystemStream result = sut.FileStream.New(path, mode, access, share, bufferSize, useAsync); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode, access, share, bufferSize, useAsync); @@ -168,7 +168,7 @@ public void New_String_FileMode_FileAccess_FileShare_Int_FileOptions_ShouldRegis int bufferSize = 42; FileOptions options = new(); - sut.FileStream.New(path, mode, access, share, bufferSize, options); + using FileSystemStream result = sut.FileStream.New(path, mode, access, share, bufferSize, options); sut.Statistics.FileStream.ShouldOnlyContain(nameof(IFileStreamFactory.New), path, mode, access, share, bufferSize, options); @@ -182,7 +182,7 @@ public void Wrap_FileStream_ShouldRegisterCall() try { - sut.FileStream.Wrap(fileStream); + using FileSystemStream result = sut.FileStream.Wrap(fileStream); } catch (NotSupportedException) { diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs index 23f64a08a..ce069a338 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileStreamStatisticsTests.cs @@ -12,14 +12,14 @@ public class FileStreamStatisticsTests public void BeginRead_ByteArray_Int_Int_AsyncCallback_Object_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; AsyncCallback? callback = null; - object? state = new(); + object? state = null; - sut.FileStream.New("foo", FileMode.OpenOrCreate) - .BeginRead(buffer, offset, count, callback, state); + fileStream.BeginRead(buffer, offset, count, callback, state); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.BeginRead), buffer, offset, count, callback, state); @@ -29,14 +29,14 @@ public void BeginRead_ByteArray_Int_Int_AsyncCallback_Object_ShouldRegisterCall( public void BeginWrite_ByteArray_Int_Int_AsyncCallback_Object_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; AsyncCallback? callback = null; object? state = null; - sut.FileStream.New("foo", FileMode.OpenOrCreate) - .BeginWrite(buffer, offset, count, callback, state); + fileStream.BeginWrite(buffer, offset, count, callback, state); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.BeginWrite), buffer, offset, count, callback, state); @@ -46,10 +46,11 @@ public void BeginWrite_ByteArray_Int_Int_AsyncCallback_Object_ShouldRegisterCall public void CopyTo_Stream_Int_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); Stream destination = new MemoryStream(); int bufferSize = 42; - sut.FileStream.New("foo", FileMode.OpenOrCreate).CopyTo(destination, bufferSize); + fileStream.CopyTo(destination, bufferSize); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.CopyTo), destination, bufferSize); @@ -59,12 +60,12 @@ public void CopyTo_Stream_Int_ShouldRegisterCall() public async Task CopyToAsync_Stream_Int_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); Stream destination = new MemoryStream(); int bufferSize = 42; CancellationToken cancellationToken = CancellationToken.None; - await sut.FileStream.New("foo", FileMode.OpenOrCreate) - .CopyToAsync(destination, bufferSize, cancellationToken); + await fileStream.CopyToAsync(destination, bufferSize, cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.CopyToAsync), destination, bufferSize, cancellationToken); @@ -75,10 +76,10 @@ public void EndRead_IAsyncResult_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithFile("foo"); - FileSystemStream stream = sut.FileStream.New("foo", FileMode.OpenOrCreate); - IAsyncResult asyncResult = stream.BeginRead(new byte[10], 0, 10, null, null); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); + IAsyncResult asyncResult = fileStream.BeginRead(new byte[10], 0, 10, null, null); - stream.EndRead(asyncResult); + fileStream.EndRead(asyncResult); sut.Statistics.FileStream["foo"].Methods.Count.Should().Be(2); sut.Statistics.FileStream["foo"].Methods.Values.Should() @@ -92,10 +93,10 @@ public void EndWrite_IAsyncResult_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithFile("foo"); - FileSystemStream stream = sut.FileStream.New("foo", FileMode.OpenOrCreate); - IAsyncResult asyncResult = stream.BeginWrite(new byte[10], 0, 10, null, null); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); + IAsyncResult asyncResult = fileStream.BeginWrite(new byte[10], 0, 10, null, null); - stream.EndWrite(asyncResult); + fileStream.EndWrite(asyncResult); sut.Statistics.FileStream["foo"].Methods.Count.Should().Be(2); sut.Statistics.FileStream["foo"].Methods.Values.Should() @@ -108,8 +109,9 @@ public void EndWrite_IAsyncResult_ShouldRegisterCall() public void Flush_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); - sut.FileStream.New("foo", FileMode.OpenOrCreate).Flush(); + fileStream.Flush(); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Flush)); } @@ -118,9 +120,10 @@ public void Flush_ShouldRegisterCall() public void Flush_Bool_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); bool flushToDisk = true; - sut.FileStream.New("foo", FileMode.OpenOrCreate).Flush(flushToDisk); + fileStream.Flush(flushToDisk); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Flush), flushToDisk); @@ -130,9 +133,10 @@ public void Flush_Bool_ShouldRegisterCall() public async Task FlushAsync_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); CancellationToken cancellationToken = CancellationToken.None; - await sut.FileStream.New("foo", FileMode.OpenOrCreate).FlushAsync(cancellationToken); + await fileStream.FlushAsync(cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.FlushAsync), cancellationToken); @@ -143,9 +147,10 @@ public async Task FlushAsync_CancellationToken_ShouldRegisterCall() public void Read_SpanByte_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); Span buffer = new(); - _ = sut.FileStream.New("foo", FileMode.OpenOrCreate).Read(buffer); + _ = fileStream.Read(buffer); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Read), buffer); @@ -156,11 +161,12 @@ public void Read_SpanByte_ShouldRegisterCall() public void Read_ByteArray_Int_Int_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; - sut.FileStream.New("foo", FileMode.OpenOrCreate).Read(buffer, offset, count); + _ = fileStream.Read(buffer, offset, count); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Read), buffer, offset, count); @@ -168,13 +174,14 @@ public void Read_ByteArray_Int_Int_ShouldRegisterCall() #if FEATURE_SPAN [SkippableFact] - public void ReadAsync_MemoryByte_CancellationToken_ShouldRegisterCall() + public async Task ReadAsync_MemoryByte_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + await using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); Memory buffer = new(); CancellationToken cancellationToken = CancellationToken.None; - sut.FileStream.New("foo", FileMode.OpenOrCreate).ReadAsync(buffer, cancellationToken); + _ = await fileStream.ReadAsync(buffer, cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.ReadAsync), buffer, cancellationToken); @@ -185,13 +192,13 @@ public void ReadAsync_MemoryByte_CancellationToken_ShouldRegisterCall() public async Task ReadAsync_ByteArray_Int_Int_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; CancellationToken cancellationToken = CancellationToken.None; - await sut.FileStream.New("foo", FileMode.OpenOrCreate) - .ReadAsync(buffer, offset, count, cancellationToken); + _ = await fileStream.ReadAsync(buffer, offset, count, cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.ReadAsync), buffer, offset, count, cancellationToken); @@ -201,8 +208,9 @@ await sut.FileStream.New("foo", FileMode.OpenOrCreate) public void ReadByte_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); - sut.FileStream.New("foo", FileMode.OpenOrCreate).ReadByte(); + fileStream.ReadByte(); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.ReadByte)); } @@ -211,10 +219,11 @@ public void ReadByte_ShouldRegisterCall() public void Seek_Int64_SeekOrigin_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); long offset = new(); SeekOrigin origin = new(); - sut.FileStream.New("foo", FileMode.OpenOrCreate).Seek(offset, origin); + fileStream.Seek(offset, origin); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Seek), offset, origin); @@ -224,9 +233,10 @@ public void Seek_Int64_SeekOrigin_ShouldRegisterCall() public void SetLength_Int64_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); long value = new(); - sut.FileStream.New("foo", FileMode.OpenOrCreate).SetLength(value); + fileStream.SetLength(value); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.SetLength), value); @@ -236,8 +246,9 @@ public void SetLength_Int64_ShouldRegisterCall() public void ToString_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); - sut.FileStream.New("foo", FileMode.OpenOrCreate).ToString(); + _ = fileStream.ToString(); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.ToString)); } @@ -247,9 +258,10 @@ public void ToString_ShouldRegisterCall() public void Write_ReadOnlySpanByte_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); ReadOnlySpan buffer = new(); - sut.FileStream.New("foo", FileMode.OpenOrCreate).Write(buffer); + fileStream.Write(buffer); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Write), buffer); @@ -260,11 +272,12 @@ public void Write_ReadOnlySpanByte_ShouldRegisterCall() public void Write_ByteArray_Int_Int_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; - sut.FileStream.New("foo", FileMode.OpenOrCreate).Write(buffer, offset, count); + fileStream.Write(buffer, offset, count); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.Write), buffer, offset, count); @@ -272,13 +285,14 @@ public void Write_ByteArray_Int_Int_ShouldRegisterCall() #if FEATURE_SPAN [SkippableFact] - public void WriteAsync_ReadOnlyMemoryByte_CancellationToken_ShouldRegisterCall() + public async Task WriteAsync_ReadOnlyMemoryByte_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + await using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); ReadOnlyMemory buffer = new(); CancellationToken cancellationToken = CancellationToken.None; - sut.FileStream.New("foo", FileMode.OpenOrCreate).WriteAsync(buffer, cancellationToken); + await fileStream.WriteAsync(buffer, cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.WriteAsync), buffer, cancellationToken); @@ -289,13 +303,13 @@ public void WriteAsync_ReadOnlyMemoryByte_CancellationToken_ShouldRegisterCall() public async Task WriteAsync_ByteArray_Int_Int_CancellationToken_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte[] buffer = Encoding.UTF8.GetBytes("foo"); int offset = 0; int count = 2; CancellationToken cancellationToken = CancellationToken.None; - await sut.FileStream.New("foo", FileMode.OpenOrCreate) - .WriteAsync(buffer, offset, count, cancellationToken); + await fileStream.WriteAsync(buffer, offset, count, cancellationToken); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.WriteAsync), buffer, offset, count, cancellationToken); @@ -305,9 +319,10 @@ await sut.FileStream.New("foo", FileMode.OpenOrCreate) public void WriteByte_Byte_ShouldRegisterCall() { MockFileSystem sut = new(); + using FileSystemStream fileStream = sut.FileStream.New("foo", FileMode.OpenOrCreate); byte value = new(); - sut.FileStream.New("foo", FileMode.OpenOrCreate).WriteByte(value); + fileStream.WriteByte(value); sut.Statistics.FileStream["foo"].ShouldOnlyContain(nameof(FileSystemStream.WriteByte), value); diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs index 73cd43229..774a90024 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherFactoryStatisticsTests.cs @@ -10,7 +10,7 @@ public void New_ShouldRegisterCall() { MockFileSystem sut = new(); - sut.FileSystemWatcher.New(); + using IFileSystemWatcher result = sut.FileSystemWatcher.New(); sut.Statistics.FileSystemWatcher.ShouldOnlyContain(nameof(IFileSystemWatcherFactory.New)); } @@ -22,7 +22,7 @@ public void New_String_ShouldRegisterCall() sut.Initialize().WithSubdirectory("foo"); string path = "foo"; - sut.FileSystemWatcher.New(path); + using IFileSystemWatcher result = sut.FileSystemWatcher.New(path); sut.Statistics.FileSystemWatcher.ShouldOnlyContain(nameof(IFileSystemWatcherFactory.New), path); @@ -36,7 +36,7 @@ public void New_String_String_ShouldRegisterCall() string path = "foo"; string filter = "bar"; - sut.FileSystemWatcher.New(path, filter); + using IFileSystemWatcher result = sut.FileSystemWatcher.New(path, filter); sut.Statistics.FileSystemWatcher.ShouldOnlyContain(nameof(IFileSystemWatcherFactory.New), path, filter); @@ -48,10 +48,9 @@ public void Wrap_FileSystemWatcher_ShouldRegisterCall() MockFileSystem sut = new(); FileSystemWatcher fileSystemWatcher = new(); - sut.FileSystemWatcher.Wrap(fileSystemWatcher); + using IFileSystemWatcher result = sut.FileSystemWatcher.Wrap(fileSystemWatcher); sut.Statistics.FileSystemWatcher.ShouldOnlyContain(nameof(IFileSystemWatcherFactory.Wrap), fileSystemWatcher); } - } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs index 3410c90e8..f068cc94a 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/FileSystem/FileSystemWatcherStatisticsTests.cs @@ -1,6 +1,6 @@ using System.IO; -using System.Threading.Tasks; using System.Threading; +using System.Threading.Tasks; using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.Statistics.FileSystem; @@ -12,10 +12,12 @@ public void BeginInit_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithSubdirectory("foo"); + using IFileSystemWatcher fileSystemWatcher = sut.FileSystemWatcher.New("foo"); - sut.FileSystemWatcher.New("foo").BeginInit(); + fileSystemWatcher.BeginInit(); - sut.Statistics.FileSystemWatcher["foo"].ShouldOnlyContain(nameof(IFileSystemWatcher.BeginInit)); + sut.Statistics.FileSystemWatcher["foo"] + .ShouldOnlyContain(nameof(IFileSystemWatcher.BeginInit)); } [SkippableFact] @@ -23,10 +25,12 @@ public void EndInit_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithSubdirectory("foo"); + using IFileSystemWatcher fileSystemWatcher = sut.FileSystemWatcher.New("foo"); - sut.FileSystemWatcher.New("foo").EndInit(); + fileSystemWatcher.EndInit(); - sut.Statistics.FileSystemWatcher["foo"].ShouldOnlyContain(nameof(IFileSystemWatcher.EndInit)); + sut.Statistics.FileSystemWatcher["foo"] + .ShouldOnlyContain(nameof(IFileSystemWatcher.EndInit)); } [SkippableFact] @@ -34,6 +38,7 @@ public void WaitForChanged_WatcherChangeTypes_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithSubdirectory("foo"); + using IFileSystemWatcher fileSystemWatcher = sut.FileSystemWatcher.New("foo"); // Changes in the background are necessary, so that FileSystemWatcher.WaitForChanged returns. CancellationTokenSource cts = new(TimeSpan.FromSeconds(1)); _ = Task.Run(async () => @@ -47,10 +52,10 @@ public void WaitForChanged_WatcherChangeTypes_ShouldRegisterCall() }, cts.Token); WatcherChangeTypes changeType = WatcherChangeTypes.Created; - sut.FileSystemWatcher.New("foo").WaitForChanged(changeType); + fileSystemWatcher.WaitForChanged(changeType); - sut.Statistics.FileSystemWatcher["foo"].ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), - changeType); + sut.Statistics.FileSystemWatcher["foo"] + .ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), changeType); } [SkippableFact] @@ -58,6 +63,7 @@ public void WaitForChanged_WatcherChangeTypes_Int_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithSubdirectory("foo"); + using IFileSystemWatcher fileSystemWatcher = sut.FileSystemWatcher.New("foo"); // Changes in the background are necessary, so that FileSystemWatcher.WaitForChanged returns. CancellationTokenSource cts = new(TimeSpan.FromSeconds(1)); _ = Task.Run(async () => @@ -72,10 +78,10 @@ public void WaitForChanged_WatcherChangeTypes_Int_ShouldRegisterCall() WatcherChangeTypes changeType = WatcherChangeTypes.Created; int timeout = 42; - sut.FileSystemWatcher.New("foo").WaitForChanged(changeType, timeout); + fileSystemWatcher.WaitForChanged(changeType, timeout); - sut.Statistics.FileSystemWatcher["foo"].ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), - changeType, timeout); + sut.Statistics.FileSystemWatcher["foo"] + .ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), changeType, timeout); } #if FEATURE_FILESYSTEM_NET7 @@ -84,6 +90,7 @@ public void WaitForChanged_WatcherChangeTypes_TimeSpan_ShouldRegisterCall() { MockFileSystem sut = new(); sut.Initialize().WithSubdirectory("foo"); + using IFileSystemWatcher fileSystemWatcher = sut.FileSystemWatcher.New("foo"); // Changes in the background are necessary, so that FileSystemWatcher.WaitForChanged returns. CancellationTokenSource cts = new(TimeSpan.FromSeconds(1)); _ = Task.Run(async () => @@ -98,10 +105,10 @@ public void WaitForChanged_WatcherChangeTypes_TimeSpan_ShouldRegisterCall() WatcherChangeTypes changeType = WatcherChangeTypes.Created; TimeSpan timeout = TimeSpan.FromSeconds(2); - sut.FileSystemWatcher.New("foo").WaitForChanged(changeType, timeout); + fileSystemWatcher.WaitForChanged(changeType, timeout); - sut.Statistics.FileSystemWatcher["foo"].ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), - changeType, timeout); + sut.Statistics.FileSystemWatcher["foo"] + .ShouldOnlyContain(nameof(IFileSystemWatcher.WaitForChanged), changeType, timeout); } #endif } diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs new file mode 100644 index 000000000..eb114777b --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/MethodStatisticsTests.cs @@ -0,0 +1,31 @@ +namespace Testably.Abstractions.Testing.Tests.Statistics; + +public sealed class MethodStatisticsTests +{ + [Fact] + public void ToString_ShouldContainName() + { + MockFileSystem sut = new(); + sut.Directory.CreateDirectory("foo"); + + string result = sut.Statistics.Directory.Methods[1].ToString(); + + result.Should() + .Contain(nameof(IDirectory.CreateDirectory)).And + .Contain("\"foo\"").And + .NotContain(","); + } + + [Fact] + public void ToString_ShouldContainParameters() + { + MockFileSystem sut = new(); + sut.File.WriteAllText("foo", "bar"); + + string result = sut.Statistics.File.Methods[1].ToString(); + + result.Should() + .Contain(nameof(IFile.WriteAllText)).And + .Contain("\"foo\",\"bar\""); + } +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/ParameterDescriptionTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/ParameterDescriptionTests.cs new file mode 100644 index 000000000..142dff7d3 --- /dev/null +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/ParameterDescriptionTests.cs @@ -0,0 +1,120 @@ +using Testably.Abstractions.Testing.Statistics; + +namespace Testably.Abstractions.Testing.Tests.Statistics; + +public sealed class ParameterDescriptionTests +{ + [Theory] + [AutoData] + public void FromOutParameter_ShouldSetIsOutParameterToTrue(int value) + { + ParameterDescription sut = ParameterDescription.FromOutParameter(value); + + sut.IsOutParameter.Should().BeTrue(); + } + + [Theory] + [AutoData] + public void FromParameter_ShouldSetIsOutParameterToFalse(int value) + { + ParameterDescription sut = ParameterDescription.FromParameter(value); + + sut.IsOutParameter.Should().BeFalse(); + } + +#if FEATURE_SPAN + [Theory] + [AutoData] + public void FromParameter_WithSpan_ShouldSetIsOutParameterToFalse(int[] buffer) + { + Span value = buffer.AsSpan(); + + ParameterDescription sut = ParameterDescription.FromParameter(value); + + sut.IsOutParameter.Should().BeFalse(); + } + + [Theory] + [AutoData] + public void FromParameter_WithReadOnlySpan_ShouldSetIsOutParameterToFalse(string buffer) + { + ReadOnlySpan value = buffer.AsSpan(); + + ParameterDescription sut = ParameterDescription.FromParameter(value); + + sut.IsOutParameter.Should().BeFalse(); + } +#endif + + [Theory] + [AutoData] + public void Is_WithFromOutParameter_ShouldCheckForMatchingValue(int value) + { + ParameterDescription sut = ParameterDescription.FromOutParameter(value); + + sut.Is(value).Should().BeTrue(); + sut.Is(value + 1).Should().BeFalse(); + sut.Is("foo").Should().BeFalse(); + } + + [Theory] + [AutoData] + public void Is_WithFromParameter_ShouldCheckForMatchingValue(string value) + { + ParameterDescription sut = ParameterDescription.FromParameter(value); + + sut.Is(value).Should().BeTrue(); + sut.Is($"other_{value}").Should().BeFalse(); + sut.Is(42).Should().BeFalse(); + } + + [Theory] + [AutoData] + public void ToString_ShouldReturnValue(int value) + { + ParameterDescription sut = ParameterDescription.FromParameter(value); + + string? result = sut.ToString(); + + result.Should().Be(value.ToString()); + } + + [Theory] + [AutoData] + public void ToString_WithStringValue_ShouldReturnValueEnclosedInQuotationMarks(string value) + { + ParameterDescription sut = ParameterDescription.FromOutParameter(value); + + string? result = sut.ToString(); + + result.Should().Be($"\"{value}\""); + } + +#if FEATURE_SPAN + [Theory] + [AutoData] + public void ToString_WithSpan_ShouldSetIsOutParameterToFalse(int[] buffer) + { + Span value = buffer.AsSpan(); + ParameterDescription sut = ParameterDescription.FromParameter(value); + string expectedString = $"[{string.Join(",", buffer)}]"; + + string? result = sut.ToString(); + + result.Should().Be(expectedString); + } + + [Theory] + [AutoData] + public void ToString_WithReadOnlySpan_ShouldSetIsOutParameterToFalse(string buffer) + { + ReadOnlySpan value = buffer.AsSpan(); + ParameterDescription sut = ParameterDescription.FromParameter(value); + string expectedString = $"[{string.Join(",", buffer.ToCharArray())}]"; + + string? result = sut.ToString(); + + result.Should().Be(expectedString); + } +#endif +} diff --git a/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs index b9ea16076..89cf696d6 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Statistics/StatisticsTests.cs @@ -183,7 +183,7 @@ string GetName(Type type, bool firstCharUpperCase) if (type.IsGenericType) { - int idx = type.Name.IndexOf("`", StringComparison.Ordinal); + int idx = type.Name.IndexOf('`', StringComparison.Ordinal); if (idx > 0) { return