testilo 13.10.0 → 13.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,241 @@
1
+ /*
2
+ tsp28
3
+ Testilo score proc 28
4
+
5
+ Computes target score data and adds them to a ts26 report.
6
+ */
7
+
8
+ // IMPORTS
9
+
10
+ const {issueClasses} = require('./tic28');
11
+
12
+ // CONSTANTS
13
+
14
+ // ID of this proc.
15
+ const scoreProcID = 'tsp28';
16
+ // Configuration disclosures.
17
+ const severityWeights = [1, 2, 3, 4];
18
+ const toolWeight = 0.1;
19
+ const logWeights = {
20
+ logCount: 0.1,
21
+ logSize: 0.002,
22
+ errorLogCount: 0.2,
23
+ errorLogSize: 0.004,
24
+ prohibitedCount: 3,
25
+ visitRejectionCount: 2
26
+ };
27
+ // How much each second of excess latency adds to the score.
28
+ const latencyWeight = 1;
29
+ // Normal latency (1.5 second per visit).
30
+ const normalLatency = 9;
31
+ // How much each prevention adds to the score.
32
+ const preventionWeight = 300;
33
+ // Indexes of issues.
34
+ const issueIndex = {};
35
+ const issueMatcher = [];
36
+ Object.keys(issueClasses).forEach(issueClassName => {
37
+ Object.keys(issueClasses[issueClassName].tools).forEach(toolName => {
38
+ Object.keys(issueClasses[issueClassName].tools[toolName]).forEach(issueID => {
39
+ if (! issueIndex[toolName]) {
40
+ issueIndex[toolName] = {};
41
+ }
42
+ issueIndex[toolName][issueID] = issueClassName;
43
+ if (issueClasses[issueClassName].tools[toolName][issueID].variable) {
44
+ issueMatcher.push(issueID);
45
+ }
46
+ })
47
+ });
48
+ });
49
+
50
+ // FUNCTIONS
51
+
52
+ // Scores a report.
53
+ exports.scorer = report => {
54
+ console.log(`Scoring report ${report.id}`);
55
+ // If there are any acts in the report:
56
+ const {acts} = report;
57
+ if (Array.isArray(acts) && acts.length) {
58
+ // If any of them are test acts:
59
+ const testActs = acts.filter(act => act.type === 'test');
60
+ if (testActs.length) {
61
+ // Initialize the score data.
62
+ const score = {
63
+ scoreProcID,
64
+ summary: {
65
+ total: 0,
66
+ issue: 0,
67
+ tool: 0,
68
+ prevention: 0,
69
+ log: 0,
70
+ latency: 0
71
+ },
72
+ details: {
73
+ severity: {
74
+ total: [0, 0, 0, 0],
75
+ byTool: {}
76
+ },
77
+ prevention: {},
78
+ issue: {}
79
+ }
80
+ };
81
+ const {summary, details} = score;
82
+ // For each test act:
83
+ testActs.forEach(act => {
84
+ // If the page prevented the tool from operating:
85
+ const {which, standardResult} = act;
86
+ if (! standardResult || standardResult.prevented) {
87
+ // Add this to the score.
88
+ details.prevention[which] = preventionWeight;
89
+ }
90
+ // Otherwise, if a successful standard result exists:
91
+ else if (
92
+ standardResult
93
+ && standardResult.totals
94
+ && standardResult.totals.length === 4
95
+ && standardResult.instances
96
+ ) {
97
+ // Add the severity totals of the tool to the score.
98
+ const {totals} = standardResult;
99
+ details.severity.byTool[which] = totals;
100
+ // Add the instance data of the tool to the score.
101
+ standardResult.instances.forEach(instance => {
102
+ let {ruleID} = instance;
103
+ if (! issueIndex[which][ruleID]) {
104
+ ruleID = issueMatcher.find(pattern => {
105
+ const patternRE = new RegExp(pattern);
106
+ return patternRE.test(instance.ruleID);
107
+ });
108
+ }
109
+ if (ruleID) {
110
+ const issueID = issueIndex[which][ruleID];
111
+ if (! details.issue[issueID]) {
112
+ details.issue[issueID] = {
113
+ score: 0,
114
+ maxCount: 0,
115
+ weight: issueClasses[issueID].weight,
116
+ tools: {}
117
+ };
118
+ }
119
+ if (! details.issue[issueID].tools[which]) {
120
+ details.issue[issueID].tools[which] = {};
121
+ }
122
+ if (! details.issue[issueID].tools[which][ruleID]) {
123
+ const ruleData = issueClasses[issueID].tools[which][ruleID];
124
+ details.issue[issueID].tools[which][ruleID] = {
125
+ quality: ruleData.quality,
126
+ what: ruleData.what,
127
+ complaints: {
128
+ countTotal: 0,
129
+ texts: []
130
+ }
131
+ };
132
+ }
133
+ details
134
+ .issue[issueID]
135
+ .tools[which][ruleID]
136
+ .complaints
137
+ .countTotal += instance.count || 1;
138
+ if (
139
+ ! details
140
+ .issue[issueID]
141
+ .tools[which][ruleID]
142
+ .complaints
143
+ .texts
144
+ .includes(instance.what)
145
+ ) {
146
+ details.issue[issueID].tools[which][ruleID].complaints.texts.push(instance.what);
147
+ }
148
+ }
149
+ else {
150
+ console.log(`ERROR: ${instance.ruleID} of ${which} not found in issueClasses`);
151
+ }
152
+ });
153
+ }
154
+ // Otherwise, i.e. if a failed standard result exists:
155
+ else {
156
+ // Add an inferred prevention to the score.
157
+ details.prevention[which] = preventionWeight;
158
+ }
159
+ });
160
+ // For each issue with any complaints:
161
+ Object.keys(details.issue).forEach(issueID => {
162
+ const issueData = details.issue[issueID];
163
+ // For each tool with any complaints for the issue:
164
+ Object.keys(issueData.tools).forEach(toolID => {
165
+ // Get the sum of the weighted counts of its issue rules.
166
+ let weightedCount = 0;
167
+ Object.values(issueData.tools[toolID]).forEach(ruleData => {
168
+ weightedCount += ruleData.quality * ruleData.complaints.countTotal;
169
+ });
170
+ // If the sum exceeds the existing maximum weighted count for the issue:
171
+ if (weightedCount > issueData.maxCount) {
172
+ // Change the maximum count for the issue to the sum.
173
+ issueData.maxCount = weightedCount;
174
+ }
175
+ });
176
+ // Get the score for the issue.
177
+ issueData.score = Math.round(issueData.weight * issueData.maxCount);
178
+ });
179
+ // Add the severity detail totals to the score.
180
+ details.severity.total = Object.keys(details.severity.byTool).reduce((severityTotals, toolID) => {
181
+ details.severity.byTool[toolID].forEach((severityScore, index) => {
182
+ severityTotals[index] += severityScore;
183
+ });
184
+ return severityTotals;
185
+ }, details.severity.total);
186
+ // Add the summary issue total to the score.
187
+ summary.issue = Object
188
+ .values(details.issue)
189
+ .reduce((total, current) => total + current.score, 0);
190
+ // Add the summary tool total to the score.
191
+ summary.tool = toolWeight * details.severity.total.reduce(
192
+ (total, current, index) => total + severityWeights[index] * current, 0
193
+ );
194
+ // Add the summary prevention total to the score.
195
+ summary.prevention = Object.values(details.prevention).reduce(
196
+ (total, current) => total + current, 0
197
+ );
198
+ // Add the summary log score to the score.
199
+ const {jobData} = report;
200
+ if (jobData) {
201
+ summary.log = Math.max(0, Math.round(
202
+ logWeights.logCount * jobData.logCount
203
+ + logWeights.logSize * jobData.logSize +
204
+ + logWeights.errorLogCount * jobData.errorLogCount
205
+ + logWeights.errorLogSize * jobData.errorLogSize
206
+ + logWeights.prohibitedCount * jobData.prohibitedCount +
207
+ + logWeights.visitRejectionCount * jobData.visitRejectionCount
208
+ ));
209
+ // Add the summary latency score to the score.
210
+ summary.latency = Math.round(
211
+ latencyWeight * (Math.max(0, jobData.visitLatency - normalLatency))
212
+ );
213
+ }
214
+ // Round the unrounded scores.
215
+ Object.keys(summary).forEach(summaryTypeName => {
216
+ summary[summaryTypeName] = Math.round(summary[summaryTypeName]);
217
+ });
218
+ details.severity.total.forEach((severityTotal, index) => {
219
+ details.severity.total[index] = Math.round(severityTotal);
220
+ });
221
+ // Add the summary total score to the score.
222
+ summary.total = summary.issue
223
+ + summary.tool
224
+ + summary.prevention
225
+ + summary.log
226
+ + summary.latency;
227
+ // Add the score to the report.
228
+ report.score = score;
229
+ }
230
+ // Otherwise, i.e. if none of them is a test act:
231
+ else {
232
+ // Report this.
233
+ console.log('ERROR: No test acts');
234
+ }
235
+ }
236
+ // Otherwise, i.e. if there are no acts in the report:
237
+ else {
238
+ // Report this.
239
+ console.log('ERROR: No acts');
240
+ }
241
+ };