Skip to content

Commit

Permalink
Conditionally include versioning of System.IO.Abstractions / Testable…
Browse files Browse the repository at this point in the history
…IO.System.IO.Abstractions based on version. If the version is 6, add default type mapping.
  • Loading branch information
cwinland committed May 28, 2024
1 parent 9032e24 commit fa866bc
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 20 deletions.
5 changes: 4 additions & 1 deletion FastMoq.Core/FastMoq.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="7.*" Condition="'$(TargetFramework)' == 'net7.0'" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.*" Condition="'$(TargetFramework)' == 'net8.0'" />

<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="*" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="17.2.3" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="19.2.91" Condition="'$(TargetFramework)' == 'net7.0'"/>
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" Version="21.*" Condition="'$(TargetFramework)' == 'net8.0'"/>

<PackageReference Include="NuGet.Build.Tasks.Pack" Version="6.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; buildtransitive</IncludeAssets>
Expand Down
38 changes: 30 additions & 8 deletions FastMoq.Core/Mocker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,28 @@ public T AddInjections<T>(T obj, Type? referenceType = null) where T : class?
return obj;
}

/// <summary>
/// Adds the file io abstraction mapping.
/// </summary>
public void AddFileSystemAbstractionMapping()
{
this
.AddType<IDirectory, DirectoryBase>()
.AddType<IDirectoryInfo, DirectoryInfoBase>()
.AddType<IDirectoryInfoFactory, MockDirectoryInfoFactory>()
.AddType<IDriveInfo, DriveInfoBase>()
.AddType<IDriveInfoFactory, MockDriveInfoFactory>()
.AddType<IFile, FileBase>()
.AddType<IFileInfo, FileInfoBase>()
.AddType<IFileInfoFactory, MockFileInfoFactory>()
.AddType<IFileStreamFactory, MockFileStreamFactory>()
.AddType<IFileSystem, FileSystemBase>()
.AddType<IFileSystemInfo, FileSystemInfoBase>()
.AddType<IFileSystemWatcherFactory, MockFileSystemWatcherFactory>()
.AddType<IPath, PathBase>()
;
}

