tor-browser

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

parser_datreader.js (6548B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /**
      7 * A test suite that runs WHATWG HTML parser tests.
      8 * The tests are from html5lib.
      9 *
     10 * http://html5lib.googlecode.com/
     11 */
     12 
     13 /**
     14 * A few utility functions.
     15 */
     16 function log() {}
     17 
     18 function startsWith(s, s2) {
     19  return s.indexOf(s2) == 0;
     20 }
     21 
     22 function trimString(s) {
     23  return s.replace(/^\s+/, "").replace(/\s+$/, "");
     24 }
     25 
     26 /**
     27 * Parses an individual testcase into an array containing the input
     28 * string, a string representing the expected tree (DOM), and a list
     29 * of error messages.
     30 *
     31 * @param A string containing a single testcase
     32 */
     33 function parseTestcase(testcase) {
     34  var lines = testcase.split("\n");
     35 
     36  /* check that the first non-empty, non-comment line is #data */
     37  for (let line of lines) {
     38    if (!line || startsWith(line, "##")) {
     39      continue;
     40    }
     41    if (line == "#data") {
     42      break;
     43    }
     44    log(lines);
     45    throw new Error("Unknown test format.");
     46  }
     47 
     48  var input = [];
     49  var output = [];
     50  var errors = [];
     51  var fragment = [];
     52  var currentList = input;
     53  for (let line of lines) {
     54    if (startsWith(line, "##todo")) {
     55      todo(false, line.substring(6));
     56      continue;
     57    }
     58    if (
     59      !(
     60        startsWith(line, "#error") ||
     61        startsWith(line, "#document") ||
     62        startsWith(line, "#document-fragment") ||
     63        startsWith(line, "#data")
     64      )
     65    ) {
     66      currentList.push(line);
     67    } else if (line == "#errors") {
     68      currentList = errors;
     69    } else if (line == "#document") {
     70      currentList = output;
     71    } else if (line == "#document-fragment") {
     72      currentList = fragment;
     73    }
     74  }
     75  while (!output[output.length - 1]) {
     76    output.pop(); // zap trailing blank lines
     77  }
     78  // logger.log(input.length, output.length, errors.length);
     79  return [input.join("\n"), output.join("\n"), errors, fragment[0]];
     80 }
     81 
     82 /**
     83 * A generator function that accepts a list of strings. Each list
     84 * member corresponds to the contents of a ".dat" file from the
     85 * html5lib test suite.
     86 *
     87 * @param The list of strings
     88 */
     89 function* test_parser(testlist) {
     90  for (var testgroup of testlist) {
     91    var tests = testgroup.split("#data\n");
     92    tests = tests.filter(test => test).map(test => "#data\n" + test);
     93    for (var test of tests) {
     94      yield parseTestcase(test);
     95    }
     96  }
     97 }
     98 
     99 /**
    100 * Transforms a DOM document to a string matching the format in
    101 * the test cases.
    102 *
    103 * @param the DOM document
    104 */
    105 function docToTestOutput(doc) {
    106  var walker = doc.createTreeWalker(doc, NodeFilter.SHOW_ALL, null);
    107  return addLevels(walker, "", "| ").slice(0, -1); // remove the last newline
    108 }
    109 
    110 /**
    111 * Creates a walker for a fragment that skips over the root node.
    112 *
    113 * @param an element
    114 */
    115 function createFragmentWalker(elt) {
    116  return elt.ownerDocument.createTreeWalker(
    117    elt,
    118    NodeFilter.SHOW_ALL,
    119    function (node) {
    120      return elt == node ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_ACCEPT;
    121    }
    122  );
    123 }
    124 
    125 /**
    126 * Transforms the descendants of an element to a string matching the format
    127 * in the test cases.
    128 *
    129 * @param an element
    130 */
    131 function fragmentToTestOutput(elt) {
    132  var walker = createFragmentWalker(elt);
    133  return addLevels(walker, "", "| ").slice(0, -1); // remove the last newline
    134 }
    135 
    136 function addLevels(walker, buf, indent) {
    137  if (walker.firstChild()) {
    138    do {
    139      buf += indent;
    140      switch (walker.currentNode.nodeType) {
    141        case Node.ELEMENT_NODE:
    142          buf += "<";
    143          var ns = walker.currentNode.namespaceURI;
    144          if ("http://www.w3.org/1998/Math/MathML" == ns) {
    145            buf += "math ";
    146          } else if ("http://www.w3.org/2000/svg" == ns) {
    147            buf += "svg ";
    148          } else if ("http://www.w3.org/1999/xhtml" != ns) {
    149            buf += "otherns ";
    150          }
    151          buf += walker.currentNode.localName + ">";
    152          if (walker.currentNode.hasAttributes()) {
    153            var valuesByName = {};
    154            var attrs = walker.currentNode.attributes;
    155            for (let i = 0; i < attrs.length; ++i) {
    156              var localName = attrs[i].localName;
    157              var name;
    158              var attrNs = attrs[i].namespaceURI;
    159              if (null == attrNs) {
    160                name = localName;
    161              } else if ("http://www.w3.org/XML/1998/namespace" == attrNs) {
    162                name = "xml " + localName;
    163              } else if ("http://www.w3.org/1999/xlink" == attrNs) {
    164                name = "xlink " + localName;
    165              } else if ("http://www.w3.org/2000/xmlns/" == attrNs) {
    166                name = "xmlns " + localName;
    167              } else {
    168                name = "otherns " + localName;
    169              }
    170              valuesByName[name] = attrs[i].value;
    171            }
    172            var keys = Object.keys(valuesByName).sort();
    173            for (let i = 0; i < keys.length; ++i) {
    174              buf +=
    175                "\n" +
    176                indent +
    177                "  " +
    178                keys[i] +
    179                '="' +
    180                valuesByName[keys[i]] +
    181                '"';
    182            }
    183          }
    184          break;
    185        case Node.DOCUMENT_TYPE_NODE:
    186          buf += "<!DOCTYPE " + walker.currentNode.name;
    187          if (walker.currentNode.publicId || walker.currentNode.systemId) {
    188            buf += ' "';
    189            buf += walker.currentNode.publicId;
    190            buf += '" "';
    191            buf += walker.currentNode.systemId;
    192            buf += '"';
    193          }
    194          buf += ">";
    195          break;
    196        case Node.COMMENT_NODE:
    197          buf += "<!-- " + walker.currentNode.nodeValue + " -->";
    198          break;
    199        case Node.TEXT_NODE:
    200          buf += '"' + walker.currentNode.nodeValue + '"';
    201          break;
    202      }
    203      buf += "\n";
    204      // In the case of template elements, children do not get inserted as
    205      // children of the template element, instead they are inserted
    206      // as children of the template content (which is a document fragment).
    207      if (walker.currentNode.constructor.name === "HTMLTemplateElement") {
    208        buf += indent + "  content\n";
    209        // Walk through the template content.
    210        var templateWalker = createFragmentWalker(walker.currentNode.content);
    211        buf = addLevels(templateWalker, buf, indent + "    ");
    212      }
    213      buf = addLevels(walker, buf, indent + "  ");
    214    } while (walker.nextSibling());
    215    walker.parentNode();
    216  }
    217  return buf;
    218 }