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