// Author: Gockner, Simon // Created: 2021-12-03 // Copyright(c) 2021 SimonG. All Rights Reserved. using JetBrains.Annotations; using LightweightIocContainer; using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Registrations; using LightweightIocContainer.Validation; using NSubstitute; using NUnit.Framework; namespace Test.LightweightIocContainer.Validation; [TestFixture] public class IocValidatorTest { public interface ITest { } [UsedImplicitly] public interface IParameter { bool Method(); } private class Test : ITest { public Test(IParameter parameter) => parameter.Method(); } [UsedImplicitly] public interface IConstraint { } [UsedImplicitly] public interface IGenericTest where T : IConstraint, new() { } [UsedImplicitly] public class GenericTest : IGenericTest where T : IConstraint, new() { } [UsedImplicitly] public interface IGenericTestFactory { IGenericTest Create() where T : IConstraint, new(); } [UsedImplicitly] private class TestViewModelDontIgnoreDesignTimeCtor : ITest { public TestViewModelDontIgnoreDesignTimeCtor(string name, IParameter parameter) => parameter.Method(); public TestViewModelDontIgnoreDesignTimeCtor() => throw new Exception(); } private class Parameter : IParameter { public bool Method() => throw new NotImplementedException(); } [UsedImplicitly] public interface ITestFactory { ITest Create(IParameter parameter); } [UsedImplicitly] public interface ITestMissingParamFactory { ITest Create(string name); } [UsedImplicitly] public interface IInvalidTestFactory { ITest Create(); } [UsedImplicitly] public interface IParameterFactory { IParameter Create(); } private class TestInstallerNoFactory : IIocInstaller { public void Install(IRegistrationCollector registration) => registration.Add(); } private class TestInstallerWithFactory : IIocInstaller { public void Install(IRegistrationCollector registration) => registration.Add().WithFactory(); } private class TestInstallerWithInvalidFactory : IIocInstaller { public void Install(IRegistrationCollector registration) => registration.Add().WithFactory(); } private class TestInstallerInvalidFactoryParameterRegisteredWithoutFactory : IIocInstaller { public void Install(IRegistrationCollector registration) { registration.Add().WithFactory(); registration.Add(); } } private class TestInstallerInvalidFactoryParameterRegisteredWithFactory : IIocInstaller { public void Install(IRegistrationCollector registration) { registration.Add().WithFactory(); registration.Add().WithFactory(); } } private class TestInstallerInvalidFactoryParameterDesignTimeCtorNotIgnoredRegisteredWithFactory : IIocInstaller { public void Install(IRegistrationCollector registration) { registration.Add().WithFactory(); registration.Add().WithFactory(); } } private class TestInstallerInvalidFactoryViewModel : IIocInstaller { public void Install(IRegistrationCollector registration) { registration.Add().WithFactory(); registration.Add().WithFactory(); } } [Test] public void TestValidateWithoutFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerNoFactory()); IocValidator validator = new(iocContainer); AggregateException aggregateException = Assert.Throws(() => validator.Validate()); AssertNoMatchingConstructorFoundForType(aggregateException); } [Test] public void TestValidateWithFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerWithFactory()); IocValidator validator = new(iocContainer); validator.Validate(); } [Test] public void TestValidateWithParameter() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerNoFactory()); IocValidator validator = new(iocContainer); IParameter parameterMock = Substitute.For(); parameterMock.Method().Returns(true); validator.AddParameter(parameterMock); validator.Validate(); parameterMock.DidNotReceive().Method(); } [Test] public void TestValidateWithInvalidFactoryParameterWithoutFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerInvalidFactoryParameterRegisteredWithoutFactory()); IocValidator validator = new(iocContainer); validator.Validate(); } [Test] public void TestValidateWithInvalidParameterWithFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerInvalidFactoryParameterRegisteredWithFactory()); IocValidator validator = new(iocContainer); IParameter parameterMock = Substitute.For(); validator.AddParameter(parameterMock); AggregateException aggregateException = Assert.Throws(() => validator.Validate()); if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException) { Assert.Fail($"First element of {nameof(aggregateException.InnerExceptions)} is not of type {nameof(NoMatchingConstructorFoundException)}."); return; } if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException) { Assert.Fail($"First element of {nameof(noMatchingConstructorFoundException.InnerExceptions)} is not of type {nameof(ConstructorNotMatchingException)}."); return; } Assert.IsInstanceOf(iTest2CtorNotMatchingException.InnerExceptions[0]); } [Test] public void TestValidateViewModelWithInvalidParameterWithFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerInvalidFactoryViewModel()); IocValidator validator = new(iocContainer); AggregateException aggregateException = Assert.Throws(() => validator.Validate()); if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException) { Assert.Fail($"First element of {nameof(aggregateException.InnerExceptions)} is not of type {nameof(NoMatchingConstructorFoundException)}."); return; } if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException) { Assert.Fail($"First element of {nameof(noMatchingConstructorFoundException.InnerExceptions)} is not of type {nameof(ConstructorNotMatchingException)}."); return; } Assert.IsInstanceOf(iTest2CtorNotMatchingException.InnerExceptions[0]); } [Test] public void TestValidateViewModelWithInvalidParameterDesignTimeCtorNotIgnoredWithFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerInvalidFactoryParameterDesignTimeCtorNotIgnoredRegisteredWithFactory()); IocValidator validator = new(iocContainer); AggregateException aggregateException = Assert.Throws(() => validator.Validate()); if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException) { Assert.Fail($"First element of {nameof(aggregateException.InnerExceptions)} is not of type {nameof(NoMatchingConstructorFoundException)}."); return; } if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException) { Assert.Fail($"First element of {nameof(noMatchingConstructorFoundException.InnerExceptions)} is not of type {nameof(ConstructorNotMatchingException)}."); return; } Assert.IsInstanceOf(iTest2CtorNotMatchingException.InnerExceptions[0]); } [Test] public void TestValidateInvalidFactory() { IocContainer iocContainer = new(); iocContainer.Install(new TestInstallerWithInvalidFactory()); IocValidator validator = new(iocContainer); AggregateException aggregateException = Assert.Throws(() => validator.Validate()); AssertNoMatchingConstructorFoundForType(aggregateException); } [Test] public void TestValidateFactoryOfOpenGenericType() { IocContainer iocContainer = new(); iocContainer.Register(r => r.AddOpenGenerics(typeof(IGenericTest<>), typeof(GenericTest<>)).WithFactory()); IocValidator validator = new(iocContainer); validator.Validate(); } private void AssertNoMatchingConstructorFoundForType(AggregateException aggregateException) { Exception exception = aggregateException?.InnerExceptions[0]; if (exception is NoMatchingConstructorFoundException noMatchingConstructorFoundException) Assert.AreEqual(typeof(T), noMatchingConstructorFoundException.Type); else Assert.Fail($"Exception is no {nameof(NoMatchingConstructorFoundException)}, actual type: {exception?.GetType()}"); } }