示例#1
0
        /// <summary>
        /// Adds the time-till-completion estimates of a simulation to the collection.
        /// </summary>
        /// <param name="roadmapEstimate">The estimate for the whole roadmap.</param>
        /// <param name="projectEstimates">The estimates for each of the individual projects.</param>
        /// <exception cref="ArgumentException">Thrown when <paramref name="projectEstimates"/> is not consistent with expected projects.</exception>
        /// <exception cref="ArgumentNullException">Thrown when <paramref name="roadmapEstimate"/> or <paramref name="projectEstimates"/> is null.</exception>
        public void AddEstimationsForSimulation(WorkEstimate roadmapEstimate, IReadOnlyList <WorkEstimate> projectEstimates)
        {
            if (roadmapEstimate is null)
            {
                throw new ArgumentNullException(nameof(roadmapEstimate));
            }
            if (projectEstimates is null)
            {
                throw new ArgumentNullException(nameof(projectEstimates));
            }
            if (roadmapEstimatesOfEachSimulation.Capacity == roadmapEstimatesOfEachSimulation.Count)
            {
                throw new InvalidOperationException("Adding these estimation would exceed the expected number of simulations.");
            }

            ValidateThatNumberOfEstimatesMatchExpectedCount(projectEstimates);

            roadmapEstimatesOfEachSimulation.Add(roadmapEstimate);

            for (int i = 0; i < projectEstimates.Count; i++)
            {
                var currentProjectEstimatesForProject   = projectEstimatesOfEachSimulation[i];
                var newProjectEstimateForThisSimulation = projectEstimates[i];
                ValidateThatProjectIdentifiersAreConsistent(currentProjectEstimatesForProject, newProjectEstimateForThisSimulation);

                currentProjectEstimatesForProject.Add(newProjectEstimateForThisSimulation);
            }
        }
        private static object[] GetRowData(
            TimeTillCompletionEstimationsCollection estimations,
            int simulationIndex,
            ConfigurationMode mode,
            CultureInfo culture)
        {
            WorkEstimate roadmapEstimate = estimations.GetRoadmapEstimationForSimulation(simulationIndex);
            var          rowData         = new object[]
            {
                FormatEstimatedNumberOfWorkingDays(roadmapEstimate, culture),
                roadmapEstimate.IsIndeterminate
            };

            if (mode == ConfigurationMode.Advanced)
            {
                var additionalRowData = new object[estimations.NumberOfProjectsInRoadmap * 2];
                for (int projectIndex = 0; projectIndex < estimations.NumberOfProjectsInRoadmap; projectIndex++)
                {
                    WorkEstimate projectEstimate = estimations.GetProjectEstimationForSimulation(projectIndex, simulationIndex);
                    additionalRowData[projectIndex * 2]     = FormatEstimatedNumberOfWorkingDays(projectEstimate, culture);
                    additionalRowData[projectIndex * 2 + 1] = projectEstimate.IsIndeterminate;
                }
                rowData = rowData.Concat(additionalRowData).ToArray();
            }

            return(rowData);
        }
