private void HandleStrykerRunResult(IStrykerInputs inputs, StrykerRunResult result) { var logger = ApplicationLogging.LoggerFactory.CreateLogger <StrykerCli>(); if (double.IsNaN(result.MutationScore)) { logger.LogInformation("Stryker was unable to calculate a mutation score"); } else { logger.LogInformation("The final mutation score is {MutationScore:P2}", result.MutationScore); } if (result.ScoreIsLowerThanThresholdBreak()) { var thresholdBreak = (double)inputs.ValidateAll().Thresholds.Break / 100; logger.LogWarning("Final mutation score is below threshold break. Crashing..."); _console.WriteLine(); _console.MarkupLine($"[Red]The mutation score is lower than the configured break threshold of {thresholdBreak:P0}.[/]"); _console.MarkupLine(" [Red]Looks like you've got some work to do :smiling_face_with_halo:[/]"); ExitCode = ExitCodes.BreakThresholdViolated; } }
/// <summary> /// Creates the needed paths for logging and initializes the logger factory /// </summary> /// <param name="fileSystem">Mock filesystem</param> public void SetupLogOptions(IStrykerInputs inputs, IFileSystem fileSystem = null) { fileSystem ??= new FileSystem(); var basePath = inputs.BasePathInput.SuppliedInput; var outputPath = CreateOutputPath(basePath, fileSystem); inputs.OutputPathInput.SuppliedInput = outputPath; var logLevel = inputs.VerbosityInput.Validate(); var logToFile = inputs.LogToFileInput.Validate(outputPath); ApplicationLogging.ConfigureLogger(logLevel, logToFile, outputPath); }
public static void DeserializeConfig(string configFilePath, IStrykerInputs inputs) { var jsonConfig = LoadJsonConfig(configFilePath); // As json values are first in line we can just overwrite all supplied inputs inputs.ConcurrencyInput.SuppliedInput = jsonConfig.Concurrency; inputs.SinceInput.SuppliedInput = jsonConfig.Since is not null && (jsonConfig.Since.Enabled.HasValue && jsonConfig.Since.Enabled.Value); inputs.WithBaselineInput.SuppliedInput = jsonConfig.Baseline is not null && (jsonConfig.Baseline.Enabled.HasValue && jsonConfig.Baseline.Enabled.Value); inputs.BaselineProviderInput.SuppliedInput = jsonConfig.Baseline?.Provider; inputs.DiffIgnoreChangesInput.SuppliedInput = jsonConfig.Since?.IgnoreChangesIn; inputs.FallbackVersionInput.SuppliedInput = jsonConfig.Baseline?.FallbackVersion; inputs.AzureFileStorageUrlInput.SuppliedInput = jsonConfig.Baseline?.AzureFileShareUrl; inputs.CoverageAnalysisInput.SuppliedInput = jsonConfig.CoverageAnalysis; inputs.DisableBailInput.SuppliedInput = jsonConfig.DisableBail; inputs.DisableMixMutantsInput.SuppliedInput = jsonConfig.DisableMixMutants; inputs.AdditionalTimeoutInput.SuppliedInput = jsonConfig.AdditionalTimeout; inputs.MutateInput.SuppliedInput = jsonConfig.Mutate; inputs.MutationLevelInput.SuppliedInput = jsonConfig.MutationLevel; inputs.ProjectNameInput.SuppliedInput = jsonConfig.ProjectInfo?.Name; inputs.ModuleNameInput.SuppliedInput = jsonConfig.ProjectInfo?.Module; inputs.ProjectVersionInput.SuppliedInput = jsonConfig.ProjectInfo?.Version; inputs.ReportersInput.SuppliedInput = jsonConfig.Reporters; inputs.SinceTargetInput.SuppliedInput = jsonConfig.Since?.Target; inputs.SolutionInput.SuppliedInput = jsonConfig.Solution; inputs.TargetFrameworkInput.SuppliedInput = jsonConfig.TargetFramework; inputs.ProjectUnderTestNameInput.SuppliedInput = jsonConfig.Project; inputs.ThresholdBreakInput.SuppliedInput = jsonConfig.Thresholds?.Break; inputs.ThresholdHighInput.SuppliedInput = jsonConfig.Thresholds?.High; inputs.ThresholdLowInput.SuppliedInput = jsonConfig.Thresholds?.Low; inputs.VerbosityInput.SuppliedInput = jsonConfig.Verbosity; inputs.LanguageVersionInput.SuppliedInput = jsonConfig.LanguageVersion; inputs.TestProjectsInput.SuppliedInput = jsonConfig.TestProjects; inputs.TestCaseFilterInput.SuppliedInput = jsonConfig.TestCaseFilter; inputs.DashboardUrlInput.SuppliedInput = jsonConfig.DashboardUrl; inputs.IgnoreMutationsInput.SuppliedInput = jsonConfig.IgnoreMutations; inputs.IgnoredMethodsInput.SuppliedInput = jsonConfig.IgnoreMethods; inputs.ReportFileNameInput.SuppliedInput = jsonConfig.ReportFileName; }
/// <summary> /// Reads all config from json and console to fill stryker inputs /// </summary> /// <param name="args">Console app arguments</param> /// <param name="app">The console application containing all argument information</param> /// <param name="cmdConfigHandler">Mock console config handler</param> /// <returns>Filled stryker inputs (except output path)</returns> public void Build(IStrykerInputs inputs, string[] args, CommandLineApplication app, CommandLineConfigHandler cmdConfigHandler) { // set basepath var basePath = Directory.GetCurrentDirectory(); inputs.BasePathInput.SuppliedInput = basePath; // read config from json and commandline var configFilePath = Path.Combine(basePath, cmdConfigHandler.GetConfigFilePath(args, app)); if (File.Exists(configFilePath)) { JsonConfigHandler.DeserializeConfig(configFilePath, inputs); } cmdConfigHandler.ReadCommandLineConfig(args, app, inputs); }
public void WithConfigFile_ShouldStartStrykerWithConfigFileOptions(string argName) { IStrykerInputs actualInputs = null; var options = new StrykerOptions() { Thresholds = new Thresholds() { High = 80, Low = 60, Break = 0 } }; var runResults = new StrykerRunResult(options, 0.3); var mock = new Mock <IStrykerRunner>(MockBehavior.Strict); mock.Setup(x => x.RunMutationTest(It.IsAny <IStrykerInputs>(), It.IsAny <ILoggerFactory>(), It.IsAny <IProjectOrchestrator>())) .Callback <IStrykerInputs, ILoggerFactory, IProjectOrchestrator>((c, l, p) => actualInputs = c) .Returns(runResults) .Verifiable(); var target = new StrykerCli(mock.Object); target.Run(new string[] { argName, "filled-stryker-config.json" }); mock.VerifyAll(); actualInputs.AdditionalTimeoutInput.SuppliedInput.ShouldBe(9999); actualInputs.VerbosityInput.SuppliedInput.ShouldBe("trace"); actualInputs.ProjectUnderTestNameInput.SuppliedInput.ShouldBe("ExampleProject.csproj"); actualInputs.ReportersInput.SuppliedInput.ShouldHaveSingleItem(); actualInputs.ReportersInput.SuppliedInput.ShouldContain(Reporter.Json.ToString()); actualInputs.ConcurrencyInput.SuppliedInput.ShouldBe(1); actualInputs.ThresholdBreakInput.SuppliedInput.ShouldBe(20); actualInputs.ThresholdLowInput.SuppliedInput.ShouldBe(30); actualInputs.ThresholdHighInput.SuppliedInput.ShouldBe(40); actualInputs.MutateInput.SuppliedInput.ShouldHaveSingleItem(); actualInputs.MutateInput.SuppliedInput.ShouldContain("!**/Test.cs{1..100}{200..300}"); actualInputs.CoverageAnalysisInput.SuppliedInput.ShouldBe("perTest"); actualInputs.DisableBailInput.SuppliedInput.ShouldBe(true); actualInputs.IgnoreMutationsInput.SuppliedInput.ShouldContain("linq.FirstOrDefault"); actualInputs.IgnoredMethodsInput.SuppliedInput.ShouldContain("Log*"); actualInputs.TestCaseFilterInput.SuppliedInput.ShouldBe("(FullyQualifiedName~UnitTest1&TestCategory=CategoryA)|Priority=1"); actualInputs.DashboardUrlInput.SuppliedInput.ShouldBe("https://alternative-stryker-dashboard.io"); }
private void RunStryker(IStrykerInputs inputs) { var result = _stryker.RunMutationTest(inputs, ApplicationLogging.LoggerFactory); HandleStrykerRunResult(inputs, result); }
/// <summary> /// Starts a mutation test run /// </summary> /// <param name="options">The user options</param> /// <param name="loggerFactory">This loggerfactory will be used to create loggers during the stryker run</param> /// <exception cref="InputException">For managed exceptions</exception> public StrykerRunResult RunMutationTest(IStrykerInputs inputs, ILoggerFactory loggerFactory, IProjectOrchestrator projectOrchestrator = null) { var stopwatch = new Stopwatch(); stopwatch.Start(); SetupLogging(loggerFactory); // Setup project orchestrator can't be done sooner since it needs logging projectOrchestrator ??= new ProjectOrchestrator(); var options = inputs.ValidateAll(); _logger.LogDebug("Stryker started with options: {@Options}", options); var reporters = _reporterFactory.Create(options); try { // Mutate _mutationTestProcesses = projectOrchestrator.MutateProjects(options, reporters).ToList(); IReadOnlyProjectComponent rootComponent = AddRootFolderIfMultiProject(_mutationTestProcesses.Select(x => x.Input.ProjectInfo.ProjectContents).ToList(), options); _logger.LogInformation("{0} mutants created", rootComponent.Mutants.Count()); AnalyseCoverage(options); // Filter foreach (var project in _mutationTestProcesses) { project.FilterMutants(); } // Report reporters.OnMutantsCreated(rootComponent); var allMutants = rootComponent.Mutants; var mutantsNotRun = rootComponent.NotRunMutants().ToList(); if (!mutantsNotRun.Any()) { if (allMutants.Any(x => x.ResultStatus == MutantStatus.Ignored)) { _logger.LogWarning("It looks like all mutants with tests were ignored. Try a re-run with less ignoring!"); } if (allMutants.Any(x => x.ResultStatus == MutantStatus.NoCoverage)) { _logger.LogWarning("It looks like all non-ignored mutants are not covered by a test. Go add some tests!"); } if (allMutants.Any(x => x.ResultStatus == MutantStatus.CompileError)) { _logger.LogWarning("It looks like all mutants resulted in compile errors. Mutants sure are strange!"); } if (!allMutants.Any()) { _logger.LogWarning("It\'s a mutant-free world, nothing to test."); } reporters.OnAllMutantsTested(rootComponent); return(new StrykerRunResult(options, rootComponent.GetMutationScore())); } // Report reporters.OnStartMutantTestRun(mutantsNotRun); // Test foreach (var project in _mutationTestProcesses) { project.Test(project.Input.ProjectInfo.ProjectContents.Mutants.Where(x => x.ResultStatus == MutantStatus.NotRun).ToList()); project.Restore(); } reporters.OnAllMutantsTested(rootComponent); return(new StrykerRunResult(options, rootComponent.GetMutationScore())); } #if !DEBUG catch (Exception ex) when(!(ex is InputException)) // let the exception be caught by the debugger when in debug { _logger.LogError(ex, "An error occurred during the mutation test run "); throw; } #endif finally { // log duration stopwatch.Stop(); _logger.LogInformation("Time Elapsed {0}", stopwatch.Elapsed); } }