tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mochitestListingsUtils.js (9016B)


      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/. */
      4 
      5 // We expect this to be defined in the global scope by runtest.py.
      6 /* global _TEST_PREFIX */
      7 
      8 //
      9 // HTML GENERATION
     10 //
     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",
    115 ];
    116 
    117 /**
    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 = "";
    126 
    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;
    132 
    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 += ">";
    140 
    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    }
    149 
    150    // write the close tag
    151    response += "</" + tagName + ">\n";
    152    return response;
    153  };
    154 }
    155 
    156 function makeTags() {
    157  // map our global HTML generation functions
    158  for (let tag of tags) {
    159    this[tag] = makeTagFunc(tag.toLowerCase());
    160  }
    161 }
    162 
    163 /**
    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  }
    172 }
    173 
    174 /**
    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  }
    184 
    185  var dir = directory.QueryInterface(Ci.nsIFile);
    186  var links = {};
    187 
    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  }
    195 
    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);
    208 
    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  }
    223 
    224  return [links, count];
    225 }
    226 
    227 /**
    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  }
    236 
    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);
    241 
    242  var pathPieces = filename.split("/");
    243 
    244  return (
    245    testPattern.test(pathPieces[pathPieces.length - 1]) &&
    246    !filename.includes(".js") &&
    247    !filename.includes(".css") &&
    248    !/\^headers\^$/.test(filename)
    249  );
    250 }
    251 
    252 /**
    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    }
    269 
    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    }
    275 
    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;
    290 }
    291 
    292 /**
    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        : "";
    303 
    304    var spacer = "padding-left: " + 10 * recursionLevel + "px";
    305 
    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;
    345 }
    346 
    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  }
    356 }
    357 /**
    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  });
    366 
    367  return "[" + testFiles.join(",\n") + "]";
    368 }
    369 
    370 /**
    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  );
    382 }