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