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.type : 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 alias TestMetaData = NamedType!(AbsolutePath, Tag!"TestMetaData", 67 AbsolutePath.init, TagStringable); 68 Optional!TestMetaData testMetadata; 69 } 70 71 /// Configuration data for the compile_commands.json 72 struct ConfigCompileDb { 73 import dextool.compilation_db : CompileCommandFilter; 74 75 /// Raw user input via either config or cli 76 string[] rawDbs; 77 78 /// path to compilation databases. 79 AbsolutePath[] dbs; 80 81 /// Flags the user wants to be automatically removed from the compile_commands.json. 82 CompileCommandFilter flagFilter; 83 } 84 85 /// Configuration of how the mutation analyzer should act. 86 struct ConfigAnalyze { 87 /// User input of excludes before they are adjusted to relative root 88 string[] rawExclude; 89 /// User input of includes before they are adjusted to relative root 90 string[] rawInclude; 91 92 /// The constructed glob filter which based on rawExclude and rawinclude. 93 GlobFilter fileMatcher; 94 95 /// The size of the thread pool which affects how many files are analyzed in parallel. 96 int poolSize; 97 98 /// What files to analyze is derived from a diff. 99 bool unifiedDiffFromStdin; 100 101 /// Remove files from the database that aren't found when analyzing. 102 bool prune; 103 104 /// Turn off the sqlite synchronization safety 105 bool fastDbStore; 106 107 /// If profiling data should be printed. 108 bool profile; 109 110 /// Force the result from the files to always be saved 111 bool forceSaveAnalyze; 112 113 /// User file/directories containing tests to checksum and timestamp 114 string[] rawTestPaths; 115 AbsolutePath[] testPaths; 116 117 /// User input of excludes before they are adjusted to relative root 118 string[] rawTestExclude; 119 /// User input of includes before they are adjusted to relative root 120 string[] rawTestInclude; 121 122 /// The constructed glob filter which based on rawExclude and rawinclude. 123 GlobFilter testFileMatcher; 124 } 125 126 /// Settings for the compiler 127 struct ConfigCompiler { 128 import dextool.compilation_db : SystemCompiler = Compiler; 129 130 /// Additional flags the user wants to add besides those that are in the compile_commands.json. 131 string[] extraFlags; 132 133 /// True requires system includes to be passed on to the compiler via -I 134 bool forceSystemIncludes; 135 136 /// Deduce compiler flags from this compiler and not the one in the 137 /// supplied compilation database. / This is needed when the one specified 138 /// in the DB has e.g. a c++ stdlib that is not compatible with clang. 139 SystemCompiler useCompilerSystemIncludes; 140 141 NamedType!(bool, Tag!"AllowErrors", bool.init, TagStringable) allowErrors; 142 } 143 144 /// Settings for mutation testing 145 struct ConfigMutationTest { 146 ShellCommand[] mutationTester; 147 /// Find executables in this directory and add them to mutationTester. 148 Path[] testCommandDir; 149 /// Flags to add to all executables found in `testCommandDir` 150 string[] testCommandDirFlag; 151 152 ShellCommand mutationCompile; 153 ShellCommand[] mutationTestCaseAnalyze; 154 TestCaseAnalyzeBuiltin[] mutationTestCaseBuiltin; 155 156 /// If the user hard code a timeout for the test suite. 157 Nullable!Duration mutationTesterRuntime; 158 159 /// Timeout to use when compiling. 160 Duration buildCmdTimeout = 30.dur!"minutes"; 161 162 /// In what order to choose mutants to test. 163 MutationOrder mutationOrder = MutationOrder.bySize; 164 bool dryRun; 165 166 /// How to behave when new test cases are detected. 167 enum NewTestCases { 168 doNothing, 169 /// Automatically reset alive mutants 170 resetAlive, 171 } 172 173 NewTestCases onNewTestCases; 174 175 /// How to behave when test cases are detected of having been removed 176 enum RemovedTestCases { 177 doNothing, 178 /// Remove it and all results connectedto the test case 179 remove, 180 } 181 182 RemovedTestCases onRemovedTestCases; 183 184 /// How to behave when mutants have aged. 185 enum OldMutant { 186 nothing, 187 test, 188 } 189 190 OldMutant onOldMutants; 191 long oldMutantsNr; 192 NamedType!(double, Tag!"OldMutantPercentage", double.init, TagStringable) oldMutantPercentage = 0.0; 193 194 /// Max time to run mutation testing. 195 // note that Duration.max + Clock.currTime results in a negative time... 196 Duration maxRuntime = 52.dur!"weeks"; 197 198 // Constrain the mutation testing. 199 TestConstraint constraint; 200 201 /// If constraints should be read from a unified diff via stdin. 202 bool unifiedDiffFromStdin; 203 204 /// Stop after this many alive mutants are found. Only effective if constraint.empty is false. 205 Nullable!int maxAlive; 206 207 /// The size of the thread pool which affects how many tests are executed in parallel. 208 int testPoolSize; 209 210 /// If early stopping of test command execution should be used 211 bool useEarlyTestCmdStop; 212 213 enum LoadBehavior { 214 nothing, 215 /// Slow the testing until the load goes below the threshold 216 slowdown, 217 /// Stop mutation testing if the 15min load average reach this number. 218 halt, 219 } 220 221 LoadBehavior loadBehavior; 222 NamedType!(double, Tag!"LoadThreshold", double.init, TagStringable) loadThreshold; 223 224 /// Continuesly run the test suite to see that the test suite is OK when no mutants are injected. 225 NamedType!(bool, Tag!"ContinuesCheckTestSuite", bool.init, TagStringable) contCheckTestSuite; 226 NamedType!(int, Tag!"ContinuesCheckTestSuitePeriod", int.init, TagStringable) contCheckTestSuitePeriod = 100; 227 228 NamedType!(bool, Tag!"TestCmdChecksum", bool.init, TagStringable) testCmdChecksum; 229 230 NamedType!(long, Tag!"MaxTestCaseOutputCaptureMbyte", int.init, TagStringable) maxTestCaseOutput = 10; 231 232 NamedType!(bool, Tag!"UseSkipMutant", bool.init, TagStringable) useSkipMutant; 233 234 NamedType!(double, Tag!"MaxMemoryUsage", double.init, TagStringable) maxMemUsage = 90.0; 235 } 236 237 /// Settings for the administration mode 238 struct ConfigAdmin { 239 AdminOperation adminOp; 240 Mutation.Status mutantStatus; 241 Mutation.Status mutantToStatus; 242 string testCaseRegex; 243 long mutationId; 244 string mutantRationale; 245 246 /// used to specify a kind of mutation 247 Mutation.Kind[] subKind; 248 } 249 250 struct ConfigWorkArea { 251 /// User input root. 252 string rawRoot; 253 254 AbsolutePath root; 255 256 /// User input of excludes before they are adjusted to relative root 257 string[] rawExclude; 258 /// User input of includes before they are adjusted to relative root 259 string[] rawInclude; 260 261 /// The constructed glob filter which based on rawExclude and rawinclude. 262 /// Only mutants whose location match will be generated. 263 GlobFilter mutantMatcher; 264 } 265 266 /// Configuration of the generate mode. 267 struct ConfigGenerate { 268 long mutationId; 269 } 270 271 struct ConfigSchema { 272 bool use; 273 274 SchemaRuntime runtime; 275 276 /// Number of mutants to at most put in a schema (soft limit) 277 NamedType!(long, Tag!"MutantsPerSchema", long.init, TagStringable) mutantsPerSchema = 1000; 278 279 /// Minimum number of mutants per schema for the schema to be saved in the database. 280 NamedType!(long, Tag!"MinMutantsPerSchema", long.init, TagStringable) minMutantsPerSchema = 3; 281 282 /// Sanity check a schemata before it is used. 283 bool sanityCheckSchemata; 284 285 /// If the schematas should be written to a separate file for offline inspection. 286 /// Write the instrumented source code to .cov.<ext> for separate inspection. 287 bool log; 288 289 /// Stop mutation testing after the last schemata has been executed 290 bool stopAfterLastSchema; 291 292 /// allows a user to control exactly which files the coverage and schemata 293 /// runtime is injected in. 294 UserRuntime[] userRuntimeCtrl; 295 296 /// Only compile and execute the test suite. Used to train the schema generator. 297 NamedType!(bool, Tag!"SchemaTrainGenerator", bool.init, TagStringable) onlyCompile; 298 } 299 300 struct ConfigCoverage { 301 bool use; 302 303 CoverageRuntime runtime; 304 305 /// If the generated coverage files should be saved. 306 bool log; 307 308 /// allows a user to control exactly which files the coverage and schemata 309 /// runtime is injected in. 310 UserRuntime[] userRuntimeCtrl; 311 }