Bug 1874684 - Part 33: Defer allocation of options object for CalendarDateFromFields...
[gecko.git] / remote / test / puppeteer / tools / sort-test-expectations.mjs
blob972d2448740a2aaab6b7d89b68e1b2f3fdccd3e9
1 /**
2  * @license
3  * Copyright 2023 Google Inc.
4  * SPDX-License-Identifier: Apache-2.0
5  */
7 // TODO: this could be an eslint rule probably.
8 import fs from 'fs';
9 import path from 'path';
10 import url from 'url';
12 import prettier from 'prettier';
14 const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
15 const source = 'test/TestExpectations.json';
16 let testExpectations = JSON.parse(fs.readFileSync(source, 'utf-8'));
17 const committedExpectations = structuredClone(testExpectations);
19 function testIdMatchesExpectationPattern(title, pattern) {
20   const patternRegExString = pattern
21     // Replace `*` with non special character
22     .replace(/\*/g, '--STAR--')
23     // Escape special characters https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
24     .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
25     // Replace placeholder with greedy match
26     .replace(/--STAR--/g, '(.*)?');
27   // Match beginning and end explicitly
28   const patternRegEx = new RegExp(`^${patternRegExString}$`);
29   return patternRegEx.test(title);
32 const prettierConfig = await import(
33   path.join(__dirname, '..', '.prettierrc.cjs')
36 function getSpecificity(item) {
37   return (
38     item.parameters.length +
39     (item.testIdPattern.includes('*')
40       ? item.testIdPattern === '*'
41         ? 0
42         : 1
43       : 2)
44   );
47 testExpectations.sort((a, b) => {
48   const result = getSpecificity(a) - getSpecificity(b);
49   if (result === 0) {
50     return a.testIdPattern.localeCompare(b.testIdPattern);
51   }
52   return result;
53 });
55 testExpectations.forEach(item => {
56   item.parameters.sort();
57   item.expectations.sort();
58   item.platforms.sort();
59   // Delete comments for PASS expectations. They are likely outdated.
60   if (item.expectations.length === 1 && item.expectations[0] === 'PASS') {
61     delete item.comment;
62   }
63 });
65 function isSubset(superset, subset) {
66   let isSubset = true;
68   for (const p of subset) {
69     if (!superset.has(p)) {
70       isSubset = false;
71     }
72   }
74   return isSubset;
77 const toBeRemoved = new Set();
78 for (let i = testExpectations.length - 1; i >= 0; i--) {
79   const expectation = testExpectations[i];
80   const params = new Set(expectation.parameters);
81   const labels = new Set(expectation.expectations);
82   const platforms = new Set(expectation.platforms);
84   let foundMatch = false;
85   for (let j = i - 1; j >= 0; j--) {
86     const candidate = testExpectations[j];
87     const candidateParams = new Set(candidate.parameters);
88     const candidateLabels = new Set(candidate.expectations);
89     const candidatePlatforms = new Set(candidate.platforms);
91     if (
92       testIdMatchesExpectationPattern(
93         expectation.testIdPattern,
94         candidate.testIdPattern
95       ) &&
96       isSubset(candidateParams, params) &&
97       isSubset(candidatePlatforms, platforms)
98     ) {
99       foundMatch = true;
100       if (isSubset(candidateLabels, labels)) {
101         console.log('removing', expectation, 'already covered by', candidate);
102         toBeRemoved.add(expectation);
103       }
104       break;
105     }
106   }
108   if (!foundMatch && isSubset(new Set(['PASS']), labels)) {
109     console.log(
110       'removing',
111       expectation,
112       'because the default expectation is to pass'
113     );
114     toBeRemoved.add(expectation);
115   }
118 testExpectations = testExpectations.filter(item => {
119   return !toBeRemoved.has(item);
122 if (process.argv.includes('--lint')) {
123   const missingComments = [];
124   testExpectations.forEach(item => {
125     if (item.expectations.length === 1 && item.expectations[0] === 'PASS') {
126       return;
127     }
128     if (!item.comment) {
129       missingComments.push(item);
130     }
131   });
133   if (
134     JSON.stringify(committedExpectations) !== JSON.stringify(testExpectations)
135   ) {
136     console.error(
137       `${source} is not formatted properly. Run 'npm run format:expectations'.`
138     );
139     process.exit(1);
140   }
142   if (missingComments.length > 0) {
143     console.error(
144       `${source}: missing comments for the following expectations:`,
145       missingComments
146     );
147     process.exit(1);
148   }
149 } else {
150   fs.writeFileSync(
151     source,
152     await prettier.format(JSON.stringify(testExpectations), {
153       ...prettierConfig,
154       parser: 'json',
155     })
156   );