1 /** 2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.config; 11 12 import core.time : Duration, dur; 13 import std.typecons : Nullable; 14 15 import my.filter : GlobFilter; 16 import my.named_type; 17 import my.optional; 18 19 import dextool.plugin.mutate.type; 20 import dextool.type : AbsolutePath, Path; 21 public import dextool.plugin.mutate.backend : Mutation, TestGroup; 22 23 /// The mode the tool is operating in 24 enum ToolMode { 25 /// No mode set 26 none, 27 /// analyze for mutation points 28 analyzer, 29 /// center that can operate and control subcomponents 30 generate_mutant, 31 /// test mutation points with a test suite 32 test_mutants, 33 /// generate a report of the mutation points 34 report, 35 /// administrator interface for the mutation database 36 admin, 37 /// Dump the TOML configuration to the console 38 dumpConfig, 39 /// Write a TOML config to the filesystem 40 initConfig, 41 } 42 43 /// Config of the report. 44 struct ConfigReport { 45 ReportKind reportKind; 46 ReportSection[] reportSection = [ReportSection.summary]; 47 48 /// Directory to write logs to when writing to the filesystem. 49 AbsolutePath logDir; 50 51 /// Controls how to sort test cases by their kill statistics. 52 ReportKillSortOrder tcKillSortOrder; 53 int tcKillSortNum = 20; 54 55 /// User regex for reporting groups of tests 56 TestGroup[] testGroups; 57 58 /// If a unified diff should be used in the report 59 bool unifiedDiff; 60 61 /// If profiling data should be printed. 62 bool profile; 63 64 NamedType!(uint, Tag!"HighInterestMutantsNr", uint.init, TagStringable) highInterestMutantsNr = 5; 65 } 66 67 /// Configuration data for the compile_commands.json 68 struct ConfigCompileDb { 69 import dextool.compilation_db : CompileCommandFilter; 70 71 /// Raw user input via either config or cli 72 string[] rawDbs; 73 74 /// path to compilation databases. 75 AbsolutePath[] dbs; 76 77 /// Flags the user wants to be automatically removed from the compile_commands.json. 78 CompileCommandFilter flagFilter; 79 } 80 81 /// Configuration of how the mutation analyzer should act. 82 struct ConfigAnalyze { 83 /// User input of excludes before they are adjusted to relative root 84 string[] rawExclude; 85 /// User input of includes before they are adjusted to relative root 86 string[] rawInclude; 87 88 /// The constructed glob filter which based on rawExclude and rawinclude. 89 GlobFilter fileMatcher; 90 91 /// The size of the thread pool which affects how many files are analyzed in parallel. 92 int poolSize; 93 94 /// What files to analyze is derived from a diff. 95 bool unifiedDiffFromStdin; 96 97 /// Remove files from the database that aren't found when analyzing. 98 bool prune; 99 100 /// Turn off the sqlite synchronization safety 101 bool fastDbStore; 102 103 /// If profiling data should be printed. 104 bool profile; 105 106 /// Force the result from the files to always be saved 107 bool forceSaveAnalyze; 108 109 /// Number of mutants to at most put in a schema (soft limit) 110 NamedType!(long, Tag!"MutantsPerSchema", long.init, TagStringable) mutantsPerSchema = 1000; 111 112 /// Minimum number of mutants per schema for the schema to be saved in the database. 113 NamedType!(long, Tag!"MinMutantsPerSchema", long.init, TagStringable) minMutantsPerSchema = 3; 114 115 /// User file/directories containing tests to checksum and timestamp 116 string[] rawTestPaths; 117 AbsolutePath[] testPaths; 118 119 /// User input of excludes before they are adjusted to relative root 120 string[] rawTestExclude; 121 /// User input of includes before they are adjusted to relative root 122 string[] rawTestInclude; 123 124 /// The constructed glob filter which based on rawExclude and rawinclude. 125 GlobFilter testFileMatcher; 126 127 /// If coverage maps should be generated and saved. 128 NamedType!(bool, Tag!"SaveCoverage", bool.init, TagStringable) saveCoverage; 129 } 130 131 /// Settings for the compiler 132 struct ConfigCompiler { 133 import dextool.compilation_db : SystemCompiler = Compiler; 134 135 /// Additional flags the user wants to add besides those that are in the compile_commands.json. 136 string[] extraFlags; 137 138 /// True requires system includes to be passed on to the compiler via -I 139 bool forceSystemIncludes; 140 141 /// Deduce compiler flags from this compiler and not the one in the 142 /// supplied compilation database. / This is needed when the one specified 143 /// in the DB has e.g. a c++ stdlib that is not compatible with clang. 144 SystemCompiler useCompilerSystemIncludes; 145 146 NamedType!(bool, Tag!"AllowErrors", bool.init, TagStringable) allowErrors; 147 } 148 149 /// Settings for mutation testing 150 struct ConfigMutationTest { 151 ShellCommand[] mutationTester; 152 /// Find executables in this directory and add them to mutationTester. 153 Path[] testCommandDir; 154 /// Flags to add to all executables found in `testCommandDir` 155 string[] testCommandDirFlag; 156 157 ShellCommand mutationCompile; 158 ShellCommand[] mutationTestCaseAnalyze; 159 TestCaseAnalyzeBuiltin[] mutationTestCaseBuiltin; 160 161 /// If the user hard code a timeout for the test suite. 162 Nullable!Duration mutationTesterRuntime; 163 164 /// Timeout to use when compiling. 165 Duration buildCmdTimeout = 30.dur!"minutes"; 166 167 /// In what order to choose mutants to test. 168 MutationOrder mutationOrder; 169 bool dryRun; 170 171 /// How to behave when new test cases are detected. 172 enum NewTestCases { 173 doNothing, 174 /// Automatically reset alive mutants 175 resetAlive, 176 } 177 178 NewTestCases onNewTestCases; 179 180 /// How to behave when test cases are detected of having been removed 181 enum RemovedTestCases { 182 doNothing, 183 /// Remove it and all results connectedto the test case 184 remove, 185 } 186 187 RemovedTestCases onRemovedTestCases; 188 189 /// How to behave when mutants have aged. 190 enum OldMutant { 191 nothing, 192 test, 193 } 194 195 OldMutant onOldMutants; 196 long oldMutantsNr; 197 NamedType!(double, Tag!"OldMutantPercentage", double.init, TagStringable) oldMutantPercentage = 0.0; 198 199 /// Max time to run mutation testing. 200 // note that Duration.max + Clock.currTime results in a negative time... 201 Duration maxRuntime = 52.dur!"weeks"; 202 203 // Constrain the mutation testing. 204 TestConstraint constraint; 205 206 /// If constraints should be read from a unified diff via stdin. 207 bool unifiedDiffFromStdin; 208 209 /// Stop after this many alive mutants are found. Only effective if constraint.empty is false. 210 Nullable!int maxAlive; 211 212 /// The size of the thread pool which affects how many tests are executed in parallel. 213 int testPoolSize; 214 215 /// Seed used when randomly choosing mutants to test in a pull request. 216 long pullRequestSeed = 42; 217 218 /// If early stopping of test command execution should be used 219 bool useEarlyTestCmdStop; 220 221 /// If schematas are used for mutation testing. 222 bool useSchemata; 223 224 /// Sanity check a schemata before it is used. 225 bool sanityCheckSchemata; 226 227 /// If the schematas should be written to a separate file for offline inspection. 228 bool logSchemata; 229 230 /// Stop mutation testing after the last schemata has been executed 231 bool stopAfterLastSchema; 232 233 /// Minimum number of mutants per schema for it to be used. 234 NamedType!(long, Tag!"MinMutantsPerSchema", long.init, TagStringable) minMutantsPerSchema = 3; 235 236 enum LoadBehavior { 237 nothing, 238 /// Slow the testing until the load goes below the threshold 239 slowdown, 240 /// Stop mutation testing if the 15min load average reach this number. 241 halt, 242 } 243 244 LoadBehavior loadBehavior; 245 NamedType!(double, Tag!"LoadThreshold", double.init, TagStringable) loadThreshold; 246 247 /// If coverage data should be gathered and saved. 248 NamedType!(bool, Tag!"UseCoverage", bool.init, TagStringable) useCoverage; 249 250 /// If the generated coverage files should be saved. 251 NamedType!(bool, Tag!"LogCoverage", bool.init, TagStringable) logCoverage; 252 253 /// allows a user to control exactly which files the coverage and schemata runtime is injected in. 254 UserRuntime[] userRuntimeCtrl; 255 256 /// Continuesly run the test suite to see that the test suite is OK when no mutants are injected. 257 NamedType!(bool, Tag!"ContinuesCheckTestSuite", bool.init, TagStringable) contCheckTestSuite; 258 NamedType!(int, Tag!"ContinuesCheckTestSuitePeriod", int.init, TagStringable) contCheckTestSuitePeriod = 100; 259 } 260 261 /// Settings for the administration mode 262 struct ConfigAdmin { 263 AdminOperation adminOp; 264 Mutation.Status mutantStatus; 265 Mutation.Status mutantToStatus; 266 string testCaseRegex; 267 long mutationId; 268 string mutantRationale; 269 270 /// used to specify a kind of mutation 271 Mutation.Kind[] subKind; 272 } 273 274 struct ConfigWorkArea { 275 /// User input root. 276 string rawRoot; 277 278 AbsolutePath root; 279 280 /// User input of excludes before they are adjusted to relative root 281 string[] rawExclude; 282 /// User input of includes before they are adjusted to relative root 283 string[] rawInclude; 284 285 /// The constructed glob filter which based on rawExclude and rawinclude. 286 /// Only mutants whose location match will be generated. 287 GlobFilter mutantMatcher; 288 } 289 290 /// Configuration of the generate mode. 291 struct ConfigGenerate { 292 long mutationId; 293 }