/// <summary> /// Executes the mutation test session for the given test project. /// Algorithm: /// 1. Build project /// 2. Calculate for each test which mutations they cover. /// 3. Rebuild to remove injected code. /// 4. Run test session. /// 4a. Generate optimized test runs. /// 5. Build report. /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task <TestProjectReportModel> Test(MutationSessionProgressTracker progressTracker, CancellationToken cancellationToken = default) { // Build project progressTracker.LogBeginPreBuilding(); var projectInfo = await BuildProject(progressTracker, _testProjectPath); progressTracker.LogEndPreBuilding(); // Copy project N times progressTracker.LogBeginProjectDuplication(_parallel); var testProjectCopier = new TestProjectDuplicator(Directory.GetParent(projectInfo.AssemblyPath).FullName); var duplications = testProjectCopier.MakeInitialCopies(projectInfo, _parallel); // Begin code coverage on first project. var duplicationPool = new TestProjectDuplicationPool(duplications); var coverageProject = duplicationPool.TakeTestProject(); var coverageProjectInfo = GetTestProjectInfo(coverageProject, projectInfo); // Measure the test coverage progressTracker.LogBeginCoverage(); PrepareAssembliesForCodeCoverage(coverageProjectInfo); var coverageTimer = new Stopwatch(); coverageTimer.Start(); var coverage = await RunCoverage(coverageProject.TestProjectFile.FullFilePath(), cancellationToken); coverageTimer.Stop(); var timeout = _createTimeOut(coverageTimer); GC.Collect(); GC.WaitForPendingFinalizers(); coverageProject.MarkAsFree(); // Start test session. var testsPerMutation = GroupMutationsWithTests(coverage); return(StartMutationTestSession(coverageProjectInfo, testsPerMutation, progressTracker, timeout, duplicationPool)); }