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 15 import arsd.dom : Document, Element, require, Table, RawSource; 16 17 import dextool.plugin.mutate.backend.database : Database; 18 import dextool.plugin.mutate.backend.report.html.constants; 19 import dextool.plugin.mutate.backend.report.html.js; 20 import dextool.plugin.mutate.backend.report.html.tmpl : tmplBasicPage, 21 tmplDefaultTable, tmplDefaultMatrixTable; 22 import dextool.plugin.mutate.backend.report.utility; 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 makeTestCaseSimilarityAnalyse(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 Similarity Analyse %(%s %) %s", 37 humanReadableKinds, Clock.currTime)); 38 doc.mainBody.setAttribute("onload", "init()"); 39 doc.mainBody.addChild("p", "This is the similarity between test cases.") 40 .appendText(" The closer to 1.0 the more similare the test cases are in what they verify."); 41 { 42 auto p = doc.mainBody.addChild("p"); 43 p.addChild("b", "Note"); 44 p.appendText(": The analyse 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."); 45 } 46 47 toHtml(db, reportTestCaseSimilarityAnalyse(db, kinds, 5), doc.mainBody); 48 49 return doc.toPrettyString; 50 } 51 52 private: 53 54 void toHtml(ref Database db, TestCaseSimilarityAnalyse result, Element root) { 55 import std.algorithm : sort, map; 56 import std.array : array; 57 import std.conv : to; 58 import std.path : buildPath; 59 import cachetools : CacheLRU; 60 import dextool.cachetools; 61 import dextool.plugin.mutate.backend.database : spinSqlQuery, MutationId; 62 import dextool.plugin.mutate.backend.report.html.page_files : pathToHtmlLink; 63 import dextool.type : Path; 64 65 auto link_cache = new CacheLRU!(MutationId, string); 66 link_cache.ttl = 30; // magic number 67 Path getPath(MutationId id) { 68 return dextool.cachetools.cacheToolsRequire(link_cache, id, { 69 auto path = spinSqlQuery!(() => db.getPath(id)); 70 return format!"%s#%s"(buildPath(htmlFileDir, pathToHtmlLink(path)), id); 71 }()).Path; 72 } 73 74 //const distances = result.distances.length; 75 const test_cases = result.similarities.byKey.array.sort!((a, b) => a < b).array; 76 77 //auto mat = tmplDefaultMatrixTable(root, test_cases.map!(a => a.name.idup).array); 78 79 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.") 80 .appendText( 81 " The difference column are the mutants that are only killed by the test case in the heading."); 82 root.addChild("p", "The tables are hidden by default, click on the corresponding header to display a table."); 83 foreach (const tc; test_cases) { 84 // Containers allows for hiding a table by clicking the corresponding header. 85 // Defaults to hiding tables. 86 auto comp_container = root.addChild("div").addClass("comp_container"); 87 comp_container.addChild("h2", tc.name).addClass("tbl_header"); 88 auto tbl_container = comp_container.addChild("div").addClass("tbl_container"); 89 tbl_container.setAttribute("style", "display: none;"); 90 auto tbl = tmplDefaultTable(tbl_container, [ 91 "Test Case", "Similarity", "Difference", "Intersection" 92 ]); 93 foreach (const d; result.similarities[tc]) { 94 auto r = tbl.appendRow(); 95 r.addChild("td", d.testCase.name); 96 r.addChild("td", format("%#.3s", d.similarity)); 97 auto difference = r.addChild("td"); 98 foreach (const mut; d.difference) { 99 auto link = difference.addChild("a", mut.to!string); 100 link.href = getPath(mut); 101 difference.appendText(" "); 102 } 103 auto similarity = r.addChild("td"); 104 foreach (const mut; d.intersection) { 105 auto link = similarity.addChild("a", mut.to!string); 106 link.href = getPath(mut); 107 similarity.appendText(" "); 108 } 109 } 110 } 111 }