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