public async Task GivenPipeOnSuperClass_WhenResolvingToInterface_ItShouldReturnSuperType()
        {
            // pre-arrange
            var instanceClassA = new TestClassA();
            var instanceSuperClassB = new TestSuperClassB();

            // arrange
            var builder = new SemanticBuilder();

            builder.InstallPipe<TestClassA, IEnumerable<TestSuperClassB>>(
                (@as, broker) =>
                {
                    Assert.AreSame(instanceClassA, @as);
                    return new[] { instanceSuperClassB };
                });

            var semanticBroker = builder.CreateBroker();

            // act
            var returnedInstance = await semanticBroker.On(instanceClassA).Output<IEnumerable<ITestInterface>>();

            // assert
            var result = returnedInstance.Single();
            Assert.AreSame(instanceSuperClassB, result);
        }
        public void GivenRegistry_WhenObserverIsInserted_ItShouldDetectPriorAndAfterRegistrations()
        {
            // pre-arrange
            int countPreRegisteredCalled = 0;
            int countPostRegisteredCalled = 0;

            // arrange
            var semanticBuilder = new SemanticBuilder();

            var observer1 = new TestRegistryObserver(package =>
            {
                countPreRegisteredCalled++;
                return null;
            });
            var observer2 = new TestRegistryObserver(package =>
            {
                countPostRegisteredCalled++;
                return null;
            });

            // act
            semanticBuilder.RegisterObserver(observer1);
            semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => (TestClassB)null);
            semanticBuilder.RegisterObserver(observer2);

            // assert
            Assert.GreaterOrEqual(countPreRegisteredCalled, 1);
            Assert.GreaterOrEqual(countPostRegisteredCalled, 1);
        }
        public async Task GivenMappingFromObjectAToObjectB_WhenSolvingCollectionToCollection_ItShouldResolve()
        {
            // pre-arrangement
            int counter = 0;
            var expectedReturnObject = new TestObjectB();

            // arrange
            var semanticBuilder = new SemanticBuilder();
            semanticBuilder.InstallPipe<TestObjectA, TestObjectB>((source, innerBroker) =>
            {
                counter++;
                return expectedReturnObject;
            });

            ISemanticBroker semanticBroker = semanticBuilder.CreateBroker();

            // act
            var enumerable = await semanticBroker.On(new[] {new TestObjectA()}.AsEnumerable())
                .Output<IEnumerable<TestObjectB>>();


            // assert
            TestObjectB returnedType = enumerable.Single();
            Assert.AreSame(expectedReturnObject, returnedType);
            Assert.AreEqual(1, counter);
        }
        public void GivenEmptyBroker_WhenResolvingNullSource_ItShouldThrowArgumentNullException()
        {
            // arrange
            var builder = new SemanticBuilder();
            ISemanticBroker broker = builder.CreateBroker();

            // act
            var argumentNullException = Assert.Throws<ArgumentNullException>(() => broker.On<string>(null));

            // assert
            Assert.AreEqual("source", argumentNullException.ParamName);
        }
        public void GivenAnInstance_WhenNullToProcessCallbackParameter_ItShouldThrowArgumentNullException()
        {
            // arrange
            var semanticBuilder = new SemanticBuilder();

            // act
            var argumentNullException =
                Assert.Throws<ArgumentNullException>(
                    () => semanticBuilder.InstallPipe((Func<string, ISemanticBroker, string>) null));

            // assert
            Assert.AreEqual("processCallback", argumentNullException.ParamName);
        }
        public void GivenPopulatedRegistry_WhenDuplicatingRegistrationMoreThanOnce_ItShouldThrowInvalidRegistryConfigurationException()
        {
            // arrange
            var semanticBuilder = new SemanticBuilder();

            semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => (TestClassB)null);
            semanticBuilder.InstallPipe<TestClassA, TestClassC>((a, innerBroker) => (TestClassC)null);
            semanticBuilder.InstallPipe<TestClassB, TestClassA>((b, innerBroker) => (TestClassA)null);

            // act
            Assert.Throws<InvalidRegistryConfigurationException>(
                () => semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => (TestClassB)null));
        }
        public async Task GivenRegistryWithMultiplePipes_WhenResolvingFromAToD_ItShouldChainAllThePipes()
        {
            for (int counter = 0; counter < 15; counter++)
            {
                // pre-arrange
                var instanceClassA = new TestClassA();
                var instanceClassB = new TestClassB();
                var instanceClassC = new TestClassC();
                var instanceClassD = new TestClassD();

                // arrange
                var semanticBuilder = new SemanticBuilder();

                var enrollmentList = new List<Action>
                {
                    () => semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) =>
                    {
                        Assert.AreSame(instanceClassA, a);
                        return instanceClassB;
                    }),
                    () => semanticBuilder.InstallPipe<TestClassB, TestClassC>((b, innerBroker) =>
                    {
                        Assert.AreSame(instanceClassB, b);
                        return instanceClassC;
                    }),
                    () => semanticBuilder.InstallPipe<TestClassC, TestClassD>((c, innerBroker) =>
                    {
                        Assert.AreSame(instanceClassC, c);
                        return instanceClassD;
                    }),
                };

                var enrollmentActions = enrollmentList.OrderBy(x=>Guid.NewGuid());
                foreach (var enrollmentAction in enrollmentActions)
                {
                    enrollmentAction();
                }

                ISemanticBroker broker = semanticBuilder.CreateBroker();

                // act
                var solvedExecution = await broker.On(instanceClassA).Output<TestClassD>();

                // assert
                Assert.AreEqual(instanceClassD, solvedExecution);
            }
        }
        public async Task GivenBrokerWithPipeFromObjectAToObjectB_WhenResolving_ItShouldInstantiateThePipe()
        {
            // pre-arrangement
            var expectedOutputObject = new TestClassB();

            // arrangement
            var builder = new SemanticBuilder();
            builder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => expectedOutputObject);

            ISemanticBroker broker = builder.CreateBroker();

            // act
            var actualOutputObject = await broker.On(new TestClassA()).Output<TestClassB>();

            // assert
            Assert.AreSame(expectedOutputObject, actualOutputObject);
        }
        public void GivenPopulatedRegistry_WhenObserverEnrollsLater_ItShouldBeNotifiedOfPreviousRegistrations()
        {
            // pre-arrange
            bool wasEventCalled = false;

            // arrange
            var semanticBuilder = new SemanticBuilder();
            semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => (TestClassB)null);

            // act
            var observer = new TestRegistryObserver(package =>
            {
                wasEventCalled = true;
                return null;
            });
            semanticBuilder.RegisterObserver(observer);

            // assert
            Assert.IsTrue(wasEventCalled);
        }
        public async Task GivenAtoArrayB_WhenSolvingSingleAToArraytA_ItShouldResolve()
        {
            // pre-arrangement
            var expectedReturnObject = new TestObjectA();


            // arrange
            var semanticBuilder = new SemanticBuilder();
            semanticBuilder.InstallPipe<TestObjectA, TestObjectB[]>((source, innerBroker) => new[] {new TestObjectB()});

            ISemanticBroker semanticBroker = semanticBuilder.CreateBroker();

            // act
            var enumerable = await semanticBroker.On(expectedReturnObject).Output<TestObjectA[]>();


            // assert
            TestObjectA returnedType = enumerable.Single();
            Assert.AreSame(expectedReturnObject, returnedType);
        }
        public void GivenRegistry_WhenPipesAreRegistered_ItShouldNotifyObservers()
        {
            // pre-arrange
            bool wasEventCalled = false;

            // arrange
            var semanticBuilder = new SemanticBuilder();
            var observer = new TestRegistryObserver(package =>
            {
                wasEventCalled = true;
                return null;
            });
            semanticBuilder.RegisterObserver(observer);

            // act
            semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) => (TestClassB)null);

            // assert
            Assert.IsTrue(wasEventCalled);
        }
        public async Task GivenRegistryWithMultipleSources_WhenResolvingToSpecificType_ItShouldResolve()
        {
            // pre-arrange
            var instanceClassA = new TestClassA();
            var instanceClassB = new TestClassB();
            var instanceClassC = new TestClassC();

            // arrange
            var semanaticBuilder = new SemanticBuilder();
            semanaticBuilder.InstallPipe<TestClassA, TestClassB>((a, semanticBroker) => instanceClassB);
            semanaticBuilder.InstallPipe<TestClassA, TestClassC>((a, semanticBroker) => instanceClassC);

            ISemanticBroker broker = semanaticBuilder.CreateBroker();

            // act
            var solveToB = await broker.On(instanceClassA).Output<TestClassB>();
            var solveToC = await broker.On(instanceClassA).Output<TestClassC>();

            // assert
            Assert.AreEqual(instanceClassB, solveToB);
            Assert.AreEqual(instanceClassC, solveToC);
        }
        public async Task GivenRegistration_WhenTheProcessDelegateIsCalled_ItShouldExecuteTheSpecifiedGenericCallback()
        {
            // pre-arrangement
            var expectedTestClassA = new TestClassA();
            var expectedTestClassB = new TestClassB();

            // arrange
            var semanticBuilder = new SemanticBuilder();

            semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) =>
            {
                Assert.AreSame(expectedTestClassA, a);
                return expectedTestClassB;
            });
            ISemanticBroker semanticBroker = semanticBuilder.CreateBroker();

            // act
            var processedOuput = await semanticBroker.On(expectedTestClassA).Output<TestClassB>();

            // assert
            Assert.AreSame(expectedTestClassB, processedOuput);
        }
        public void GivenRegistry_WhenResolvingToUnresolveableDestination_ItShouldThrowCannotResolveSemanticException()
        {
            var instanceClassA = new TestClassA();
            var instanceClassC = new TestClassC();

            // arrange
            var semanaticBuilder = new SemanticBuilder();
            semanaticBuilder.InstallPipe<TestClassA, TestClassB>((a, semanticBroker) => new TestClassB());
            semanaticBuilder.InstallPipe<TestClassB, TestClassA>((b, semanticBroker) => new TestClassA());

            ISemanticBroker broker = semanaticBuilder.CreateBroker();

            // act
            var exception1 =
                Assert.Throws<CannotResolveSemanticException>(async () => await broker.On(instanceClassA).Output<TestClassC>());
            var exception2 =
                Assert.Throws<CannotResolveSemanticException>(async () => await broker.On(instanceClassC).Output<TestClassA>());

            // assert
            string expectedExceptionMessage1 =
                string.Format("The input type '{0}' could not be resolved to output a type of {1}",
                    typeof (TestClassA), typeof (TestClassC));
            string expectedExceptionMessage2 =
                string.Format("The input type '{0}' could not be resolved to output a type of {1}",
                    typeof (TestClassC), typeof (TestClassA));

            Assert.AreEqual(expectedExceptionMessage1, exception1.Message);
            Assert.AreEqual(expectedExceptionMessage2, exception2.Message);
        }
        public async Task GivenRegistryWithOnePipes_WhenResolvingFromAToB_ItShouldCallIt()
        {
            // pre-arrange
            var instanceClassA = new TestClassA();
            var instanceClassB = new TestClassB();

            // arrange
            var semanaticBuilder = new SemanticBuilder();
            semanaticBuilder.InstallPipe<TestClassA, TestClassB>((a, semanticBroker) =>
            {
                Assert.AreSame(instanceClassA, a);
                return instanceClassB;
            });

            ISemanticBroker broker = semanaticBuilder.CreateBroker();

            // act
            var solvedExecution = await broker.On(instanceClassA).Output<TestClassB>();

            // assert
            Assert.AreEqual(instanceClassB, solvedExecution);
        }
        public async Task GivenTwoClassesWhenRegisteredAsList_WhenSolvingSingleClassToEnumerable_ItShouldResolve()
        {
            // pre-arrangement
            var expectedReturnObject = new TestObjectB();

            // arrange
            var semanticBuilder = new SemanticBuilder();
            semanticBuilder.InstallPipe<TestObjectA, List<TestObjectB>>(
                (source, innerBroker) => new List<TestObjectB> {expectedReturnObject});

            ISemanticBroker semanticBroker = semanticBuilder.CreateBroker();

            // act
            var enumerable = await semanticBroker.On(new TestObjectA()).Output<IEnumerable<TestObjectB>>();


            // assert
            TestObjectB returnedType = enumerable.Single();
            Assert.AreSame(expectedReturnObject, returnedType);
        }
        public async Task GivenRegistryWithPipe_WhenResolvingFromListToArray_ItShouldUseTheShortCircuit()
        {
            for (int counter = 0; counter < 15; counter++)
            {
                // arrange
                var semanticBuilder = new SemanticBuilder();

                var enrollmentList = new List<Action>
                {
                    () => semanticBuilder.InstallPipe<TestClassA, TestClassB>((a, innerBroker) =>
                    {
                        Assert.Fail();
                        return new TestClassB();
                    }),
                    () => semanticBuilder.InstallPipe<List<TestClassA>, TestClassB[]>(
                        (a, innerBroker) => (from b in a select new TestClassB()).ToArray())
                };

                var enrollmentActions = enrollmentList.OrderBy(x => Guid.NewGuid());
                foreach (var enrollmentAction in enrollmentActions)
                {
                    enrollmentAction();
                }

                ISemanticBroker broker = semanticBuilder.CreateBroker();

                // act
                await broker.On(new[] { new TestClassA() }).Output<TestClassB[]>();
                await broker.On(new List<TestClassA> { new TestClassA() }).Output<TestClassB[]>();
                await broker.On(new List<TestClassA> { new TestClassA() }).Output<List<TestClassB>>();
                await broker.On(new List<TestClassA> { new TestClassA() }).Output<IEnumerable<TestClassB>>();
                await broker.On(new[] { new TestClassA() }).Output<List<TestClassB>>();
            }
        }