Bug 1877642 - Disable browser_fullscreen-tab-close-race.js on apple_silicon !debug...
[gecko.git] / testing / mochitest / mochitestListingsUtils.js
blobf8a2305386fe0ba5f977d3646e557d53bb2c3b38
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // We expect this to be defined in the global scope by runtest.py.
6 /* global _TEST_PREFIX */
8 //
9 // HTML GENERATION
11 /* global A, ABBR, ACRONYM, ADDRESS, APPLET, AREA, B, BASE,
12           BASEFONT, BDO, BIG, BLOCKQUOTE, BODY, BR, BUTTON,
13           CAPTION, CENTER, CITE, CODE, COL, COLGROUP, DD,
14           DEL, DFN, DIR, DIV, DL, DT, EM, FIELDSET, FONT,
15           FORM, FRAME, FRAMESET, H1, H2, H3, H4, H5, H6,
16           HEAD, HR, HTML, I, IFRAME, IMG, INPUT, INS,
17           ISINDEX, KBD, LABEL, LEGEND, LI, LINK, MAP, MENU,
18           META, NOFRAMES, NOSCRIPT, OBJECT, OL, OPTGROUP,
19           OPTION, P, PARAM, PRE, Q, S, SAMP, SCRIPT,
20           SELECT, SMALL, SPAN, STRIKE, STRONG, STYLE, SUB,
21           SUP, TABLE, TBODY, TD, TEXTAREA, TFOOT, TH, THEAD,
22           TITLE, TR, TT, U, UL, VAR */
23 var tags = [
24   "A",
25   "ABBR",
26   "ACRONYM",
27   "ADDRESS",
28   "APPLET",
29   "AREA",
30   "B",
31   "BASE",
32   "BASEFONT",
33   "BDO",
34   "BIG",
35   "BLOCKQUOTE",
36   "BODY",
37   "BR",
38   "BUTTON",
39   "CAPTION",
40   "CENTER",
41   "CITE",
42   "CODE",
43   "COL",
44   "COLGROUP",
45   "DD",
46   "DEL",
47   "DFN",
48   "DIR",
49   "DIV",
50   "DL",
51   "DT",
52   "EM",
53   "FIELDSET",
54   "FONT",
55   "FORM",
56   "FRAME",
57   "FRAMESET",
58   "H1",
59   "H2",
60   "H3",
61   "H4",
62   "H5",
63   "H6",
64   "HEAD",
65   "HR",
66   "HTML",
67   "I",
68   "IFRAME",
69   "IMG",
70   "INPUT",
71   "INS",
72   "ISINDEX",
73   "KBD",
74   "LABEL",
75   "LEGEND",
76   "LI",
77   "LINK",
78   "MAP",
79   "MENU",
80   "META",
81   "NOFRAMES",
82   "NOSCRIPT",
83   "OBJECT",
84   "OL",
85   "OPTGROUP",
86   "OPTION",
87   "P",
88   "PARAM",
89   "PRE",
90   "Q",
91   "S",
92   "SAMP",
93   "SCRIPT",
94   "SELECT",
95   "SMALL",
96   "SPAN",
97   "STRIKE",
98   "STRONG",
99   "STYLE",
100   "SUB",
101   "SUP",
102   "TABLE",
103   "TBODY",
104   "TD",
105   "TEXTAREA",
106   "TFOOT",
107   "TH",
108   "THEAD",
109   "TITLE",
110   "TR",
111   "TT",
112   "U",
113   "UL",
114   "VAR",
118  * Below, we'll use makeTagFunc to create a function for each of the
119  * strings in 'tags'. This will allow us to use s-expression like syntax
120  * to create HTML.
121  */
122 function makeTagFunc(tagName) {
123   return function (attrs /* rest... */) {
124     var startChildren = 0;
125     var response = "";
127     // write the start tag and attributes
128     response += "<" + tagName;
129     // if attr is an object, write attributes
130     if (attrs && typeof attrs == "object") {
131       startChildren = 1;
133       for (let key in attrs) {
134         const value = attrs[key];
135         var val = "" + value;
136         response += " " + key + '="' + val.replace('"', "&quot;") + '"';
137       }
138     }
139     response += ">";
141     // iterate through the rest of the args
142     for (var i = startChildren; i < arguments.length; i++) {
143       if (typeof arguments[i] == "function") {
144         response += arguments[i]();
145       } else {
146         response += arguments[i];
147       }
148     }
150     // write the close tag
151     response += "</" + tagName + ">\n";
152     return response;
153   };
156 function makeTags() {
157   // map our global HTML generation functions
158   for (let tag of tags) {
159     this[tag] = makeTagFunc(tag.toLowerCase());
160   }
164  * Creates a generator that iterates over the contents of
165  * an nsIFile directory.
166  */
167 function* dirIter(dir) {
168   var en = dir.directoryEntries;
169   while (en.hasMoreElements()) {
170     yield en.nextFile;
171   }
175  * Builds an optionally nested object containing links to the
176  * files and directories within dir.
177  */
178 function list(requestPath, directory, recurse) {
179   var count = 0;
180   var path = requestPath;
181   if (path.charAt(path.length - 1) != "/") {
182     path += "/";
183   }
185   var dir = directory.QueryInterface(Ci.nsIFile);
186   var links = {};
188   // The SimpleTest directory is hidden
189   let files = [];
190   for (let file of dirIter(dir)) {
191     if (file.exists() && !file.path.includes("SimpleTest")) {
192       files.push(file);
193     }
194   }
196   // Sort files by name, so that tests can be run in a pre-defined order inside
197   // a given directory (see bug 384823)
198   function leafNameComparator(first, second) {
199     if (first.leafName < second.leafName) {
200       return -1;
201     }
202     if (first.leafName > second.leafName) {
203       return 1;
204     }
205     return 0;
206   }
207   files.sort(leafNameComparator);
209   count = files.length;
210   for (let file of files) {
211     var key = path + file.leafName;
212     var childCount = 0;
213     if (file.isDirectory()) {
214       key += "/";
215     }
216     if (recurse && file.isDirectory()) {
217       [links[key], childCount] = list(key, file, recurse);
218       count += childCount;
219     } else if (file.leafName.charAt(0) != ".") {
220       links[key] = { test: { url: key, expected: "pass" } };
221     }
222   }
224   return [links, count];
228  * Heuristic function that determines whether a given path
229  * is a test case to be executed in the harness, or just
230  * a supporting file.
231  */
232 function isTest(filename, pattern) {
233   if (pattern) {
234     return pattern.test(filename);
235   }
237   // File name is a URL style path to a test file, make sure that we check for
238   // tests that start with the appropriate prefix.
239   var testPrefix = typeof _TEST_PREFIX == "string" ? _TEST_PREFIX : "test_";
240   var testPattern = new RegExp("^" + testPrefix);
242   var pathPieces = filename.split("/");
244   return (
245     testPattern.test(pathPieces[pathPieces.length - 1]) &&
246     !filename.includes(".js") &&
247     !filename.includes(".css") &&
248     !/\^headers\^$/.test(filename)
249   );
253  * Transform nested hashtables of paths to nested HTML lists.
254  */
255 function linksToListItems(links) {
256   var response = "";
257   var children = "";
258   for (let link in links) {
259     const value = links[link];
260     var classVal =
261       !isTest(link) && !(value instanceof Object)
262         ? "non-test invisible"
263         : "test";
264     if (value instanceof Object) {
265       children = UL({ class: "testdir" }, linksToListItems(value));
266     } else {
267       children = "";
268     }
270     var bug_title = link.match(/test_bug\S+/);
271     var bug_num = null;
272     if (bug_title != null) {
273       bug_num = bug_title[0].match(/\d+/);
274     }
276     if (bug_title == null || bug_num == null) {
277       response += LI({ class: classVal }, A({ href: link }, link), children);
278     } else {
279       var bug_url = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + bug_num;
280       response += LI(
281         { class: classVal },
282         A({ href: link }, link),
283         " - ",
284         A({ href: bug_url }, "Bug " + bug_num),
285         children
286       );
287     }
288   }
289   return response;
293  * Transform nested hashtables of paths to a flat table rows.
294  */
295 function linksToTableRows(links, recursionLevel) {
296   var response = "";
297   for (let link in links) {
298     const value = links[link];
299     var classVal =
300       !isTest(link) && value instanceof Object && "test" in value
301         ? "non-test invisible"
302         : "";
304     var spacer = "padding-left: " + 10 * recursionLevel + "px";
306     if (value instanceof Object && !("test" in value)) {
307       response += TR(
308         { class: "dir", id: "tr-" + link },
309         TD({ colspan: "3" }, "&#160;"),
310         TD({ style: spacer }, A({ href: link }, link))
311       );
312       response += linksToTableRows(value, recursionLevel + 1);
313     } else {
314       var bug_title = link.match(/test_bug\S+/);
315       var bug_num = null;
316       if (bug_title != null) {
317         bug_num = bug_title[0].match(/\d+/);
318       }
319       if (bug_title == null || bug_num == null) {
320         response += TR(
321           { class: classVal, id: "tr-" + link },
322           TD("0"),
323           TD("0"),
324           TD("0"),
325           TD({ style: spacer }, A({ href: link }, link))
326         );
327       } else {
328         var bug_url = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + bug_num;
329         response += TR(
330           { class: classVal, id: "tr-" + link },
331           TD("0"),
332           TD("0"),
333           TD("0"),
334           TD(
335             { style: spacer },
336             A({ href: link }, link),
337             " - ",
338             A({ href: bug_url }, "Bug " + bug_num)
339           )
340         );
341       }
342     }
343   }
344   return response;
347 function arrayOfTestFiles(linkArray, fileArray, testPattern) {
348   for (let link in linkArray) {
349     const value = linkArray[link];
350     if (value instanceof Object && !("test" in value)) {
351       arrayOfTestFiles(value, fileArray, testPattern);
352     } else if (isTest(link, testPattern) && value instanceof Object) {
353       fileArray.push(value.test);
354     }
355   }
358  * Produce a flat array of test file paths to be executed in the harness.
359  */
360 function jsonArrayOfTestFiles(links) {
361   var testFiles = [];
362   arrayOfTestFiles(links, testFiles);
363   testFiles = testFiles.map(function (file) {
364     return '"' + file.url + '"';
365   });
367   return "[" + testFiles.join(",\n") + "]";
371  * Produce a normal directory listing.
372  */
373 function regularListing(metadata, response) {
374   var [links] = list(metadata.path, metadata.getProperty("directory"), false);
375   response.write(
376     "<!DOCTYPE html>\n" +
377       HTML(
378         HEAD(TITLE("mochitest index ", metadata.path)),
379         BODY(BR(), A({ href: ".." }, "Up a level"), UL(linksToListItems(links)))
380       )
381   );