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