Use DryIoc for Automoqer, drop Unity dependency

(cherry picked from commit e3468daba04b52fbf41ce3004934a26b0220ec4f)
pull/2832/head
ta264 2 years ago
parent 9b120f4885
commit cf4103d73d

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.IO.Abstractions;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Disk;
@ -10,6 +11,12 @@ namespace NzbDrone.Common.Test.DiskTests
public abstract class DiskProviderFixtureBase<TSubject> : TestBase<TSubject>
where TSubject : class, IDiskProvider
{
[SetUp]
public void BaseSetup()
{
Mocker.SetConstant<IFileSystem>(new FileSystem());
}
[Test]
public void writealltext_should_truncate_existing()
{

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.IO.Abstractions;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Disk;
@ -10,6 +11,12 @@ namespace NzbDrone.Common.Test.DiskTests
public abstract class FreeSpaceFixtureBase<TSubject> : TestBase<TSubject>
where TSubject : class, IDiskProvider
{
[SetUp]
public void BaseSetup()
{
Mocker.SetConstant<IFileSystem>(new FileSystem());
}
[Test]
public void should_get_free_space_for_folder()
{

@ -1,7 +1,8 @@
using System.IO.Abstractions.TestingHelpers;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using Unity.Resolution;
using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.Framework
{
@ -14,12 +15,9 @@ namespace NzbDrone.Core.Test.Framework
[SetUp]
public void FileSystemTestSetup()
{
FileSystem = new MockFileSystem();
FileSystem = (MockFileSystem)Mocker.Resolve<IFileSystem>(FileSystemType.Mock);
DiskProvider = Mocker.Resolve<IDiskProvider>("ActualDiskProvider", new ResolverOverride[]
{
new ParameterOverride("fileSystem", FileSystem)
});
DiskProvider = Mocker.Resolve<IDiskProvider>(FileSystemType.Mock);
}
}
}

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
@ -126,6 +128,13 @@ namespace NzbDrone.Core.Test.MediaCoverTests
}
};
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "NonExistant.mp4");
var fileInfo = new FileInfo(path);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFileInfo(It.IsAny<string>()))
.Returns((FileInfoBase)fileInfo);
Subject.ConvertToLocalUrls(12, MediaCoverEntity.Artist, covers);
covers.Single().Url.Should().Be("/MediaCover/12/banner" + extension);

