tor-browser

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

original-harness.js (12106B)


      1 var ReflectionHarness = {};
      2 
      3 // @private
      4 ReflectionHarness.passed = document.getElementById("passed");
      5 ReflectionHarness.failed = document.getElementById("failed");
      6 
      7 /**
      8 * In conformance testing mode, all tests will be run.  Otherwise, we'll skip
      9 * tests for attributes that have an entirely incorrect type.
     10 */
     11 ReflectionHarness.conformanceTesting = false;
     12 
     13 /**
     14 * Returns a string representing val.  Basically just adds quotes for strings,
     15 * and passes through other recognized types literally.
     16 *
     17 * @public
     18 */
     19 ReflectionHarness.stringRep = function(val) {
     20  if (val === null) {
     21    // typeof is object, so the switch isn't useful
     22    return "null";
     23  }
     24  // In JavaScript, -0 === 0 and String(-0) == "0", so we have to
     25  // special-case.
     26  if (val === -0 && 1/val === -Infinity) {
     27    return "-0";
     28  }
     29  switch (typeof val) {
     30    case "string":
     31      for (var i = 0; i < 32; i++) {
     32        var replace = "\\";
     33        switch (i) {
     34          case 0: replace += "0"; break;
     35          case 1: replace += "x01"; break;
     36          case 2: replace += "x02"; break;
     37          case 3: replace += "x03"; break;
     38          case 4: replace += "x04"; break;
     39          case 5: replace += "x05"; break;
     40          case 6: replace += "x06"; break;
     41          case 7: replace += "x07"; break;
     42          case 8: replace += "b"; break;
     43          case 9: replace += "t"; break;
     44          case 10: replace += "n"; break;
     45          case 11: replace += "v"; break;
     46          case 12: replace += "f"; break;
     47          case 13: replace += "r"; break;
     48          case 14: replace += "x0e"; break;
     49          case 15: replace += "x0f"; break;
     50          case 16: replace += "x10"; break;
     51          case 17: replace += "x11"; break;
     52          case 18: replace += "x12"; break;
     53          case 19: replace += "x13"; break;
     54          case 20: replace += "x14"; break;
     55          case 21: replace += "x15"; break;
     56          case 22: replace += "x16"; break;
     57          case 23: replace += "x17"; break;
     58          case 24: replace += "x18"; break;
     59          case 25: replace += "x19"; break;
     60          case 26: replace += "x1a"; break;
     61          case 27: replace += "x1b"; break;
     62          case 28: replace += "x1c"; break;
     63          case 29: replace += "x1d"; break;
     64          case 30: replace += "x1e"; break;
     65          case 31: replace += "x1f"; break;
     66        }
     67        val = val.replace(String.fromCharCode(i), replace);
     68      }
     69      return '"' + val.replace('"', '\\"') + '"';
     70    case "boolean":
     71    case "undefined":
     72    case "number":
     73      return val + "";
     74    default:
     75      return typeof val + ' "' + val + '"';
     76  }
     77 }
     78 
     79 /**
     80 * An object representing info about the current test, used for printing out
     81 * nice messages and so forth.
     82 */
     83 ReflectionHarness.currentTestInfo = {};
     84 
     85 /**
     86 * .test() sets this, and it's used by .assertEquals()/.assertThrows().
     87 * Calling .test() recursively is an error.
     88 */
     89 ReflectionHarness.currentTestDescription = null;
     90 
     91 /**
     92 * Run a group of one or more assertions.  If any exceptions are thrown, catch
     93 * them and report a failure.
     94 */
     95 ReflectionHarness.test = function(fn, description) {
     96  if (this.currentTestDescription) {
     97    throw "TEST BUG: test() may not be called recursively!";
     98  }
     99  this.currentTestDescription = description;
    100  try {
    101    fn();
    102    // Not throwing is a success
    103    this.success();
    104  } catch(err) {
    105    this.failure("Exception thrown during tests with " + description);
    106  }
    107  this.currentTestDescription = null;
    108 }
    109 
    110 /**
    111 * If question === answer, output a success, else report a failure with the
    112 * given description.  Currently success and failure both increment counters,
    113 * and failures output a message to a <ul>.  Which <ul> is decided by the type
    114 * parameter -- different attribute types are separated for readability.
    115 *
    116 * @public
    117 */
    118 ReflectionHarness.assertEquals = function(expected, actual, description) {
    119  // Special-case -0 yay!
    120  if (expected === 0 && actual === 0 && 1/expected === 1/actual) {
    121    this.increment(this.passed);
    122  } else if (expected === actual) {
    123    this.increment(this.passed);
    124  } else {
    125    this.increment(this.failed);
    126    this.reportFailure(this.currentTestDescription +
    127        (description ? " followed by " + description : "") +
    128        ' (expected ' + this.stringRep(actual) + ', got ' +
    129        this.stringRep(expected) + ')');
    130  }
    131 }
    132 
    133 /**
    134 * If answer.includes(question), output a success, else report a failure with the
    135 * given description.  Currently success and failure both increment counters,
    136 * and failures output a message to a <ul>.  Which <ul> is decided by the type
    137 * parameter -- different attribute types are separated for readability.
    138 *
    139 * @public
    140 */
    141 ReflectionHarness.assertInArray = function(expected, actual, description) {
    142  if (actual.includes(expected)) {
    143    this.increment(this.passed);
    144  } else {
    145    this.increment(this.failed);
    146    this.reportFailure(this.currentTestDescription +
    147        (description ? " followed by " + description : "") +
    148        ' (expected one of ' + this.stringRep(actual) + ', got ' +
    149        this.stringRep(expected) + ')');
    150  }
    151 }
    152 
    153 /**
    154 * If calling fn causes a DOMException of the type given by the string
    155 * exceptionName (e.g., "IndexSizeError"), output a success.  Otherwise, report
    156 * a failure.
    157 *
    158 * @public
    159 */
    160 ReflectionHarness.assertThrows = function(exceptionName, fn) {
    161  try {
    162    fn();
    163  } catch (e) {
    164    if (e instanceof DOMException && (e.code == DOMException[exceptionName] ||
    165                                      e.name == exceptionName)) {
    166      this.increment(this.passed);
    167      return true;
    168    }
    169  }
    170  this.increment(this.failed);
    171  this.reportFailure(this.currentTestDescription + " must throw " +
    172      exceptionName);
    173  return false;
    174 }
    175 
    176 /**
    177 * Get a description of the current type, e.g., "a.href".
    178 */
    179 ReflectionHarness.getTypeDescription = function() {
    180  var domNode = this.currentTestInfo.domObj.tagName.toLowerCase();
    181  var idlNode = this.currentTestInfo.idlObj.nodeName.toLowerCase();
    182  var domName = this.currentTestInfo.domName;
    183  var idlName = this.currentTestInfo.idlName;
    184  var comment = this.currentTestInfo.data.comment;
    185  var typeDesc = idlNode + "." + idlName;
    186  if (!comment && (domNode != idlNode || domName != idlName)) {
    187    comment = "<" + domNode + " " + domName + ">";
    188  }
    189  if (comment) {
    190    typeDesc += " (" + comment + ")";
    191  }
    192  return typeDesc;
    193 }
    194 
    195 /**
    196 * Report a failure with the given description, adding context from the
    197 * currentTestInfo member.
    198 *
    199 * @private
    200 */
    201 ReflectionHarness.reportFailure = function(description) {
    202  var typeDesc = this.getTypeDescription();
    203  var idlName = this.currentTestInfo.idlName;
    204  var comment = this.currentTestInfo.data.comment;
    205  typeDesc = typeDesc.replace("&", "&amp;").replace("<", "&lt;");
    206  description = description.replace("&", "&amp;").replace("<", "&lt;");
    207 
    208  var type = this.currentTestInfo.data.type;
    209 
    210  // Special case for undefined attributes, which we don't want getting in
    211  // the way of everything else.
    212  if (description.search('^typeof IDL attribute \\(expected ".*", got "undefined"\\)$') != -1) {
    213    type = "undefined";
    214  }
    215 
    216  var done = false;
    217  var ul = document.getElementById("errors-" + type.replace(" ", "-"));
    218  if (ul === null) {
    219    ul = document.createElement("ul");
    220    ul.id = "errors-" + type.replace(" ", "-");
    221    var div = document.getElementById("errors");
    222    p = document.createElement("p");
    223    if (type == "undefined") {
    224      div.parentNode.insertBefore(ul, div.nextSibling);
    225      p.innerHTML = "These IDL attributes were of undefined type, presumably representing unimplemented features (cordoned off into a separate section for tidiness):";
    226    } else {
    227      div.appendChild(ul);
    228      p.innerHTML = "Errors for type " + type + ":";
    229    }
    230    ul.parentNode.insertBefore(p, ul);
    231  } else if (type != "undefined") {
    232    var existingErrors = ul.getElementsByClassName("desc");
    233    for (var i = 0; i < existingErrors.length; i++) {
    234      if (existingErrors[i].innerHTML == description) {
    235        var typeSpan = existingErrors[i].parentNode.getElementsByClassName("type")[0];
    236        // Check if we have lots of the same error for the same
    237        // attribute.  If so, we want to collapse them -- the exact
    238        // elements that exhibit the error aren't going to be important
    239        // to report in this case, and it can take a lot of space if
    240        // there's an error in a global attribute like dir or id.
    241        var types = typeSpan.innerHTML.split(", ");
    242        var count = 0;
    243        for (var i = 0; i < types.length; i++) {
    244          if (types[i].search("^\\([0-9]* elements\\)\\." + idlName + "$") != -1) {
    245            types[i] = "(" + (1 + parseInt(/[0-9]+/.exec(types[i])[0])) + " elements)." + idlName;
    246            typeSpan.innerHTML = types.join(", ");
    247            return;
    248          } else if (types[i].search("\\." + idlName + "$") != -1) {
    249            count++;
    250          }
    251        }
    252        if (comment || count < 10) {
    253          // Just add the extra error to the end, not many duplicates
    254          // (or we have a comment)
    255          typeSpan.innerHTML += ", " + typeDesc;
    256        } else {
    257          var filteredTypes = types.filter(function(type) { return type.search("\\." + idlName + "$") == -1; });
    258          if (filteredTypes.length) {
    259            typeSpan.innerHTML = filteredTypes.join(", ") + ", ";
    260          } else {
    261            typeSpan.innerHTML = "";
    262          }
    263          typeSpan.innerHTML += "(" + (types.length - filteredTypes.length) + " elements)." + idlName;
    264        }
    265        return;
    266      }
    267    }
    268  }
    269 
    270  if (type == "undefined") {
    271    ul.innerHTML += "<li>" + typeDesc;
    272  } else {
    273    ul.innerHTML += "<li><span class=\"type\">" + typeDesc + "</span>: <span class=\"desc\">" + description + "</span>";
    274  }
    275 }
    276 
    277 /**
    278 * Shorthand function for when we have a failure outside of
    279 * assertEquals()/assertThrows().  Generally used when the failure is an
    280 * exception thrown unexpectedly or such, something not equality-based.
    281 *
    282 * @public
    283 */
    284 ReflectionHarness.failure = function(message) {
    285  this.increment(this.failed);
    286  this.reportFailure(message);
    287 }
    288 
    289 /**
    290 * Shorthand function for when we have a success outside of
    291 * assertEquals()/assertThrows().
    292 *
    293 * @public
    294 */
    295 ReflectionHarness.success = function() {
    296  this.increment(this.passed);
    297 }
    298 
    299 /**
    300 * Increment the count in either "passed" or "failed".  el should always be one
    301 * of those two variables.  The implementation of this function amuses me.
    302 *
    303 * @private
    304 */
    305 ReflectionHarness.increment = function(el) {
    306  el.innerHTML = parseInt(el.innerHTML) + 1;
    307  var percent = document.getElementById("percent");
    308  var passed = document.getElementById("passed");
    309  var failed = document.getElementById("failed");
    310  percent.innerHTML = (parseInt(passed.innerHTML)/(parseInt(passed.innerHTML) + parseInt(failed.innerHTML))*100).toPrecision(3);
    311 }
    312 
    313 /**
    314 * Hide all displayed errors matching a given regex, so it's easier to filter
    315 * out repetitive failures.  TODO: Fix this so it works right with the new
    316 * "lump many errors in one <li>" thing.
    317 *
    318 * @private (kind of, only called in the original reflection.html)
    319 */
    320 ReflectionHarness.maskErrors = function(regex) {
    321  var uls = document.getElementsByTagName("ul");
    322  for (var i = 0; i < uls.length; i++) {
    323    var lis = uls[i].children;
    324    for (var j = 0; j < lis.length; j++) {
    325      if (regex !== "" && lis[j].innerHTML.match(regex)) {
    326        lis[j].style.display = "none";
    327      } else {
    328        lis[j].style.display = "list-item";
    329      }
    330    }
    331  }
    332 }
    333 
    334 // Now for some stuff that has nothing to do with ReflectionHarness and
    335 // everything to do with initialization needed for reflection.js, which seems
    336 // pointless to put in an extra file.
    337 
    338 var elements = {};
    339 
    340 var extraTests = [];
    341 
    342 /**
    343 * Used for combining a number of small arrays of element data into one big
    344 * one.
    345 */
    346 function mergeElements(src) {
    347  for (var key in src) {
    348    if (!src.hasOwnProperty(key)) {
    349      // This is inherited from a prototype or something.
    350      continue;
    351    }
    352 
    353    if (key in elements) {
    354      elements[key] = elements[key].concat(src[key]);
    355    } else {
    356      elements[key] = src[key];
    357    }
    358  }
    359 }