1 /**
2 Copyright: Copyright (c) 2020, 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_stats;
11 
12 import logger = std.experimental.logger;
13 import std.datetime : Clock, dur;
14 import std.format : format;
15 
16 import arsd.dom : Element, Link, Document;
17 import my.path : AbsolutePath;
18 
19 import dextool.plugin.mutate.backend.database : Database;
20 import dextool.plugin.mutate.backend.report.analyzers : MutationStat,
21     reportStatistics, reportSyncStatus, SyncStatus;
22 import dextool.plugin.mutate.backend.report.html.constants;
23 import dextool.plugin.mutate.backend.report.html.tmpl : tmplDefaultTable,
24     PieGraph, TimeScalePointGraph;
25 import dextool.plugin.mutate.backend.type : Mutation;
26 import dextool.plugin.mutate.backend.report.html.utility;
27 
28 void makeStats(ref Database db, string tag, Document doc, Element root,
29         const AbsolutePath workListFname) @trusted {
30     import dextool.plugin.mutate.backend.report.html.page_worklist;
31 
32     DashboardCss.h2(root.addChild(new Link(tag, null)).setAttribute("id", tag[1 .. $]), "Overview");
33     overallStat(reportStatistics(db), root.addChild("div"));
34     makeWorklistPage(db, root, workListFname);
35     syncStatus(reportSyncStatus(db, 100), root);
36 }
37 
38 private:
39 
40 // TODO: this function contains duplicated logic from the one in ../utility.d
41 void overallStat(const MutationStat s, Element base) {
42     import std.conv : to;
43     import std.typecons : tuple;
44 
45     base.addChild("p").appendHtml(format("Mutation Score <b>%.3s</b>", s.score));
46     auto time = base.addChild("div", "Time spent");
47     generatePopupHelp(time, format("%s", s.totalTime));
48 
49     if (s.untested > 0 && s.predictedDone > 0.dur!"msecs") {
50         const pred = Clock.currTime + s.predictedDone;
51         base.addChild("p", format("Remaining: %s (%s)", s.predictedDone, pred.toISOExtString));
52     }
53 
54     PieGraph("score", [
55             PieGraph.Item("alive", "red", s.alive - s.aliveNoMut),
56             PieGraph.Item("killed", "green", s.killed),
57             PieGraph.Item("Untested", "grey", s.untested),
58             PieGraph.Item("Timeout", "lightgreen", s.timeout)
59             ]).html(base, PieGraph.Width(50));
60 
61     auto tbl = tmplDefaultTable(base, ["Type", "Value"]);
62 
63     foreach (const d; [
64             tuple("Total", s.total),
65             tuple("Killed by compiler", cast(long) s.killedByCompiler),
66             tuple("Skipped", s.skipped), tuple("Equivalent", s.equivalent),
67         ]) {
68         tbl.appendRow(d[0], d[1]);
69     }
70     {
71         auto wlRow = tbl.appendRow;
72         auto wltd = wlRow.addChild("td");
73         wltd.addChild("a", "Worklist").setAttribute("href", "worklist.html");
74         generatePopupHelp(wltd,
75                 "Worklist is the number of mutants that are in the same queue to be tested/retested");
76         wltd.addChild("td", s.worklist.to!string);
77     }
78 
79     if (s.aliveNoMut != 0) {
80         auto nmRow = tbl.appendRow;
81         auto nmtd = nmRow.addChild("td", "NoMut");
82         generatePopupHelp(nmtd, "NoMut is the number of mutants that are alive but ignored.
83             They are suppressed.
84             This result in those mutants increasing the mutation score.");
85         nmtd.addChild("td", s.aliveNoMut.to!string);
86 
87         auto nmtotalRow = tbl.appendRow;
88         auto nmtotaltd = nmtotalRow.addChild("td", "NoMut/total");
89         generatePopupHelp(nmtotaltd,
90                 "NoMut/total (Supressed/total) is how much the result has increased.
91             You should react if it is high.");
92         nmtotaltd.addChild("td", format("%.3s", s.suppressedOfTotal));
93     }
94 }
95 
96 void syncStatus(SyncStatus status, Element root) {
97     auto ts = TimeScalePointGraph("SyncStatus");
98 
99     ts.put("Test", TimeScalePointGraph.Point(status.test, 1.6));
100     ts.setColor("Test", "lightBlue");
101 
102     ts.put("Code", TimeScalePointGraph.Point(status.code, 1.4));
103     ts.setColor("Code", "lightGreen");
104 
105     ts.put("Coverage", TimeScalePointGraph.Point(status.coverage, 1.2));
106     ts.setColor("Coverage", "purple");
107 
108     if (status.mutants.length != 0) {
109         double y = 0.8;
110         foreach (v; status.mutants) {
111             ts.put("Mutant", TimeScalePointGraph.Point(v.updated, y));
112             y += 0.3 / status.mutants.length;
113         }
114         ts.setColor("Mutant", "red");
115     }
116     ts.html(root, TimeScalePointGraph.Width(50));
117 
118     auto info = root.addChild("div", "Sync Status");
119     generatePopupHelp(info, "Sync Status is how old the information about mutants and their status is compared to when the tests or source code where last changed.");
120 
121 }