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