示例#3
0
        public void GIVEN_multiple_input_metrics_AND_one_project_WHEN_estimating_time_to_completion_THEN_returned_number_of_work_days_depends_on_randomly_selected_metrics(
            IReadOnlyCollection <ThroughputPerDay> throughputs, Project project, Queue <int> selectedIndices, double expectedNumberOfDaysRequired)
        {
            var inputMetrics = ToInputMetrics(throughputs);
            var roadmap      = new Roadmap(new[] { project });

            randomNumberGeneratorMock
            .Setup(rng => rng.GetRandomIndex(throughputs.Count))
            .Returns(selectedIndices.Dequeue);

            var estimator = new TimeTillCompletionEstimator(inputMetrics, randomNumberGeneratorMock.Object, someMaximumNumberOfIterations);

            var estimations = estimator.Estimate(roadmap);

            Assert.Equal(2, estimations.Count);

            WorkEstimate roadmapWorkEstimate = estimations[0];

            Assert.Equal("Roadmap", roadmapWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(expectedNumberOfDaysRequired, roadmapWorkEstimate);
            AssertEstimateIsDeterminate(roadmapWorkEstimate);

            WorkEstimate projectWorkEstimate = estimations[1];

            Assert.Equal("Project", projectWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(expectedNumberOfDaysRequired, projectWorkEstimate);
            AssertEstimateIsDeterminate(projectWorkEstimate);
        }
示例#4
0
 private static bool IsProjectIdentifierConsistentWithPriorProjectSimulations(
     WorkEstimate newProjectEstimate,
     IReadOnlyList <WorkEstimate> currentProjectEstimatesForProject)
 {
     return(currentProjectEstimatesForProject.Count == 0 ||
            newProjectEstimate.Identifier == currentProjectEstimatesForProject[0].Identifier);
 }
示例#5
0
        public void GIVEN_one_input_metric_AND_one_project_WHEN_estimating_time_to_completion_THEN_return_number_of_work_days(
            ThroughputPerDay throughput,
            Project project,
            double expectedNumberOfDaysRequired)
        {
            var inputMetrics = ToInputMetrics(new[] { throughput });
            var roadmap      = new Roadmap(new[] { project });

            var estimator = new TimeTillCompletionEstimator(inputMetrics, randomNumberGeneratorMock.Object, someMaximumNumberOfIterations);

            var estimations = estimator.Estimate(roadmap);

            Assert.Equal(2, estimations.Count);

            WorkEstimate roadmapWorkEstimate = estimations[0];

            Assert.Equal("Roadmap", roadmapWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(expectedNumberOfDaysRequired, roadmapWorkEstimate);
            AssertEstimateIsDeterminate(roadmapWorkEstimate);

            WorkEstimate projectWorkEstimate = estimations[1];

            Assert.Equal("Project", projectWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(expectedNumberOfDaysRequired, roadmapWorkEstimate);
            AssertEstimateIsDeterminate(roadmapWorkEstimate);
        }
示例#6
0
 private static void ValidateThatProjectIdentifiersAreConsistent(
     IReadOnlyList <WorkEstimate> currentProjectEstimatesForProject,
     WorkEstimate newProjectEstimateForThisSimulation)
 {
     if (!IsProjectIdentifierConsistentWithPriorProjectSimulations(newProjectEstimateForThisSimulation, currentProjectEstimatesForProject))
     {
         throw new ArgumentException("A project estimate's identifier mismatches a the expected project's identifier.", "projectEstimates");
     }
 }
        public void GIVEN_estimations_collection_for_1_simulation_WHEN_adding_2nd_simulation_results_THEN_throw_InvalidOperationException()
        {
            var estimates = new TimeTillCompletionEstimationsCollection(1, 1);

            var roadmap          = CreateCompletedRoadmap();
            var roadmapEstimate  = new WorkEstimate(roadmap, 1.0);
            var projectEstimates = roadmap.Projects.Select(p => new WorkEstimate(p, 1.0)).ToArray();

            estimates.AddEstimationsForSimulation(roadmapEstimate, projectEstimates);
            void SecondCall() => estimates.AddEstimationsForSimulation(roadmapEstimate, projectEstimates);

            var actualException = Assert.Throws <InvalidOperationException>(SecondCall);

            Assert.Equal("Adding these estimation would exceed the expected number of simulations.", actualException.Message);
        }
示例#8
0
        private static IReadOnlyList <WorkEstimate> CreateWorkEstimatesResult(
            Roadmap roadmap,
            double numberOfDaysToFinishRoadmap,
            IReadOnlyDictionary <Project, double> estimatedNumberOfWorkingDaysRequiredToFinishWorkPerProject)
        {
            var workEstimates = new WorkEstimate[estimatedNumberOfWorkingDaysRequiredToFinishWorkPerProject.Count + 1];

            workEstimates[0] = new WorkEstimate(roadmap, numberOfDaysToFinishRoadmap);
            var index = 1;

            foreach (KeyValuePair <Project, double> keyValuePair in estimatedNumberOfWorkingDaysRequiredToFinishWorkPerProject)
            {
                workEstimates[index++] = new WorkEstimate(keyValuePair.Key, keyValuePair.Value);
            }
            return(workEstimates);
        }
        public void GIVEN_some_simulation_results_added_WHEN_getting_estimates_for_invalid_project_number_THEN_throw_ArgumentOutOfRangeException(
            int invalidProjectIndex)
        {
            var estimates = new TimeTillCompletionEstimationsCollection(2, 1);

            var roadmap          = CreateCompletedRoadmap();
            var roadmapEstimate  = new WorkEstimate(roadmap, 1.0);
            var projectEstimates = roadmap.Projects.Select(p => new WorkEstimate(p, 1.0)).ToArray();

            estimates.AddEstimationsForSimulation(roadmapEstimate, projectEstimates);
            estimates.AddEstimationsForSimulation(roadmapEstimate, projectEstimates);

            object Call() => estimates[invalidProjectIndex];

            var actualException = Assert.Throws <ArgumentOutOfRangeException>("projectIndex", Call);

            Assert.StartsWith("Project index must be in range [0, 0].", actualException.Message);
        }
        public void GIVEN_estimations_collection_with_1_simulation_WHEN_adding_different_project_estimations_THEN_throw_ArgumentException()
        {
            var estimates = new TimeTillCompletionEstimationsCollection(2, 1);

            var roadmap          = CreateCompletedRoadmap();
            var roadmapEstimate  = new WorkEstimate(roadmap, 1.0);
            var projectEstimates = roadmap.Projects.Select(p => new WorkEstimate(p, 1.0)).ToArray();

            estimates.AddEstimationsForSimulation(roadmapEstimate, projectEstimates);

            var differentProjectEstimates = new[] { new WorkEstimate(CreateCompletedProject("someUniqueName"), 1.0) };

            void SecondCall() => estimates.AddEstimationsForSimulation(roadmapEstimate, differentProjectEstimates);

            var actualException = Assert.Throws <ArgumentException>("projectEstimates", SecondCall);

            Assert.StartsWith("A project estimate's identifier mismatches a the expected project's identifier.", actualException.Message);
        }
示例#11
0
        public void GIVEN_all_input_metrics_with_zero_throughput_AND_some_project_WHEN_estimating_time_to_completion_THEN_return_indeterminate_with_lower_bound_estimate()
        {
            var inputMetrics = ToInputMetrics(new[] { ToThroughput(0) });

            var estimator = new TimeTillCompletionEstimator(inputMetrics, randomNumberGeneratorMock.Object, someMaximumNumberOfIterations);

            var estimations = estimator.Estimate(someRoadmap);

            Assert.Equal(2, estimations.Count);

            WorkEstimate roadmapWorkEstimate = estimations[0];

            Assert.Equal("Roadmap", roadmapWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(someMaximumNumberOfIterations, roadmapWorkEstimate);
            AssertExpectedNumberOfWorkingDaysIsIndeterminate(roadmapWorkEstimate);

            WorkEstimate projectWorkEstimate = estimations[1];

            Assert.Equal("Project", projectWorkEstimate.Identifier);
            AssertExpectedNumberOfWorkingDaysIsEqual(someMaximumNumberOfIterations, projectWorkEstimate);
            AssertExpectedNumberOfWorkingDaysIsIndeterminate(projectWorkEstimate);
        }
示例#12
0
        public void GIVEN_multiple_input_metrics_AND_one_project_AND_truely_random_number_generator_WHEN_estimating_time_to_completion_THEN_return_number_of_work_days_in_range(
            IReadOnlyCollection <ThroughputPerDay> throughputs, Project project, double lowerBoundExpectedNumberOfDaysRequired, double upperBoundExpectedNumberOfDaysRequired)
        {
            var inputMetrics = ToInputMetrics(throughputs);
            var roadmap      = new Roadmap(new[] { project });

            var estimator = new TimeTillCompletionEstimator(inputMetrics, realRandomNumberGenerator, someMaximumNumberOfIterations);

            var estimations = estimator.Estimate(roadmap);

            Assert.Equal(2, estimations.Count);

            WorkEstimate roadmapWorkEstimate = estimations[0];

            Assert.Equal("Roadmap", roadmapWorkEstimate.Identifier);
            Assert.InRange(roadmapWorkEstimate.EstimatedNumberOfWorkingDaysRequired, lowerBoundExpectedNumberOfDaysRequired, upperBoundExpectedNumberOfDaysRequired);
            AssertEstimateIsDeterminate(roadmapWorkEstimate);

            WorkEstimate projectWorkEstimate = estimations[1];

            Assert.Equal("Project", projectWorkEstimate.Identifier);
            Assert.InRange(projectWorkEstimate.EstimatedNumberOfWorkingDaysRequired, lowerBoundExpectedNumberOfDaysRequired, upperBoundExpectedNumberOfDaysRequired);
            AssertEstimateIsDeterminate(projectWorkEstimate);
        }
 private static string FormatEstimatedNumberOfWorkingDays(
     WorkEstimate estimate,
     CultureInfo culture) =>
 estimate.EstimatedNumberOfWorkingDaysRequired.ToString(culture);