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_case_similarity; 11 12 import logger = std.experimental.logger; 13 import std.format : format; 14 import std.datetime : dur, Clock; 15 16 import arsd.dom : Document, Element, require, Table, RawSource; 17 18 import dextool.plugin.mutate.backend.database : Database; 19 import dextool.plugin.mutate.backend.report.analyzers : TestCaseSimilarityAnalyse, 20 reportTestCaseSimilarityAnalyse; 21 import dextool.plugin.mutate.backend.report.html.constants; 22 import dextool.plugin.mutate.backend.resource : jsTableOnClick; 23 import dextool.plugin.mutate.backend.report.html.tmpl : tmplBasicPage, 24 tmplDefaultTable, tmplDefaultMatrixTable, dashboardCss; 25 import dextool.plugin.mutate.backend.type : Mutation; 26 import dextool.plugin.mutate.config : ConfigReport; 27 import dextool.plugin.mutate.type : MutationKind; 28 29 auto makeTestCaseSimilarityAnalyse(ref Database db, ref const ConfigReport conf, 30 const(MutationKind)[] humanReadableKinds, const(Mutation.Kind)[] kinds) @trusted { 31 32 auto doc = tmplBasicPage.dashboardCss; 33 doc.title(format("Test Case Similarity Analyse %(%s %) %s", 34 humanReadableKinds, Clock.currTime)); 35 doc.mainBody.setAttribute("onload", "init()"); 36 37 auto script = doc.root.childElements("head")[0].addChild("script"); 38 script.addChild(new RawSource(doc, jsTableOnClick)); 39 40 toHtml(db, doc, reportTestCaseSimilarityAnalyse(db, kinds, 5), doc.mainBody, script); 41 42 return doc.toPrettyString; 43 } 44 45 private: 46 47 void toHtml(ref Database db, Document doc, TestCaseSimilarityAnalyse result, 48 Element root, Element script) { 49 import std.algorithm : sort, map; 50 import std.array : array, appender; 51 import std.conv : to; 52 import std.json : JSONValue; 53 import std.path : buildPath; 54 import dextool.cachetools; 55 import dextool.plugin.mutate.backend.database : spinSql, MutationId; 56 import dextool.plugin.mutate.backend.report.html.page_files : pathToHtmlLink; 57 import dextool.type : Path; 58 59 root.addChild("p", "This is the similarity between test cases."); 60 { 61 auto p = root.addChild("p"); 62 p.addChild("b", "Note"); 63 p.appendText(": The analysis is based on the mutants that the test cases kill; thus, it is dependent on the mutation operators that are used when generating the report."); 64 } 65 66 auto getPath = nullableCache!(MutationId, string, (MutationId id) { 67 auto path = spinSql!(() => db.getPath(id)).get; 68 return format!"%s#%s"(buildPath(Html.fileDir, pathToHtmlLink(path)), id); 69 })(0, 30.dur!"seconds"); 70 71 const test_cases = result.similarities.byKey.array.sort!((a, b) => a < b).array; 72 73 root.addChild("p", "The intersection column is the mutants that are killed by both the test case in the heading and in the column Test Case.") 74 .appendText( 75 " The difference column are the mutants that are only killed by the test case in the heading."); 76 root.addChild("p", 77 "The tables are hidden by default, click on the corresponding header to display a table."); 78 with (root.addChild("button", "expand all")) { 79 setAttribute("type", "button"); 80 setAttribute("id", "expand_all"); 81 } 82 with (root.addChild("button", "collapse all")) { 83 setAttribute("type", "button"); 84 setAttribute("id", "collapse_all"); 85 } 86 foreach (const tc; test_cases) { 87 // Containers allows for hiding a table by clicking the corresponding header. 88 // Defaults to hiding tables. 89 auto comp_container = root.addChild("div").addClass("comp_container"); 90 auto heading = comp_container.addChild("h2").addClass("tbl_header"); 91 heading.addChild("i").addClass("right"); 92 heading.appendText(" "); 93 heading.appendText(tc.name); 94 auto tbl_container = comp_container.addChild("div").addClass("tbl_container"); 95 tbl_container.setAttribute("style", "display: none;"); 96 auto tbl = tmplDefaultTable(tbl_container, [ 97 "Test Case", "Similarity", "Difference", "Intersection" 98 ]); 99 foreach (const d; result.similarities[tc]) { 100 auto r = tbl.appendRow(); 101 r.addChild("td", d.testCase.name); 102 r.addChild("td", format("%#.3s", d.similarity)); 103 auto difference = r.addChild("td"); 104 foreach (const mut; d.difference) { 105 auto link = difference.addChild("a", mut.to!string); 106 link.href = getPath(mut).get; 107 difference.appendText(" "); 108 } 109 auto similarity = r.addChild("td"); 110 foreach (const mut; d.intersection) { 111 auto link = similarity.addChild("a", mut.to!string); 112 link.href = getPath(mut).get; 113 similarity.appendText(" "); 114 } 115 } 116 } 117 }