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 }