diff --git a/Directory.Packages.props b/Directory.Packages.props index 7f8a9462a..cd9f1e9f1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -26,7 +26,6 @@ - @@ -35,6 +34,7 @@ + diff --git a/Examples/Directory.Build.props b/Examples/Directory.Build.props index 008c30326..22c05416d 100644 --- a/Examples/Directory.Build.props +++ b/Examples/Directory.Build.props @@ -28,13 +28,13 @@ + - diff --git a/Examples/SafeFileHandle/SafeFileHandle/CustomSafeFileHandleStrategy.cs b/Examples/SafeFileHandle/SafeFileHandle/CustomSafeFileHandleStrategy.cs index fc58dfa4f..a2265efc7 100644 --- a/Examples/SafeFileHandle/SafeFileHandle/CustomSafeFileHandleStrategy.cs +++ b/Examples/SafeFileHandle/SafeFileHandle/CustomSafeFileHandleStrategy.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Testably.Abstractions.FileSystem; +using System.IO.Abstractions; using Testably.Abstractions.Testing; using Testably.Abstractions.Testing.FileSystem; diff --git a/Tests/Directory.Build.props b/Tests/Directory.Build.props index d2549aa5c..317512cf6 100644 --- a/Tests/Directory.Build.props +++ b/Tests/Directory.Build.props @@ -26,7 +26,6 @@ - diff --git a/Tests/Helpers/Testably.Abstractions.TestHelpers/Testably.Abstractions.TestHelpers.csproj b/Tests/Helpers/Testably.Abstractions.TestHelpers/Testably.Abstractions.TestHelpers.csproj index 03c2df1bc..60643d32c 100644 --- a/Tests/Helpers/Testably.Abstractions.TestHelpers/Testably.Abstractions.TestHelpers.csproj +++ b/Tests/Helpers/Testably.Abstractions.TestHelpers/Testably.Abstractions.TestHelpers.csproj @@ -20,7 +20,6 @@ - diff --git a/Tests/Helpers/Testably.Abstractions.Tests.SourceGenerator/Testably.Abstractions.Tests.SourceGenerator.csproj b/Tests/Helpers/Testably.Abstractions.Tests.SourceGenerator/Testably.Abstractions.Tests.SourceGenerator.csproj index 2501d15a8..496dbb151 100644 --- a/Tests/Helpers/Testably.Abstractions.Tests.SourceGenerator/Testably.Abstractions.Tests.SourceGenerator.csproj +++ b/Tests/Helpers/Testably.Abstractions.Tests.SourceGenerator/Testably.Abstractions.Tests.SourceGenerator.csproj @@ -23,7 +23,6 @@ - diff --git a/Tests/Testably.Abstractions.Testing.Tests/Helpers/PathHelperTests.cs b/Tests/Testably.Abstractions.Testing.Tests/Helpers/PathHelperTests.cs index 070ecf281..262f12073 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/Helpers/PathHelperTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/Helpers/PathHelperTests.cs @@ -1,5 +1,4 @@ -using Moq; -using System.IO; +using System.IO; using Testably.Abstractions.Testing.Helpers; using Testably.Abstractions.Testing.Tests.TestHelpers; @@ -75,18 +74,12 @@ public void public void ThrowCommonExceptionsIfPathIsInvalid_WithInvalidCharacters( char[] invalidChars) { - Mock mockFileSystem = new(); - Mock pathSystemMock = new(); - mockFileSystem.Setup(m => m.Path).Returns(pathSystemMock.Object); - pathSystemMock.Setup(m => m.GetInvalidPathChars()).Returns(invalidChars); - pathSystemMock - .Setup(m => m.GetFullPath(It.IsAny())) - .Returns(s => s); + FileSystemMockForPath mockFileSystem = new(invalidChars); string path = invalidChars[0] + "foo"; Exception? exception = Record.Exception(() => { - path.EnsureValidFormat(mockFileSystem.Object); + path.EnsureValidFormat(mockFileSystem); }); #if NETFRAMEWORK @@ -97,4 +90,288 @@ public void ThrowCommonExceptionsIfPathIsInvalid_WithInvalidCharacters( .Which.Message.Should().Contain($"'{path}'"); #endif } + + private sealed class FileSystemMockForPath : IFileSystem + { + public FileSystemMockForPath(char[] invalidChars) + { + Path = new PathMockWithInvalidChars(invalidChars); + } + + #region IFileSystem Members + + /// + public IDirectory Directory + => throw new NotSupportedException(); + + /// + public IDirectoryInfoFactory DirectoryInfo + => throw new NotSupportedException(); + + /// + public IDriveInfoFactory DriveInfo + => throw new NotSupportedException(); + + /// + public IFile File + => throw new NotSupportedException(); + + /// + public IFileInfoFactory FileInfo + => throw new NotSupportedException(); + + /// + public IFileStreamFactory FileStream + => throw new NotSupportedException(); + + /// + public IFileSystemWatcherFactory FileSystemWatcher + => throw new NotSupportedException(); + + /// + public IPath Path { get; } + + #endregion + + private sealed class PathMockWithInvalidChars : IPath + { + private readonly char[] _invalidChars; + + public PathMockWithInvalidChars(char[] invalidChars) + { + _invalidChars = invalidChars; + } + + #region IPath Members + + /// + public char AltDirectorySeparatorChar + => throw new NotSupportedException(); + + /// + public char DirectorySeparatorChar + => throw new NotSupportedException(); + + /// + public IFileSystem FileSystem + => throw new NotSupportedException(); + + /// + public char PathSeparator + => throw new NotSupportedException(); + + /// + public char VolumeSeparatorChar + => throw new NotSupportedException(); + + /// + public string ChangeExtension(string? path, string? extension) + => throw new NotSupportedException(); + + /// + public string Combine(string path1, string path2) + => throw new NotSupportedException(); + + /// + public string Combine(string path1, string path2, string path3) + => throw new NotSupportedException(); + + /// + public string Combine(string path1, string path2, string path3, string path4) + => throw new NotSupportedException(); + + /// + public string Combine(params string[] paths) + => throw new NotSupportedException(); + +#if FEATURE_PATH_ADVANCED + /// + public bool EndsInDirectorySeparator(ReadOnlySpan path) + => throw new NotSupportedException(); + + /// + public bool EndsInDirectorySeparator(string path) + => throw new NotSupportedException(); +#endif + + /// + public bool Exists(string? path) + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public ReadOnlySpan GetDirectoryName(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public string GetDirectoryName(string? path) + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public ReadOnlySpan GetExtension(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public string GetExtension(string? path) + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public ReadOnlySpan GetFileName(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public string GetFileName(string? path) + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public ReadOnlySpan GetFileNameWithoutExtension(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public string GetFileNameWithoutExtension(string? path) + => throw new NotSupportedException(); + + /// + public string GetFullPath(string path) + => path; + +#if FEATURE_PATH_RELATIVE + /// + public string GetFullPath(string path, string basePath) + => throw new NotSupportedException(); +#endif + + /// + public char[] GetInvalidFileNameChars() + => throw new NotSupportedException(); + + /// + public char[] GetInvalidPathChars() + => _invalidChars; + +#if FEATURE_SPAN + /// + public ReadOnlySpan GetPathRoot(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public string GetPathRoot(string? path) + => throw new NotSupportedException(); + + /// + public string GetRandomFileName() + => throw new NotSupportedException(); + +#if FEATURE_PATH_RELATIVE + /// + public string GetRelativePath(string relativeTo, string path) + => throw new NotSupportedException(); +#endif + + /// + public string GetTempFileName() + => throw new NotSupportedException(); + + /// + public string GetTempPath() + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public bool HasExtension(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public bool HasExtension(string? path) + => throw new NotSupportedException(); + +#if FEATURE_PATH_RELATIVE + /// + public bool IsPathFullyQualified(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public bool IsPathFullyQualified(string path) + => throw new NotSupportedException(); + +#if FEATURE_SPAN + /// + public bool IsPathRooted(ReadOnlySpan path) + => throw new NotSupportedException(); +#endif + + /// + public bool IsPathRooted(string? path) + => throw new NotSupportedException(); + +#if FEATURE_PATH_JOIN + /// + public string Join(ReadOnlySpan path1, ReadOnlySpan path2) + => throw new NotSupportedException(); + + /// + public string Join(ReadOnlySpan path1, ReadOnlySpan path2, + ReadOnlySpan path3) + => throw new NotSupportedException(); +#endif + +#if FEATURE_PATH_ADVANCED + /// + public string Join(string? path1, string? path2) + => throw new NotSupportedException(); + + /// + public string Join(string? path1, string? path2, string? path3) + => throw new NotSupportedException(); + + /// + public string Join(params string?[] paths) + => throw new NotSupportedException(); + + /// + public string Join(ReadOnlySpan path1, ReadOnlySpan path2, + ReadOnlySpan path3, ReadOnlySpan path4) + => throw new NotSupportedException(); + + /// + public string Join(string? path1, string? path2, string? path3, string? path4) + => throw new NotSupportedException(); +#endif + +#if FEATURE_PATH_ADVANCED + /// + public ReadOnlySpan TrimEndingDirectorySeparator(ReadOnlySpan path) + => throw new NotSupportedException(); + + /// + public string TrimEndingDirectorySeparator(string path) + => throw new NotSupportedException(); +#endif + +#if FEATURE_PATH_JOIN + /// + public bool TryJoin(ReadOnlySpan path1, ReadOnlySpan path2, + Span destination, out int charsWritten) + => throw new NotSupportedException(); + + /// + public bool TryJoin(ReadOnlySpan path1, ReadOnlySpan path2, + ReadOnlySpan path3, Span destination, + out int charsWritten) + => throw new NotSupportedException(); +#endif + + #endregion + } + } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/RandomProvider.GeneratorTests.cs b/Tests/Testably.Abstractions.Testing.Tests/RandomProvider.GeneratorTests.cs index 48b2ea69a..fac4380cd 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/RandomProvider.GeneratorTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/RandomProvider.GeneratorTests.cs @@ -1,4 +1,4 @@ -using Moq; +using System.Collections; using System.Collections.Generic; using System.Linq; @@ -82,15 +82,13 @@ public void FromCallback_ShouldExecuteCallback() [Fact] public void FromEnumerable_Dispose_ShouldDisposeEnumerator() { - Mock> mock = new(); - Mock> enumeratorMock = new(); - mock.Setup(m => m.GetEnumerator()).Returns(enumeratorMock.Object); + EnumerableMock enumerable = new(); RandomProvider.Generator sut = - RandomProvider.Generator.FromEnumerable(mock.Object); + RandomProvider.Generator.FromEnumerable(enumerable); sut.Dispose(); - enumeratorMock.Verify(m => m.Dispose()); + enumerable.Enumerator.IsDisposed.Should().BeTrue(); } [Fact] @@ -216,5 +214,51 @@ public void Operator_FromValue(Guid value) results.Should().AllBeEquivalentTo(value); } + + private sealed class EnumerableMock : IEnumerable + { + public EnumeratorMock Enumerator { get; } = new(); + + #region IEnumerable Members + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public IEnumerator GetEnumerator() + => Enumerator; + + #endregion + } + + private sealed class EnumeratorMock : IEnumerator + { + public bool IsDisposed { get; private set; } + + #region IEnumerator Members + + /// + public int Current + => 0; + + /// + object IEnumerator.Current + => Current; + + /// + public void Dispose() + => IsDisposed = true; + + /// + public bool MoveNext() + => throw new NotSupportedException(); + + /// + public void Reset() + => throw new NotSupportedException(); + + #endregion + } } } diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/Tests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/Tests.cs index 3ebbbcd08..a784cff75 100644 --- a/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/Tests.cs +++ b/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/Tests.cs @@ -1,4 +1,3 @@ -using Moq; using System.ComponentModel; using System.IO; using System.Threading; @@ -132,7 +131,7 @@ public void Site_ShouldBeInitializedWithNull() [SkippableFact] public void Site_ShouldBeWritable() { - ISite? site = new Mock().Object; + ISite site = new MockSite(); FileSystem.Initialize(); using IFileSystemWatcher fileSystemWatcher = FileSystem.FileSystemWatcher.New(BasePath); @@ -155,7 +154,7 @@ public void SynchronizingObject_ShouldBeInitializedWithNull() [SkippableFact] public void SynchronizingObject_ShouldBeWritable() { - ISynchronizeInvoke? synchronizingObject = new Mock().Object; + ISynchronizeInvoke synchronizingObject = new MockSynchronizeInvoke(); FileSystem.Initialize(); using IFileSystemWatcher fileSystemWatcher = FileSystem.FileSystemWatcher.New(BasePath); @@ -164,4 +163,108 @@ public void SynchronizingObject_ShouldBeWritable() fileSystemWatcher.SynchronizingObject.Should().Be(synchronizingObject); } + + private sealed class MockSite : ISite + { + public MockSite() + { + Component = new ComponentMock(this); + Container = new ContainerMock(); + } + + #region ISite Members + + /// + public IComponent Component { get; } + + /// + public IContainer Container { get; } + + /// + public bool DesignMode => true; + + /// + public string? Name { get; set; } = ""; + + /// + public object GetService(Type serviceType) + => throw new NotSupportedException(); + + #endregion + + private sealed class ContainerMock : IContainer + { + /// + public void Dispose() + { + // Ignore any call in tests + } + + /// + public void Add(IComponent? component) + { + // Ignore any call in tests + } + + /// + public void Add(IComponent? component, string? name) + { + // Ignore any call in tests + } + + /// + public void Remove(IComponent? component) + { + // Ignore any call in tests + } + + /// + public ComponentCollection Components + => throw new NotSupportedException(); + } + + private sealed class ComponentMock : IComponent + { + public ComponentMock(ISite site) + { + Site = site; + } + + /// + public void Dispose() + { + // Ignore any call in tests + } + + /// + public ISite? Site { get; set; } + + /// + public event EventHandler? Disposed; + } + } + + private sealed class MockSynchronizeInvoke : ISynchronizeInvoke + { + #region ISynchronizeInvoke Members + + /// + public bool InvokeRequired + => true; + + /// + public IAsyncResult BeginInvoke(Delegate method, object?[]? args) + => throw new NotSupportedException(); + + /// + public object EndInvoke(IAsyncResult result) + => throw new NotSupportedException(); + + /// + // ReSharper disable once ReturnTypeCanBeNotNullable + public object? Invoke(Delegate method, object?[]? args) + => throw new NotSupportedException(); + + #endregion + } }