1 /** 2 Copyright: Copyright (c) 2019, 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_case_unique; 11 12 import logger = std.experimental.logger; 13 import std.format : format; 14 15 import arsd.dom : Element, RawSource; 16 17 import dextool.plugin.mutate.backend.database : Database; 18 import dextool.plugin.mutate.backend.report.analyzers : TestCaseUniqueness, 19 reportTestCaseUniqueness; 20 import dextool.plugin.mutate.backend.report.html.constants : htmlFileDir; 21 import dextool.plugin.mutate.backend.report.html.js : js_similarity; 22 import dextool.plugin.mutate.backend.report.html.tmpl : tmplBasicPage, tmplDefaultTable; 23 import dextool.plugin.mutate.backend.type : Mutation; 24 import dextool.plugin.mutate.config : ConfigReport; 25 import dextool.plugin.mutate.type : MutationKind; 26 27 auto makeTestCaseUnique(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 33 auto s = doc.root.childElements("head")[0].addChild("script"); 34 s.addChild(new RawSource(doc, js_similarity)); 35 36 doc.title(format("Test Case Uniqueness %(%s %) %s", humanReadableKinds, Clock.currTime)); 37 doc.mainBody.setAttribute("onload", "init()"); 38 doc.mainBody.addChild("p", "This report contains the test cases that uniquely kill mutants, which those mutants are and test cases that aren't unique."); 39 40 toHtml(db, reportTestCaseUniqueness(db, kinds), doc.mainBody); 41 42 return doc.toPrettyString; 43 } 44 45 private: 46 47 void toHtml(ref Database db, TestCaseUniqueness result, Element root) { 48 import std.algorithm : sort, map; 49 import std.array : array; 50 import std.conv : to; 51 import std.path : buildPath; 52 import cachetools : CacheLRU; 53 import dextool.cachetools; 54 import dextool.plugin.mutate.backend.database : spinSql, MutationId; 55 import dextool.plugin.mutate.backend.report.html.page_files : pathToHtmlLink; 56 import dextool.type : Path; 57 58 auto link_cache = new CacheLRU!(MutationId, string); 59 link_cache.ttl = 30; // magic number 60 Path getPath(MutationId id) { 61 return dextool.cachetools.cacheToolsRequire(link_cache, id, { 62 auto path = spinSql!(() => db.getPath(id)).get; 63 return format!"%s#%s"(buildPath(htmlFileDir, pathToHtmlLink(path)), id); 64 }()).Path; 65 } 66 67 with (root.addChild("button", "expand all")) { 68 setAttribute("type", "button"); 69 setAttribute("id", "expand_all"); 70 } 71 with (root.addChild("button", "collapse all")) { 72 setAttribute("type", "button"); 73 setAttribute("id", "collapse_all"); 74 } 75 76 foreach (const k; result.uniqueKills.byKey.array.sort) { 77 // Containers allows for hiding a table by clicking the corresponding header. 78 // Defaults to hiding tables. 79 auto comp_container = root.addChild("div").addClass("comp_container"); 80 auto heading = comp_container.addChild("h2").addClass("tbl_header"); 81 heading.addChild("i").addClass("right"); 82 heading.appendText(" "); 83 heading.appendText(k.name); 84 auto tbl_container = comp_container.addChild("div").addClass("tbl_container"); 85 tbl_container.setAttribute("style", "display: none;"); 86 auto tbl = tmplDefaultTable(tbl_container, ["Mutation ID"]); 87 88 auto r = tbl.appendRow(); 89 auto mut_ids = r.addChild("td"); 90 foreach (const m; result.uniqueKills[k].sort) { 91 auto link = mut_ids.addChild("a", m.to!string); 92 link.href = getPath(m); 93 mut_ids.appendText(" "); 94 } 95 } 96 97 { 98 root.addChild("p", "These are test cases that have no unique kills"); 99 auto tbl = tmplDefaultTable(root, ["Test Case"]); 100 foreach (const tc; result.noUniqueKills.sort) { 101 auto r = tbl.appendRow; 102 r.addChild("td", tc.name); 103 } 104 } 105 }