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.report.html.page_test_groups; 11 12 import logger = std.experimental.logger; 13 import std.format : format; 14 15 import arsd.dom : Document, Element, require, Table; 16 17 import dextool.plugin.mutate.backend.database : Database; 18 import dextool.plugin.mutate.backend.diff_parser : Diff; 19 import dextool.plugin.mutate.backend.report.analyzers : TestGroupStat, reportTestGroups; 20 import dextool.plugin.mutate.backend.report.html.constants; 21 import dextool.plugin.mutate.backend.report.html.tmpl : tmplBasicPage, tmplDefaultTable; 22 import dextool.plugin.mutate.backend.type : Mutation; 23 import dextool.plugin.mutate.config : ConfigReport; 24 import dextool.plugin.mutate.type : MutationKind; 25 import dextool.type : AbsolutePath; 26 27 auto makeTestGroups(ref Database db, ref const ConfigReport conf, 28 const(MutationKind)[] humanReadableKinds, const(Mutation.Kind)[] kinds) @trusted { 29 import std.datetime : Clock; 30 31 auto doc = tmplBasicPage; 32 doc.title(format("Test Groups %(%s %) %s", humanReadableKinds, Clock.currTime)); 33 34 if (conf.testGroups.length != 0) 35 doc.mainBody.addChild("h2", "Test Groups"); 36 foreach (tg; conf.testGroups) 37 testGroups(reportTestGroups(db, kinds, tg), doc.mainBody); 38 39 return doc.toPrettyString; 40 } 41 42 private: 43 44 void testGroups(const TestGroupStat test_g, Element root) { 45 import std.algorithm : sort, map; 46 import std.array : array; 47 import std.conv : to; 48 import std.path : buildPath; 49 import std.typecons : tuple; 50 import dextool.plugin.mutate.backend.mutation_type : toUser; 51 import dextool.plugin.mutate.backend.report.html.page_files : pathToHtmlLink; 52 53 root.addChild("h3", test_g.description); 54 55 auto stat_tbl = tmplDefaultTable(root, ["Property", "Value"]); 56 foreach (const d; [ 57 tuple("Mutation Score", test_g.stats.score.to!string), 58 tuple("Alive", test_g.stats.alive.to!string), 59 tuple("Total", test_g.stats.total.to!string) 60 ]) { 61 auto r = stat_tbl.appendRow(); 62 r.addChild("td", d[0]); 63 r.addChild("td", d[1]); 64 } 65 66 with (root.addChild("p")) { 67 appendText("Mutation data per file."); 68 appendText("The killed mutants are those that where killed by this test group."); 69 appendText("Therefor the total here is less than the reported total."); 70 } 71 72 auto file_tbl = tmplDefaultTable(root, ["File", "Alive", "Killed"]); 73 74 foreach (const pkv; test_g.files 75 .byKeyValue 76 .map!(a => tuple(a.key, a.value.dup)) 77 .array 78 .sort!((a, b) => a[1] < b[1])) { 79 auto r = file_tbl.appendRow(); 80 81 const path = test_g.files[pkv[0]]; 82 r.addChild("td", path); 83 84 auto alive_ids = r.addChild("td").setAttribute("valign", "top"); 85 if (auto alive = pkv[0] in test_g.alive) { 86 foreach (a; (*alive).dup.sort!((a, b) => a.sloc.line < b.sloc.line)) { 87 auto link = alive_ids.addChild("a", format("%s:%s", a.kind.toUser, a.sloc.line)); 88 link.href = format("%s#%s", buildPath(htmlFileDir, pathToHtmlLink(path)), a.id); 89 alive_ids.appendText(" "); 90 } 91 } 92 93 auto killed_ids = r.addChild("td").setAttribute("valign", "top"); 94 if (auto killed = pkv[0] in test_g.killed) { 95 foreach (a; (*killed).dup.sort!((a, b) => a.sloc.line < b.sloc.line)) { 96 auto link = killed_ids.addChild("a", format("%s:%s", a.kind.toUser, a.sloc.line)); 97 link.href = format("%s#%s", buildPath(htmlFileDir, pathToHtmlLink(path)), a.id); 98 killed_ids.appendText(" "); 99 } 100 } 101 } 102 103 auto tc_tbl = tmplDefaultTable(root, ["Test Case"]); 104 foreach (tc; test_g.testCases) { 105 tc_tbl.appendRow(tc.name); 106 } 107 }