public void GenerateAllocations_GivenModelExecuteThrowsException_ThrowsException()
        {
            //Arrange
            BuildProject buildProject = CreateBuildProject();

            buildProject.Build.Assembly = MockData.GetMockAssembly();

            IEnumerable <ProviderSummary> providers = new[]
            {
                new ProviderSummary {
                    Id = ProviderId, Name = ProviderName
                }
            };

            IEnumerable <ProviderSourceDataset> datasets = new[]
            {
                new ProviderSourceDataset()
            };

            Func <string, string, Task <IEnumerable <ProviderSourceDataset> > > func = (s, p) =>
            {
                return(Task.FromResult(datasets));
            };

            IEnumerable <CalculationResult> calculationResults = new[]
            {
                new CalculationResult
                {
                    Calculation = new Reference {
                        Id = CalculationId
                    }
                }
            };

            IAllocationModel allocationModel = Substitute.For <IAllocationModel>();

            allocationModel
            .When(x => x.Execute(Arg.Any <List <ProviderSourceDataset> >(), Arg.Any <ProviderSummary>()))
            .Do(x => { throw new Exception(); });

            IAllocationFactory allocationFactory = Substitute.For <IAllocationFactory>();

            allocationFactory
            .CreateAllocationModel(Arg.Any <Assembly>())
            .Returns(allocationModel);

            ILogger logger = CreateLogger();

            CalculationEngine calculationEngine = CreateCalculationEngine(allocationFactory, logger: logger);

            //Act
            Func <Task> test = () => calculationEngine.GenerateAllocations(buildProject, providers, func);

            //Assert
            test
            .Should()
            .ThrowExactly <Exception>();
        }
        public void CalculateProviderResult_WhenCalculationsAreNull_ShouldReturnResultWithEmptyCalculations()
        {
            // Arrange
            IAllocationModel mockAllocationModel = Substitute.For <IAllocationModel>();

            mockAllocationModel
            .Execute(Arg.Any <List <ProviderSourceDataset> >(), Arg.Any <ProviderSummary>())
            .Returns(new List <CalculationResult>());

            CalculationEngine calculationEngine = CreateCalculationEngine();
            ProviderSummary   providerSummary   = CreateDummyProviderSummary();
            BuildProject      buildProject      = CreateBuildProject();

            // Act
            ProviderResult result = calculationEngine.CalculateProviderResults(mockAllocationModel, buildProject, null,
                                                                               providerSummary, new List <ProviderSourceDataset>());

            // Assert
            result.CalculationResults.Should().BeEmpty();
            result.AllocationLineResults.Should().BeEmpty();
            result.Provider.Should().Be(providerSummary);
            result.SpecificationId.Should().BeEquivalentTo(buildProject.SpecificationId);
            result.Id.Should().BeEquivalentTo(GenerateId(providerSummary.Id, buildProject.SpecificationId));
        }
        async public Task GenerateAllocations_GivenBuildProject_Runs()
        {
            //Arrange
            BuildProject buildProject = CreateBuildProject();

            buildProject.Build.Assembly = MockData.GetMockAssembly();

            IEnumerable <ProviderSummary> providers = new[]
            {
                new ProviderSummary {
                    Id = ProviderId, Name = ProviderName
                }
            };

            IEnumerable <ProviderSourceDataset> datasets = new[]
            {
                new ProviderSourceDataset()
            };

            Func <string, string, Task <IEnumerable <ProviderSourceDataset> > > func = (s, p) =>
            {
                return(Task.FromResult(datasets));
            };

            IEnumerable <CalculationResult> calculationResults = new[]
            {
                new CalculationResult
                {
                    Calculation = new Reference {
                        Id = CalculationId
                    },
                }
            };

            IAllocationModel allocationModel = Substitute.For <IAllocationModel>();

            allocationModel
            .Execute(Arg.Any <List <ProviderSourceDataset> >(), Arg.Any <ProviderSummary>())
            .Returns(calculationResults);

            IAllocationFactory allocationFactory = Substitute.For <IAllocationFactory>();

            allocationFactory
            .CreateAllocationModel(Arg.Any <Assembly>())
            .Returns(allocationModel);

            ILogger logger = CreateLogger();

            ICalculationsRepository        calculationsRepository = CreateCalculationsRepository();
            List <CalculationSummaryModel> calculations           = new List <CalculationSummaryModel>()
            {
                new CalculationSummaryModel()
                {
                    Id = CalculationId,
                },
                new CalculationSummaryModel()
                {
                    Id = "calc2",
                },
                new CalculationSummaryModel()
                {
                    Id = "calc3",
                }
            };

            calculationsRepository
            .GetCalculationSummariesForSpecification(Arg.Any <string>())
            .Returns(calculations);

            CalculationEngine calculationEngine = CreateCalculationEngine(allocationFactory, calculationsRepository, logger: logger);

            //Act
            IEnumerable <ProviderResult> results = await calculationEngine.GenerateAllocations(buildProject, providers, func);

            //Assert
            results
            .Count()
            .Should()
            .Be(1);

            results
            .First()
            .CalculationResults
            .Count
            .Should()
            .Be(3);
        }
        public void CalculateProviderResult_WhenCalculationValuesReturnedWithMultipleAllocationLinesAndMixOfValuesAndNulls_ThenAllocationLineValuesAreSetCorrectly()
        {
            // Arrange
            List <Reference> policySpecificationsForFundingCalc = new List <Reference>()
            {
                new Reference("Spec1", "SpecOne"),
                new Reference("Spec2", "SpecTwo")
            };
            List <Reference> policySpecificationsForNumberCalc = new List <Reference>()
            {
                new Reference("Spec1", "SpecOne"),
            };
            Reference allocationLine1 = new Reference("allocationLine", "allocation line for Funding Calc and number calc");
            Reference allocationLine2 = new Reference("allocationLine2", "Second allocation line");
            Reference allocationLine3 = new Reference("allocationLine3", "Allocation line excluded");

            CalculationResult calc1 = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = new Reference("calc1", "Calc 1"),
                AllocationLine           = allocationLine1,
                CalculationSpecification = new Reference("FSpect", "FundingSpecification"),
                PolicySpecifications     = policySpecificationsForFundingCalc,
                Value = 10000
            };
            CalculationResult calc2 = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = new Reference("calc2", "Calc 2"),
                AllocationLine           = allocationLine1,
                CalculationSpecification = new Reference("FSpec2", "FundingSpecification2"),
                PolicySpecifications     = policySpecificationsForNumberCalc,
                Value = 20000
            };
            CalculationResult calc3 = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = new Reference("calc3", "Calc 3"),
                AllocationLine           = allocationLine2,
                CalculationSpecification = new Reference("calc3", "Calc 3"),
                PolicySpecifications     = policySpecificationsForNumberCalc,
                Value = 67
            };
            CalculationResult calc4 = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = new Reference("calc4", "Calc 4"),
                AllocationLine           = allocationLine3,
                CalculationSpecification = new Reference("calc4", "Calc 4"),
                PolicySpecifications     = policySpecificationsForNumberCalc,
                Value = null,
            };

            List <CalculationResult> calculationResults = new List <CalculationResult>()
            {
                calc1,
                calc2,
                calc3,
                calc4,
            };
            IAllocationModel mockAllocationModel = Substitute.For <IAllocationModel>();

            mockAllocationModel
            .Execute(Arg.Any <List <ProviderSourceDataset> >(), Arg.Any <ProviderSummary>())
            .Returns(calculationResults);

            CalculationEngine calculationEngine = CreateCalculationEngine();
            ProviderSummary   providerSummary   = CreateDummyProviderSummary();
            BuildProject      buildProject      = CreateBuildProject();


            IEnumerable <CalculationSummaryModel> calculationSummaryModels = new[]
            {
                new CalculationSummaryModel()
                {
                    Id              = "calc1",
                    Name            = "Calc 1",
                    CalculationType = CalculationType.Funding
                },
                new CalculationSummaryModel()
                {
                    Id              = "calc2",
                    Name            = "Calc 2",
                    CalculationType = CalculationType.Funding
                },
                new CalculationSummaryModel()
                {
                    Id              = "calc3",
                    Name            = "Calc 3",
                    CalculationType = CalculationType.Funding
                },
                new CalculationSummaryModel()
                {
                    Id              = "calc4",
                    Name            = "Calc 4",
                    CalculationType = CalculationType.Funding
                },
            };

            // Act
            var calculateProviderResults = calculationEngine.CalculateProviderResults(mockAllocationModel, buildProject, calculationSummaryModels,
                                                                                      providerSummary, new List <ProviderSourceDataset>());
            ProviderResult result = calculateProviderResults;

            // Assert
            result
            .AllocationLineResults
            .Should()
            .HaveCount(3);

            // Values are summed for allocation line
            result
            .AllocationLineResults[0]
            .Value
            .Should()
            .Be(30000);

            result
            .AllocationLineResults[1]
            .Value
            .Should()
            .Be(67);

            // All calculations for Allocation Line 3 returned nulls - therefore allocation line value is null
            result
            .AllocationLineResults[2]
            .Value
            .Should()
            .Be(null);
        }
        public void CalculateProviderResult_WhenCalculationsAreNotEmpty_ShouldReturnCorrectResult()
        {
            // Arrange
            List <Reference> policySpecificationsForFundingCalc = new List <Reference>()
            {
                new Reference("Spec1", "SpecOne"),
                new Reference("Spec2", "SpecTwo")
            };
            List <Reference> policySpecificationsForNumberCalc = new List <Reference>()
            {
                new Reference("Spec1", "SpecOne"),
            };
            Reference allocationLineReturned = new Reference("allocationLine", "allocation line for Funding Calc and number calc");

            Reference fundingCalcReference = new Reference("CalcF1", "Funding calc 1");
            Reference fundingCalcSpecificationReference = new Reference("FSpect", "FundingSpecification");

            Reference numbercalcReference = new Reference("CalcF2", "Funding calc 2");
            Reference numbercalcSpecificationReference = new Reference("FSpec2", "FundingSpecification2");

            CalculationResult fundingCalcReturned = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = fundingCalcReference,
                AllocationLine           = allocationLineReturned,
                CalculationSpecification = fundingCalcSpecificationReference,
                PolicySpecifications     = policySpecificationsForFundingCalc,
                Value = 10000
            };
            CalculationResult fundingCalcReturned2 = new CalculationResult()
            {
                CalculationType          = CalculationType.Funding,
                Calculation              = numbercalcReference,
                AllocationLine           = allocationLineReturned,
                CalculationSpecification = numbercalcSpecificationReference,
                PolicySpecifications     = policySpecificationsForNumberCalc,
                Value = 20000
            };

            List <CalculationResult> calculationResults = new List <CalculationResult>()
            {
                fundingCalcReturned,
                fundingCalcReturned2
            };
            IAllocationModel mockAllocationModel = Substitute.For <IAllocationModel>();

            mockAllocationModel
            .Execute(Arg.Any <List <ProviderSourceDataset> >(), Arg.Any <ProviderSummary>())
            .Returns(calculationResults);

            CalculationEngine calculationEngine = CreateCalculationEngine();
            ProviderSummary   providerSummary   = CreateDummyProviderSummary();
            BuildProject      buildProject      = CreateBuildProject();

            var nonMatchingCalculationModel = new CalculationSummaryModel()
            {
                Id              = "Non matching calculation",
                Name            = "Non matching calculation",
                CalculationType = CalculationType.Funding
            };
            IEnumerable <CalculationSummaryModel> calculationSummaryModels = new[]
            {
                new CalculationSummaryModel()
                {
                    Id              = fundingCalcReference.Id,
                    Name            = fundingCalcReference.Name,
                    CalculationType = CalculationType.Funding
                },
                new CalculationSummaryModel()
                {
                    Id              = numbercalcReference.Id,
                    Name            = numbercalcReference.Name,
                    CalculationType = CalculationType.Funding
                },
                nonMatchingCalculationModel
            };

            // Act
            var calculateProviderResults = calculationEngine.CalculateProviderResults(mockAllocationModel, buildProject, calculationSummaryModels,
                                                                                      providerSummary, new List <ProviderSourceDataset>());
            ProviderResult result = calculateProviderResults;

            // Assert
            result.Provider.Should().Be(providerSummary);
            result.SpecificationId.Should().BeEquivalentTo(buildProject.SpecificationId);
            result.Id.Should().BeEquivalentTo(GenerateId(providerSummary.Id, buildProject.SpecificationId));
            result.CalculationResults.Should().HaveCount(3);
            result.AllocationLineResults.Should().HaveCount(1);

            AllocationLineResult allocationLine = result.AllocationLineResults[0];

            allocationLine.Value = 30000;

            CalculationResult fundingCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == fundingCalcReference.Id);

            fundingCalcResult.Calculation.Should().BeEquivalentTo(fundingCalcReference);
            fundingCalcResult.CalculationType.Should().BeEquivalentTo(fundingCalcReturned.CalculationType);
            fundingCalcResult.AllocationLine.Should().BeEquivalentTo(allocationLineReturned);
            fundingCalcResult.CalculationSpecification.Should().BeEquivalentTo(fundingCalcSpecificationReference);
            fundingCalcResult.PolicySpecifications.Should().BeEquivalentTo(policySpecificationsForFundingCalc);
            fundingCalcResult.Value.Should().Be(fundingCalcReturned.Value.Value);

            CalculationResult numberCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == numbercalcReference.Id);

            numberCalcResult.Calculation.Should().BeEquivalentTo(numbercalcReference);
            numberCalcResult.CalculationType.Should().BeEquivalentTo(fundingCalcReturned2.CalculationType);
            numberCalcResult.AllocationLine.Should().BeEquivalentTo(allocationLineReturned);
            numberCalcResult.CalculationSpecification.Should().BeEquivalentTo(numbercalcSpecificationReference);
            numberCalcResult.PolicySpecifications.Should().BeEquivalentTo(policySpecificationsForNumberCalc);
            numberCalcResult.Value.Should().Be(fundingCalcReturned2.Value.Value);

            CalculationResult nonMatchingCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == "Non matching calculation");

            nonMatchingCalcResult.Calculation.Should().BeEquivalentTo(new Reference(nonMatchingCalculationModel.Id, nonMatchingCalculationModel.Name));
            nonMatchingCalcResult.CalculationType.Should().BeEquivalentTo(nonMatchingCalculationModel.CalculationType);
            nonMatchingCalcResult.AllocationLine.Should().BeNull();
            nonMatchingCalcResult.CalculationSpecification.Should().BeNull();
            nonMatchingCalcResult.PolicySpecifications.Should().BeNull();
            nonMatchingCalcResult.Value.Should().BeNull();
        }
        public void CalculateProviderResult_WhenCalculationsAreNotEmpty_ShouldReturnCorrectResult()
        {
            // Arrange

            List <Reference> policySpecificationsForFundingCalc = new List <Reference>()
            {
                new Reference("Spec1", "SpecOne"),
                new Reference("Spec2", "SpecTwo")
            };

            Reference fundingCalcReference = new Reference("CalcF1", "Funding calc 1");

            Reference numbercalcReference = new Reference("CalcF2", "Funding calc 2");

            Reference booleancalcReference = new Reference("CalcF3", "Funding calc 3");

            Reference fundingLineCalcReference = new Reference("FL1", "Funding line calc 1");

            CalculationResult fundingCalcReturned = new CalculationResult()
            {
                Calculation = fundingCalcReference,
                Value       = 10000
            };
            CalculationResult fundingCalcReturned2 = new CalculationResult()
            {
                Calculation = numbercalcReference,
                Value       = 20000
            };
            CalculationResult fundingCalcReturned3 = new CalculationResult()
            {
                Calculation = booleancalcReference,
                Value       = true
            };

            CalculationResultContainer calculationResultContainer = new CalculationResultContainer();

            List <CalculationResult> calculationResults = new List <CalculationResult>()
            {
                fundingCalcReturned,
                fundingCalcReturned2,
                fundingCalcReturned3
            };

            calculationResultContainer.CalculationResults = calculationResults;

            string fundingStreamId = "FS1";

            FundingLineResult fundingLineResult = new FundingLineResult
            {
                Value       = 1000,
                FundingLine = fundingLineCalcReference,
                FundingLineFundingStreamId = fundingStreamId
            };

            List <FundingLineResult> fundingLineResults = new List <FundingLineResult>
            {
                fundingLineResult
            };

            calculationResultContainer.FundingLineResults = fundingLineResults;

            IAllocationModel mockAllocationModel = Substitute.For <IAllocationModel>();

            mockAllocationModel
            .Execute(Arg.Any <Dictionary <string, ProviderSourceDataset> >(), Arg.Any <ProviderSummary>())
            .Returns(calculationResultContainer);

            CalculationEngine calculationEngine = CreateCalculationEngine();
            ProviderSummary   providerSummary   = CreateDummyProviderSummary();
            BuildProject      buildProject      = CreateBuildProject();

            var nonMatchingCalculationModel = new CalculationSummaryModel()
            {
                Id                   = "Non matching calculation",
                Name                 = "Non matching calculation",
                CalculationType      = CalculationType.Template,
                CalculationValueType = CalculationValueType.Number
            };
            IEnumerable <CalculationSummaryModel> calculationSummaryModels = new[]
            {
                new CalculationSummaryModel()
                {
                    Id                   = fundingCalcReference.Id,
                    Name                 = fundingCalcReference.Name,
                    CalculationType      = CalculationType.Template,
                    CalculationValueType = CalculationValueType.Number
                },
                new CalculationSummaryModel()
                {
                    Id                   = numbercalcReference.Id,
                    Name                 = numbercalcReference.Name,
                    CalculationType      = CalculationType.Template,
                    CalculationValueType = CalculationValueType.Number
                },
                new CalculationSummaryModel()
                {
                    Id                   = booleancalcReference.Id,
                    Name                 = booleancalcReference.Name,
                    CalculationType      = CalculationType.Template,
                    CalculationValueType = CalculationValueType.Boolean
                },
                nonMatchingCalculationModel
            };

            // Act
            var calculateProviderResults = calculationEngine.CalculateProviderResults(mockAllocationModel, buildProject.SpecificationId, calculationSummaryModels,
                                                                                      providerSummary, new Dictionary <string, ProviderSourceDataset>());
            ProviderResult result = calculateProviderResults;

            // Assert
            result.Provider.Should().Be(providerSummary);
            result.SpecificationId.Should().BeEquivalentTo(buildProject.SpecificationId);
            result.Id.Should().BeEquivalentTo(GenerateId(providerSummary.Id, buildProject.SpecificationId));
            result.CalculationResults.Should().HaveCount(3);
            result.FundingLineResults.Should().HaveCount(1);

            CalculationResult fundingCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == fundingCalcReference.Id);

            fundingCalcResult.Calculation.Should().BeEquivalentTo(fundingCalcReference);
            fundingCalcResult.CalculationType.Should().BeEquivalentTo(CalculationType.Template);
            fundingCalcResult.Value.Should().Be(fundingCalcReturned.Value);
            fundingCalcResult.CalculationDataType.Should().Be(CalculationDataType.Decimal);

            CalculationResult numberCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == numbercalcReference.Id);

            numberCalcResult.Calculation.Should().BeEquivalentTo(numbercalcReference);
            numberCalcResult.CalculationType.Should().BeEquivalentTo(CalculationType.Template);
            numberCalcResult.Value.Should().Be(fundingCalcReturned2.Value);
            numberCalcResult.CalculationDataType.Should().Be(CalculationDataType.Decimal);

            CalculationResult booleanCalcResult = result.CalculationResults.First(cr => cr.Calculation.Id == booleancalcReference.Id);

            booleanCalcResult.Calculation.Should().BeEquivalentTo(booleancalcReference);
            booleanCalcResult.CalculationType.Should().BeEquivalentTo(CalculationType.Template);
            booleanCalcResult.Value.Should().Be(fundingCalcReturned3.Value);
            booleanCalcResult.CalculationDataType.Should().Be(CalculationDataType.Boolean);

            FundingLineResult fundingLineCalcResult = result.FundingLineResults.First(cr => cr.FundingLine.Id == fundingLineCalcReference.Id);

            fundingLineCalcResult.FundingLine.Should().BeEquivalentTo(fundingLineCalcReference);
            fundingLineCalcResult.Value.Should().Be(fundingLineResult.Value);
            fundingLineCalcResult.FundingLineFundingStreamId.Should().Be(fundingStreamId);
        }