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.backend.database.type;
11 
12 import core.time : Duration;
13 import std.datetime : SysTime;
14 
15 import my.named_type;
16 import my.hash : Checksum64;
17 import sumtype;
18 
19 import dextool.type : AbsolutePath, Path;
20 import dextool.plugin.mutate.backend.type;
21 
22 public import dextool.plugin.mutate.backend.database.schema : MutantTimeoutCtxTbl;
23 public import dextool.plugin.mutate.backend.type : MutantTimeProfile;
24 
25 @safe:
26 
27 /// The context (state) of how the testing of the timeout mutants are going.
28 alias MutantTimeoutCtx = MutantTimeoutCtxTbl;
29 
30 /// Primary key in the mutation table
31 alias MutationId = NamedType!(long, Tag!"MutationId", 0, Comparable, Hashable, ConvertStringable);
32 
33 /// Primary key for mutation status
34 alias MutationStatusId = NamedType!(long, Tag!"MutationStatusId", long.init,
35         Comparable, Hashable, ConvertStringable);
36 
37 /// Primary key in the files table
38 alias FileId = NamedType!(long, Tag!"FileId", long.init, Comparable, Hashable, TagStringable);
39 
40 /// Primary key in the test files table
41 alias TestFileId = NamedType!(long, Tag!"TestFileId", long.init, Comparable,
42         Hashable, TagStringable);
43 
44 /// Primary key in the test_case table
45 alias TestCaseId = NamedType!(long, Tag!"TestCaseId", long.init, Comparable,
46         Hashable, TagStringable);
47 
48 /// Primary key for mutation schematas.
49 alias SchemataId = NamedType!(long, Tag!"SchemataId", long.init, Comparable,
50         Hashable, TagStringable);
51 
52 /// Primary key for a schemata fragment.
53 alias SchemataFragmentId = NamedType!(long, Tag!"SchemataFragmentId",
54         long.init, Comparable, Hashable, TagStringable);
55 
56 Checksum toChecksum(const MutationStatusId id) {
57     return Checksum(id.get);
58 }
59 
60 MutationStatusId toMutationStatusId(const Checksum cs) {
61     return MutationStatusId(cs.c0);
62 }
63 
64 MutationStatusId toMutationStatusId(const CodeMutant m) {
65     return MutationStatusId(m.id.value.c0);
66 }
67 
68 struct MutationEntry {
69     MutationStatusId id;
70     Path file;
71     SourceLoc sloc;
72     MutationPoint mp;
73     MutantTimeProfile profile;
74     Language lang;
75 }
76 
77 struct NextMutationEntry {
78     import std.typecons : Nullable;
79 
80     enum Status {
81         /// Mutant retrieved.
82         ok,
83         /// All mutants tested.
84         done,
85     }
86 
87     Status st;
88     Nullable!MutationEntry entry;
89 }
90 
91 struct MutationPointEntry {
92     MutationPoint mp;
93     Path file;
94     /// Start of the mutation point.
95     SourceLoc sloc;
96     /// End of the mutation point.
97     SourceLoc slocEnd;
98 }
99 
100 /// The source code mutations for a mutation point.
101 struct MutationPointEntry2 {
102     Path file;
103     Offset offset;
104     /// Start of the mutation point.
105     SourceLoc sloc;
106     /// End of the mutation point.
107     SourceLoc slocEnd;
108     CodeMutant cm;
109 
110     void set(CodeMutant m) @safe pure nothrow {
111         cm = m;
112     }
113 }
114 
115 /// Report about mutants of a specific kind(s).
116 struct MutationReportEntry {
117     ///
118     long count;
119 
120     /// Test time spent on the mutants.
121     MutantTimeProfile time;
122 }
123 
124 /// Mutants that are tagged with nomut of a specific kind(s).
125 struct MetadataNoMutEntry {
126     ///
127     long count;
128 }
129 
130 struct MutantInfo {
131     MutationStatusId id;
132     Mutation.Status status;
133     ExitStatus ecode;
134     Mutation.Kind kind;
135     SourceLoc sloc;
136     MutationStatusId stId;
137 }
138 
139 struct MutantInfo2 {
140     MutationStatusId id;
141     Mutation.Status status;
142     ExitStatus exitStatus;
143     Path file;
144     SourceLoc sloc;
145     MutantPrio prio;
146     SysTime updated;
147 
148     // number of test cases that killed the mutant
149     int tcKilled;
150 }
151 
152 struct TestCaseInfo {
153     /// The sum on the execution time of killing the mutants.
154     MutantTimeProfile time;
155 
156     ///
157     long killedMutants;
158 }
159 
160 /// What mutants a test case killed.
161 struct TestCaseInfo2 {
162     TestCase name;
163     MutationStatusId[] killed;
164 }
165 
166 struct MutationStatusTime {
167     import std.datetime : SysTime;
168 
169     MutationStatusId id;
170     SysTime updated;
171 }
172 
173 struct MutantTestTime {
174     MutationStatusId id;
175     Mutation.Status status;
176     Duration compileTime;
177     Duration testTime;
178 }
179 
180 alias MutantPrio = NamedType!(long, Tag!"MutantPriority", long.init, TagStringable);
181 
182 struct MutationStatus {
183     import std.datetime : SysTime;
184     import std.typecons : Nullable;
185 
186     MutationStatusId statusId;
187     Mutation.Status status;
188     MutantPrio prio;
189     SysTime updated;
190     Nullable!SysTime added;
191     ExitStatus exitStatus;
192 }
193 
194 /// Metadata about a line in a file.
195 struct LineMetadata {
196     FileId id;
197     uint line;
198     LineAttr attr;
199 
200     this(FileId fid, uint line) {
201         this(fid, line, LineAttr.init);
202     }
203 
204     this(FileId fid, uint line, LineAttr attr) {
205         this.id = fid;
206         this.line = line;
207         this.attr = attr;
208     }
209 
210     void opAssign(LineMetadata rhs) @trusted pure nothrow @nogc {
211         this.id = rhs.id;
212         this.line = rhs.line;
213         this.attr = rhs.attr;
214     }
215 
216     void set(NoMut a) @trusted pure nothrow @nogc {
217         attr = LineAttr(a);
218     }
219 
220     bool isNoMut() @safe pure nothrow const @nogc {
221         return attr.match!((NoMetadata a) => false, (NoMut a) => true);
222     }
223 }
224 
225 struct NoMetadata {
226 }
227 
228 /// A mutation suppression with optional tag and comment.
229 struct NoMut {
230     string tag;
231     string comment;
232 }
233 
234 /// Metadata attributes that may be attached to a mutant.
235 alias MutantAttr = SumType!(NoMetadata, NoMut);
236 
237 /// Metadata attributes that may be attached to a line.
238 alias LineAttr = SumType!(NoMetadata, NoMut);
239 
240 /// Metadata about a mutant.
241 struct MutantMetaData {
242     import std.range : isOutputRange;
243 
244     MutationStatusId id;
245     MutantAttr attr;
246 
247     this(MutationStatusId id) {
248         this(id, MutantAttr.init);
249     }
250 
251     this(MutationStatusId id, MutantAttr attr) {
252         this.id = id;
253         this.attr = attr;
254     }
255 
256     void set(NoMut a) @trusted pure nothrow @nogc {
257         attr = MutantAttr(a);
258     }
259 
260     bool isNoMut() @safe pure nothrow const @nogc {
261         return attr.match!((NoMetadata a) => false, (NoMut a) => true);
262     }
263 
264     string kindToString() @safe pure const {
265         import std.array : appender;
266         import std.format : FormatSpec;
267 
268         auto buf = appender!string;
269         kindToString(buf);
270         return buf.data;
271     }
272 
273     void kindToString(Writer)(ref Writer w) const if (isOutputRange!(Writer, char)) {
274         import std.range : put;
275 
276         attr.match!((NoMetadata a) {}, (NoMut a) => put(w, "nomut"));
277     }
278 
279     import std.range : isOutputRange;
280 
281     string toString() @safe pure const {
282         import std.array : appender;
283 
284         auto buf = appender!string;
285         toString(buf);
286         return buf.data;
287     }
288 
289     void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, char)) {
290         kindToString(w);
291     }
292 }
293 
294 alias Rationale = NamedType!(string, Tag!"Rationale", string.init, TagStringable);
295 
296 struct MarkedMutant {
297     MutationStatusId statusId;
298 
299     /// Checksum of the marked mutant.
300     Checksum statusChecksum;
301 
302     SourceLoc sloc;
303     Path path;
304 
305     /// The status it should always be changed to.
306     Mutation.Status toStatus;
307 
308     /// Time when the mutant where marked.
309     SysTime time;
310 
311     Rationale rationale;
312 
313     string mutText;
314 }
315 
316 /// A fragment of a schemata which is one application.
317 struct SchemataFragment {
318     Path file;
319     Offset offset;
320     const(ubyte)[] text;
321 }
322 
323 struct SchemaFragmentV2 {
324     Offset offset;
325     const(ubyte)[] text;
326     MutationStatusId[] mutants;
327 }
328 
329 struct Schemata {
330     SchemataId id;
331 
332     /// Sorted in the order they should be applied.
333     SchemataFragment[] fragments;
334 }
335 
336 struct TestCmdRuntime {
337     SysTime timeStamp;
338 
339     /// The execution time of the test suite.
340     Duration runtime;
341 }
342 
343 struct MutationScore {
344     SysTime timeStamp;
345     NamedType!(double, Tag!"MutationScore", 0.0, TagStringable) score;
346 }
347 
348 struct FileScore {
349     SysTime timeStamp;
350     NamedType!(double, Tag!"MutationFileScore", 0.0, TagStringable) score;
351     Path file;
352 }
353 
354 alias TestFilePath = NamedType!(Path, Tag!"TestFilePath", Path.init, Hashable, TagStringable);
355 alias TestFileChecksum = NamedType!(Checksum, Tag!"TestFileChecksum",
356         Checksum.init, TagStringable, Hashable);
357 
358 struct TestFile {
359     TestFilePath file;
360 
361     /// Checksum of the content.
362     TestFileChecksum checksum;
363 
364     /// Last time the file was changed.
365     SysTime timeStamp;
366 }
367 
368 alias CoverageRegionId = NamedType!(long, Tag!"CoverageRegionId", long.init,
369         Comparable, Hashable, ConvertStringable);
370 struct CovRegion {
371     CoverageRegionId id;
372     Offset region;
373 }
374 
375 struct CovRegionStatus {
376     bool status;
377     Offset region;
378 }
379 
380 /// A file that a root is dependent on.
381 struct DepFile {
382     Path file;
383     Checksum checksum;
384 }
385 
386 alias ToolVersion = NamedType!(long, Tag!"ToolVersion", long.init, TagStringable, Comparable);
387 
388 alias ChecksumTestCmdOriginal = NamedType!(Checksum64,
389         Tag!"ChecksumTestCmdOriginal", Checksum64.init, TagStringable);
390 
391 alias ChecksumTestCmdMutated = NamedType!(Checksum64,
392         Tag!"ChecksumTestCmdMutated", Checksum64.init, TagStringable);
393 
394 struct WorklistItem {
395     MutationStatusId id;
396     MutantPrio prio;
397 }