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