/// <summary>
/// Creates a <see cref="MockModel" /> with the given <see cref="Mock" /> with the option of overwriting an existing
/// <see cref="MockModel" />
Expand Down Expand Up @@ -252,7 +274,7 @@ public MockModel<T> AddMock<T>(Mock<T> mock, bool overwrite, bool nonPublic = fa
/// <param name="replace">Replace type if already exists. Default: false.</param>
/// <param name="args">arguments needed in model.</param>
/// <exception cref="System.ArgumentException"></exception>
public void AddType(Type tInterface, Type tClass, Func<Mocker, object>? createFunc = null, bool replace = false, params object?[]? args)
public Mocker AddType(Type tInterface, Type tClass, Func<Mocker, object>? createFunc = null, bool replace = false, params object?[]? args)
{
ArgumentNullException.ThrowIfNull(tClass);
ArgumentNullException.ThrowIfNull(tInterface);
Expand All @@ -267,12 +289,14 @@ public void AddType(Type tInterface, Type tClass, Func<Mocker, object>? createFu
throw new ArgumentException($"{tClass.Name} is not assignable to {tInterface.Name}.");
}

if (typeMap.ContainsKey(tInterface) && replace)
if (replace && typeMap.ContainsKey(tInterface))
{
typeMap.Remove(tInterface);
}

typeMap.Add(tInterface, new InstanceModel(tInterface, tClass, createFunc, args?.ToList() ?? new()));
typeMap.Add(tInterface, new InstanceModel(tInterface, tClass, createFunc, args?.ToList() ?? []));

return this;
}

/// <summary>
Expand All @@ -282,7 +306,7 @@ public void AddType(Type tInterface, Type tClass, Func<Mocker, object>? createFu
/// <param name="createFunc">An optional create function used to create the class.</param>
/// <param name="replace">Replace type if already exists. Default: false.</param>
/// <param name="args">arguments needed in model.</param>
public void AddType<T>(Func<Mocker, T>? createFunc = null, bool replace = false, params object?[]? args) where T : class =>
public Mocker AddType<T>(Func<Mocker, T>? createFunc = null, bool replace = false, params object?[]? args) where T : class =>
AddType<T, T>(createFunc, replace, args);

/// <summary>
Expand All @@ -295,7 +319,7 @@ public void AddType<T>(Func<Mocker, T>? createFunc = null, bool replace = false,
/// <param name="args">arguments needed in model.</param>
/// <exception cref="ArgumentException">$"{typeof(TClass).Name} cannot be an interface."</exception>
/// <exception cref="ArgumentException">$"{typeof(TClass).Name} is not assignable to {typeof(TInterface).Name}."</exception>
public void AddType<TInterface, TClass>(Func<Mocker, TClass>? createFunc = null, bool replace = false, params object?[]? args)
public Mocker AddType<TInterface, TClass>(Func<Mocker, TClass>? createFunc = null, bool replace = false, params object?[]? args)
where TInterface : class where TClass : class => AddType(typeof(TInterface), typeof(TClass), createFunc, replace, args);

/// <summary>
Expand Down Expand Up @@ -1339,9 +1363,7 @@ internal ConstructorModel FindConstructor(bool bestGuess, Type type, bool nonPub
// if it is not best guess, then we can't know which constructor.
if (!bestGuess && constructors.Count(x => x.ParameterList.Length > 0) > 1)
{
throw new AmbiguousImplementationException(
"Multiple parameterized constructors exist. Cannot decide which to use."
);
throw this.GetAmbiguousConstructorImplementationException(type);
}

// Best Guess //
Expand Down
9 changes: 8 additions & 1 deletion FastMoq.Core/MockerTestBase_Constructors.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace FastMoq
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;

namespace FastMoq
{
/// <inheritdoc />
public partial class MockerTestBase<TComponent> where TComponent : class
Expand Down Expand Up @@ -62,6 +65,10 @@ protected MockerTestBase(Action<Mocker> setupMocksAction,
SetupMocksAction = setupMocksAction;
CreateComponentAction = createComponentAction ?? DefaultCreateAction;
CreatedComponentAction = createdComponentAction;

#if NET6_0
Mocks.AddFileSystemAbstractionMapping();
#endif
Component = GetComponent();
}

Expand Down
39 changes: 32 additions & 7 deletions FastMoq.Tests/MocksTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ namespace FastMoq.Tests
{
public class MocksTests : MockerTestBase<Mocker>
{
public MocksTests() : base(SetupAction, CreateAction, CreatedAction) { }
public MocksTests() : base(SetupAction, CreateAction, CreatedAction)
{
Component.AddFileSystemAbstractionMapping();
}

[Fact]
public void AddInjections()
Expand Down Expand Up @@ -366,28 +369,32 @@ public void CreateMockWithInjectParameters()
public void AddTypeT_ShouldBe_AddTypeTT()
{
Mocks.AddType<TestClassOne>(_ => Mocks.CreateInstance<TestClassOne>());
var t = Mocks.typeMap.First().Value.CreateFunc.Invoke(null);
var t = GetTypeMapOf<TestClassOne>().Value.CreateFunc.Invoke(null);
Mocks.typeMap.Clear();
Mocks.AddFileSystemAbstractionMapping();
Mocks.AddType<TestClassOne, TestClassOne>(_ => Mocks.CreateInstance<TestClassOne>());
var t2 = Mocks.typeMap.First().Value.CreateFunc.Invoke(null);
var t2 = GetTypeMapOf<TestClassOne>().Value.CreateFunc.Invoke(null);
t.Should().BeEquivalentTo(t2);
}

[Fact]
public void AddTypeT_ShouldBe_AddType()
{
Mocks.AddType<TestClassOne>(_ => Mocks.CreateInstance<TestClassOne>());
var t = Mocks.typeMap.First().Value.CreateFunc.Invoke(null);
var t = GetTypeMapOf<TestClassOne>().Value.CreateFunc.Invoke(null);
var o = Mocks.CreateInstance<TestClassOne>();
o.Should().BeEquivalentTo(t);
Mocks.typeMap.Clear();
Mocks.AddFileSystemAbstractionMapping();
Mocks.AddType(typeof(TestClassOne), typeof(TestClassOne), _ => Mocks.CreateInstance<TestClassOne>());
var t2 = Mocks.typeMap.First().Value.CreateFunc.Invoke(null);
var t2 = GetTypeMapOf<TestClassOne>().Value.CreateFunc.Invoke(null);
t.Should().BeEquivalentTo(t2);
o = Mocks.CreateInstance<TestClassOne>();
o.Should().BeEquivalentTo(t2);
}

private KeyValuePair<Type, IInstanceModel> GetTypeMapOf<T>() => Mocks.typeMap.First(x => x.Value.Type.FullName == typeof(T).FullName);

[Fact]
public void FileSystem_ShouldBeValid()
{
Expand Down Expand Up @@ -746,8 +753,26 @@ public void IsValidConstructor()
}

[Fact]
public void Mocker_AddMapClass() => new Action(() => Component.AddType<IFileSystem, FileSystem>())
.Should().NotThrow();
public void Mocker_AddMapClass_NotADuplicate()
{
Component.typeMap.Clear();
new Action(() => Component.AddType<IFileSystem, FileSystem>())
.Should().NotThrow();
}

[Fact]
public void Mocker_AddMapClass_Duplicate()
{
new Action(() => Component.AddType<IFileSystem, FileSystem>())
.Should().Throw<Exception>();
}

[Fact]
public void Mocker_AddMapClass_OverwriteDuplicate()
{
new Action(() => Component.AddType<IFileSystem, FileSystem>(replace: true))
.Should().NotThrow();
}

[Fact]
public void Mocker_AddMapClassIncompatibleInterface_ShouldThrow() => new Action(() => Component.AddType<IFileInfo, FileSystem>())
Expand Down
5 changes: 2 additions & 3 deletions FastMoq.Web/Blazor/MockerBlazorTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime;
using System.Security.Claims;

namespace FastMoq.Web.Blazor
Expand Down Expand Up @@ -532,7 +531,7 @@ public IRenderedComponent<TComponent> GetComponent<TComponent>(Func<IRenderedCom

return components.Count <= 1
? components.First(predicate)
: throw new AmbiguousImplementationException($"Multiple components of type '{typeof(TComponent)}' was found.");
: throw Mocks.GetAmbiguousImplementationException(typeof(TComponent));
}

/// <inheritdoc />
Expand All @@ -542,7 +541,7 @@ public IRenderedComponent<TComponent> GetComponent<TComponent>(Func<IElement, bo

return components.Count <= 1
? components.First()
: throw new AmbiguousImplementationException($"Multiple components of type '{typeof(TComponent)}' was found.");
: throw Mocks.GetAmbiguousImplementationException(typeof(TComponent));
}

/// <inheritdoc />
Expand Down

0 comments on commit fa866bc

Please sign in to comment.