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 alias MutantPrio = NamedType!(long, Tag!"MutantPriority", long.init, TagStringable);
161 
162 struct MutationStatus {
163     import std.datetime : SysTime;
164     import std.typecons : Nullable;
165 
166     MutationStatusId statusId;
167     Mutation.Status status;
168     MutantPrio prio;
169     SysTime updated;
170     Nullable!SysTime added;
171     ExitStatus exitStatus;
172 }
173 
174 /// Metadata about a line in a file.
175 struct LineMetadata {
176     FileId id;
177     uint line;
178     LineAttr attr;
179 
180     this(FileId fid, uint line) {
181         this(fid, line, LineAttr.init);
182     }
183 
184     this(FileId fid, uint line, LineAttr attr) {
185         this.id = fid;
186         this.line = line;
187         this.attr = attr;
188     }
189 
190     void set(NoMut a) @trusted pure nothrow @nogc {
191         attr = LineAttr(a);
192     }
193 
194     bool isNoMut() @safe pure nothrow const @nogc {
195         return attr.match!((NoMetadata a) => false, (NoMut a) => true);
196     }
197 }
198 
199 struct NoMetadata {
200 }
201 
202 /// A mutation suppression with optional tag and comment.
203 struct NoMut {
204     string tag;
205     string comment;
206 }
207 
208 /// Metadata attributes that may be attached to a mutant.
209 alias MutantAttr = SumType!(NoMetadata, NoMut);
210 
211 /// Metadata attributes that may be attached to a line.
212 alias LineAttr = SumType!(NoMetadata, NoMut);
213 
214 /// Metadata about a mutant.
215 struct MutantMetaData {
216     import std.range : isOutputRange;
217 
218     MutationId id;
219     MutantAttr attr;
220 
221     this(MutationId id) {
222         this(id, MutantAttr.init);
223     }
224 
225     this(MutationId id, MutantAttr attr) {
226         this.id = id;
227         this.attr = attr;
228     }
229 
230     void set(NoMut a) @trusted pure nothrow @nogc {
231         attr = MutantAttr(a);
232     }
233 
234     bool isNoMut() @safe pure nothrow const @nogc {
235         return attr.match!((NoMetadata a) => false, (NoMut a) => true);
236     }
237 
238     string kindToString() @safe pure const {
239         import std.array : appender;
240         import std.format : FormatSpec;
241 
242         auto buf = appender!string;
243         kindToString(buf);
244         return buf.data;
245     }
246 
247     void kindToString(Writer)(ref Writer w) const if (isOutputRange!(Writer, char)) {
248         import std.range : put;
249 
250         attr.match!((NoMetadata a) {}, (NoMut a) => put(w, "nomut"));
251     }
252 
253     import std.range : isOutputRange;
254 
255     string toString() @safe pure const {
256         import std.array : appender;
257 
258         auto buf = appender!string;
259         toString(buf);
260         return buf.data;
261     }
262 
263     void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, char)) {
264         kindToString(w);
265     }
266 }
267 
268 alias Rationale = NamedType!(string, Tag!"Rationale", string.init, TagStringable);
269 
270 struct MarkedMutant {
271     MutationStatusId statusId;
272 
273     /// Checksum of the marked mutant.
274     Checksum statusChecksum;
275 
276     MutationId mutationId;
277 
278     SourceLoc sloc;
279     Path path;
280 
281     /// The status it should always be changed to.
282     Mutation.Status toStatus;
283 
284     /// Time when the mutant where marked.
285     SysTime time;
286 
287     Rationale rationale;
288 
289     string mutText;
290 }
291 
292 /// A fragment of a schemata which is one application.
293 struct SchemataFragment {
294     Path file;
295     Offset offset;
296     const(ubyte)[] text;
297 }
298 
299 struct Schemata {
300     SchemataId id;
301 
302     /// Sorted in the order they should be applied.
303     SchemataFragment[] fragments;
304 }
305 
306 struct TestCmdRuntime {
307     SysTime timeStamp;
308 
309     /// The execution time of the test suite.
310     Duration runtime;
311 }
312 
313 struct MutationScore {
314     SysTime timeStamp;
315     NamedType!(double, Tag!"MutationScore", 0.0, TagStringable) score;
316 }
317 
318 alias TestFilePath = NamedType!(Path, Tag!"TestFilePath", Path.init, Hashable, TagStringable);
319 alias TestFileChecksum = NamedType!(Checksum, Tag!"TestFileChecksum",
320         Checksum.init, TagStringable, Hashable);
321 
322 struct TestFile {
323     TestFilePath file;
324 
325     /// Checksum of the content.
326     TestFileChecksum checksum;
327 
328     /// Last time the file was changed.
329     SysTime timeStamp;
330 }
331 
332 alias CoverageRegionId = NamedType!(long, Tag!"CoverageRegionId", long.init,
333         Comparable, Hashable, ConvertStringable);
334 struct CovRegion {
335     CoverageRegionId id;
336     Offset region;
337 }
338 
339 /// A file that a root is dependent on.
340 struct DepFile {
341     Path file;
342     Checksum checksum;
343 }
344 
345 alias ToolVersion = NamedType!(long, Tag!"ToolVersion", long.init, TagStringable, Comparable);
346 
347 alias ChecksumTestCmdOriginal = NamedType!(Checksum64,
348         Tag!"ChecksumTestCmdOriginal", Checksum64.init, TagStringable);
349 
350 alias ChecksumTestCmdMutated = NamedType!(Checksum64,
351         Tag!"ChecksumTestCmdMutated", Checksum64.init, TagStringable);
352 
353 enum SchemaStatus {
354     /// no status exist
355     none,
356     /// the schema compiled and the test suite executed OK
357     ok,
358     /// either it failed to compile or the test suite failed
359     broken,
360     /// the schema only contain killed mutants
361     allKilled,
362 }