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