@ -13,6 +13,7 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Music;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
{
@ -55,9 +56,7 @@ namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
[SetUp]
public void Setup()
{
_diskProvider = Mocker.Resolve<IDiskProvider>("ActualDiskProvider");
Mocker.SetConstant<IDiskProvider>(_diskProvider);
_diskProvider = Mocker.Resolve<IDiskProvider>(FileSystemType.Actual);
Mocker.GetMock<IConfigService>()
.Setup(x => x.WriteAudioTags)

@ -1,4 +1,5 @@
using FluentAssertions;
using System.IO.Abstractions;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Mono.Disk;
@ -16,6 +17,7 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo
{
NotBsd();
Mocker.SetConstant<IFileSystem>(new FileSystem());
Mocker.SetConstant<IDiskProvider>(Mocker.Resolve<DiskProvider>());
}

@ -1,4 +1,5 @@
using System.IO;
using System.IO;
using System.IO.Abstractions;
using FluentAssertions;
using Moq;
using NUnit.Framework;
@ -20,6 +21,7 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
{
NotBsd();
Mocker.SetConstant<IFileSystem>(new FileSystem());
Mocker.SetConstant<IDiskProvider>(Mocker.Resolve<DiskProvider>());
var info = Subject.Read();
info.FullName.Should().NotBeNullOrWhiteSpace();

@ -2,20 +2,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using DryIoc;
using Moq;
using Moq.Language.Flow;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Test.Common.AutoMoq.Unity;
using Unity;
using Unity.Resolution;
[assembly: InternalsVisibleTo("AutoMoq.Tests")]
namespace NzbDrone.Test.Common.AutoMoq
{
@ -23,41 +17,29 @@ namespace NzbDrone.Test.Common.AutoMoq
public class AutoMoqer
{
public readonly MockBehavior DefaultBehavior = MockBehavior.Default;
public Type ResolveType;
private IUnityContainer _container;
private IDictionary<Type, object> _registeredMocks;
private readonly IContainer _container;
private readonly IDictionary<Type, object> _registeredMocks = new Dictionary<Type, object>();
public AutoMoqer()
{
SetupAutoMoqer(new UnityContainer());
}
_container = CreateTestContainer(new Container(rules => rules.WithMicrosoftDependencyInjectionRules().WithDefaultReuse(Reuse.Singleton)));
public AutoMoqer(MockBehavior defaultBehavior)
{
DefaultBehavior = defaultBehavior;
SetupAutoMoqer(new UnityContainer());
}
LoadPlatformLibrary();
public AutoMoqer(IUnityContainer container)
{
SetupAutoMoqer(container);
AssemblyLoader.RegisterSQLiteResolver();
}
public virtual T Resolve<T>()
{
ResolveType = typeof(T);
var result = _container.Resolve<T>();
SetConstant(result);
ResolveType = null;
return result;
}
public virtual T Resolve<T>(string name, params ResolverOverride[] resolverOverrides)
public virtual T Resolve<T>(object serviceKey)
{
ResolveType = typeof(T);
var result = _container.Resolve<T>(name, resolverOverrides);
var result = _container.Resolve<T>(serviceKey: serviceKey);
SetConstant(result);
ResolveType = null;
return result;
}
@ -70,8 +52,7 @@ namespace NzbDrone.Test.Common.AutoMoq
public virtual Mock<T> GetMock<T>(MockBehavior behavior)
where T : class
{
ResolveType = null;
var type = GetTheMockType<T>();
var type = typeof(T);
if (GetMockHasNotBeenCalledForThisType(type))
{
CreateANewMockAndRegisterIt<T>(type, behavior);
@ -89,88 +70,61 @@ namespace NzbDrone.Test.Common.AutoMoq
public virtual void SetMock(Type type, Mock mock)
{
if (_registeredMocks.ContainsKey(type) == false)
if (GetMockHasNotBeenCalledForThisType(type))
{
_registeredMocks.Add(type, mock);
}
if (mock != null)
{
_container.RegisterInstance(type, mock.Object);
_container.RegisterInstance(type, mock.Object, ifAlreadyRegistered: IfAlreadyRegistered.Replace);
}
}
public virtual void SetConstant<T>(T instance)
{
_container.RegisterInstance(instance);
_container.RegisterInstance(instance, ifAlreadyRegistered: IfAlreadyRegistered.Replace);
SetMock(instance.GetType(), null);
}
public ISetup<T> Setup<T>(Expression<Action<T>> expression)
where T : class
private IContainer CreateTestContainer(IContainer container)
{
return GetMock<T>().Setup(expression);
}
var c = container.CreateChild(IfAlreadyRegistered.Replace,
container.Rules
.WithDynamicRegistration((serviceType, serviceKey) =>
{
// ignore services with non-default key
if (serviceKey != null)
{
return null;
}
public ISetup<T, TResult> Setup<T, TResult>(Expression<Func<T, TResult>> expression)
where T : class
{
return GetMock<T>().Setup(expression);
}
if (serviceType == typeof(object))
{
return null;
}
public void Verify<T>(Expression<Action<T>> expression)
where T : class
{
GetMock<T>().Verify(expression);
}
if (serviceType.IsGenericType && serviceType.IsOpenGeneric())
{
return null;
}
public void Verify<T>(Expression<Action<T>> expression, string failMessage)
where T : class
{
GetMock<T>().Verify(expression, failMessage);
}
// get the Mock object for the abstract class or interface
if (serviceType.IsInterface || serviceType.IsAbstract)
{
return new[] { new DynamicRegistration(GetMockFactory(serviceType), IfAlreadyRegistered.Keep) };
}
public void Verify<T>(Expression<Action<T>> expression, Times times)
where T : class
{
GetMock<T>().Verify(expression, times);
}
// concrete types
var concreteTypeFactory = serviceType.ToFactory(Reuse.Singleton, FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
public void Verify<T>(Expression<Action<T>> expression, Times times, string failMessage)
where T : class
{
GetMock<T>().Verify(expression, times, failMessage);
}
public void VerifyAllMocks()
{
foreach (var registeredMock in _registeredMocks)
{
var mock = registeredMock.Value as Mock;
if (mock != null)
{
mock.VerifyAll();
}
}
}
private void SetupAutoMoqer(IUnityContainer container)
{
_container = container;
container.RegisterInstance(this);
return new[] { new DynamicRegistration(concreteTypeFactory) };
},
DynamicRegistrationFlags.Service | DynamicRegistrationFlags.AsFallback));
_registeredMocks = new Dictionary<Type, object>();
c.Register(typeof(Mock<>), Reuse.Singleton, FactoryMethod.DefaultConstructor());
RegisterPlatformLibrary(container);
AddTheAutoMockingContainerExtensionToTheContainer(container);
AssemblyLoader.RegisterSQLiteResolver();
}
private static void AddTheAutoMockingContainerExtensionToTheContainer(IUnityContainer container)
{
container.AddNewExtension<AutoMockingContainerExtension>();
return;
return c;
}
private Mock<T> TheRegisteredMockForThisType<T>(Type type)
@ -189,16 +143,21 @@ namespace NzbDrone.Test.Common.AutoMoq
private bool GetMockHasNotBeenCalledForThisType(Type type)
{
return _registeredMocks.ContainsKey(type) == false;
return !_registeredMocks.ContainsKey(type);
}
private static Type GetTheMockType<T>()
where T : class
private DelegateFactory GetMockFactory(Type serviceType)
{
return typeof(T);
var mockType = typeof(Mock<>).MakeGenericType(serviceType);
return new DelegateFactory(r =>
{
var mock = (Mock)r.Resolve(mockType);
SetMock(serviceType, mock);
return mock.Object;
}, Reuse.Singleton);
}
private void RegisterPlatformLibrary(IUnityContainer container)
private void LoadPlatformLibrary()
{
var assemblyName = "Lidarr.Windows";
@ -208,20 +167,25 @@ namespace NzbDrone.Test.Common.AutoMoq
}
var types = Assembly.Load(assemblyName).GetTypes();
// This allows us to resolve the platform specific disk provider in FileSystemTest
var diskProvider = types.Where(x => x.Name == "DiskProvider").SingleOrDefault();
container.RegisterType(typeof(IDiskProvider), diskProvider, "ActualDiskProvider");
// This seems to be required now so that Unity can resolve the extra arguments to the
// Mono DiskProvider. I don't understand why we need this now but didn't before.
// It's auto registering everything in the assembly with Ixxx -> xxx.
types.Except(new[] { diskProvider }).Where(t => t.GetInterfaces().Any(i => i.Name == "I" + t.Name)).ToList()
.ForEach(t => container.RegisterType(t.GetInterface("I" + t.Name, false), t));
// This tells the mocker to resolve IFileSystem using an actual filesystem (and not a mock)
// if not specified, giving the old behaviour before we switched to System.IO.Abstractions.
SetConstant<IFileSystem>(new FileSystem());
var diskProvider = types.SingleOrDefault(x => x.Name == "DiskProvider");
// The standard dynamic mock registrations, explicit so DryIoC doesn't get confused when we add alternatives
_container.Register(typeof(IFileSystem), GetMockFactory(typeof(IFileSystem)));
_container.Register(typeof(IDiskProvider), GetMockFactory(typeof(IDiskProvider)));
// A concrete registration from the platform library using a mock filesystem
_container.RegisterInstance<IFileSystem>(new MockFileSystem(), serviceKey: FileSystemType.Mock);
_container.Register(typeof(IDiskProvider),
diskProvider,
made: Parameters.Of.Type<IFileSystem>(serviceKey: FileSystemType.Mock),
serviceKey: FileSystemType.Mock);
// A concrete registration from the platform library using the actual filesystem
_container.Register<IFileSystem, FileSystem>(serviceKey: FileSystemType.Actual);
_container.Register(typeof(IDiskProvider),
diskProvider,
made: Parameters.Of.Type<IFileSystem>(serviceKey: FileSystemType.Actual),
serviceKey: FileSystemType.Actual);
}
}
}

@ -0,0 +1,8 @@
namespace NzbDrone.Test.Common.AutoMoq
{
public enum FileSystemType
{
Actual,
Mock
}
}

@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Moq;
using Unity;
using Unity.Builder;
using Unity.Strategies;
namespace NzbDrone.Test.Common.AutoMoq.Unity
{
public class AutoMockingBuilderStrategy : BuilderStrategy
{
private readonly IUnityContainer _container;
private readonly MockRepository _mockFactory;
private readonly IEnumerable<Type> _registeredTypes;
public AutoMockingBuilderStrategy(IEnumerable<Type> registeredTypes, IUnityContainer container)
{
var autoMoqer = container.Resolve<AutoMoqer>();
_mockFactory = new MockRepository(autoMoqer.DefaultBehavior);
_registeredTypes = registeredTypes;
_container = container;
}
public override void PreBuildUp(ref BuilderContext context)
{
var autoMoqer = _container.Resolve<AutoMoqer>();
var type = GetTheTypeFromTheBuilderContext(context);
if (AMockObjectShouldBeCreatedForThisType(type))
{
var mock = CreateAMockObject(type);
context.Existing = mock.Object;
autoMoqer.SetMock(type, mock);
}
}
private bool AMockObjectShouldBeCreatedForThisType(Type type)
{
var mocker = _container.Resolve<AutoMoqer>();
return TypeIsNotRegistered(type) && (mocker.ResolveType == null || mocker.ResolveType != type);
}
private static Type GetTheTypeFromTheBuilderContext(BuilderContext context)
{
// return (context.OriginalBuildKey).Type;
return context.Type;
}
private bool TypeIsNotRegistered(Type type)
{
return _registeredTypes.Any(x => x.Equals(type)) == false;
}
private Mock CreateAMockObject(Type type)
{
var createMethod = GenerateAnInterfaceMockCreationMethod(type);
return InvokeTheMockCreationMethod(createMethod);
}
private Mock InvokeTheMockCreationMethod(MethodInfo createMethod)
{
return (Mock)createMethod.Invoke(_mockFactory, new object[] { new List<object>().ToArray() });
}
private MethodInfo GenerateAnInterfaceMockCreationMethod(Type type)
{
var createMethodWithNoParameters = _mockFactory.GetType().GetMethod("Create", EmptyArgumentList());
return createMethodWithNoParameters.MakeGenericMethod(new[] { type });
}
private static Type[] EmptyArgumentList()
{
return new[] { typeof(object[]) };
}
}
}

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using Unity.Builder;
using Unity.Extension;
namespace NzbDrone.Test.Common.AutoMoq.Unity
{
public class AutoMockingContainerExtension : UnityContainerExtension
{
private readonly IList<Type> _registeredTypes = new List<Type>();
protected override void Initialize()
{
SetEventsOnContainerToTrackAllRegisteredTypes();
SetBuildingStrategyForBuildingUnregisteredTypes();
}
private void SetEventsOnContainerToTrackAllRegisteredTypes()
{
Context.Registering += (sender, e) => RegisterType(e.TypeFrom);
Context.RegisteringInstance += (sender, e) => RegisterType(e.RegisteredType);
}
private void RegisterType(Type typeToRegister)
{
_registeredTypes.Add(typeToRegister);
}
private void SetBuildingStrategyForBuildingUnregisteredTypes()
{
var strategy = new AutoMockingBuilderStrategy(_registeredTypes, Container);
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
}
}

@ -10,9 +10,9 @@
<PackageReference Include="NLog" Version="4.7.14" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="RestSharp" Version="106.15.0" />
<PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" />
<PackageReference Include="RestSharp.Serializers.SystemTextJson" Version="106.15.0" />
<PackageReference Include="System.IO.Abstractions" Version="13.2.29" />
<PackageReference Include="Unity" Version="5.11.10" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="13.2.29" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Common\Lidarr.Common.csproj" />

Loading…
Cancel
Save