tor-browser

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

defineProperty-setup.js (29521B)


      1 // |reftest| skip -- not a test.
      2 // Any copyright is dedicated to the Public Domain.
      3 // http://creativecommons.org/licenses/publicdomain/
      4 
      5 assertEq("defineProperty" in Object, true);
      6 assertEq(Object.defineProperty.length, 3);
      7 
      8 /*
      9 * Disable an assertion that is pathologically slow given the exhaustiveness of
     10 * these tests.
     11 */
     12 if (typeof enableStackWalkingAssertion === "function")
     13  enableStackWalkingAssertion(false);
     14 
     15 if (!Object.prototype.toSource)
     16 {
     17  Object.defineProperty(Object.prototype, "toSource",
     18  {
     19    value: function toSource()
     20    {
     21      if (this instanceof RegExp)
     22      {
     23        var v = "new RegExp(" + uneval(this.source);
     24        var f = (this.multiline ? "m" : "") +
     25                (this.global ? "g" : "") +
     26                (this.ignoreCase ? "i" : "");
     27        return v + (f ? ", '" + f + "'" : "") + ")";
     28      }
     29      return JSON.stringify(this);
     30    },
     31    enumerable: false,
     32    configurable: true,
     33    writable: true
     34  });
     35 }
     36 if (!("uneval" in this))
     37 {
     38  Object.defineProperty(this, "uneval",
     39  {
     40    value: function uneval(v)
     41    {
     42      if (v === null)
     43        return "null";
     44      if (typeof v === "object")
     45        return v.toSource();
     46      if (typeof v === "string")
     47      {
     48        v = JSON.stringify({v:v});
     49        return v.substring(5, v.length - 1);
     50      }
     51      return "" + v;
     52    },
     53    enumerable: false,
     54    configurable: true,
     55    writable: true
     56  });
     57 }
     58 
     59 // reimplemented for the benefit of engines which don't have this helper
     60 function assertEq(v1, v2, m)
     61 {
     62  if (!SameValue(v1, v2))
     63  {
     64    throw "assertion failed: " +
     65          "got " + uneval(v1) + ", expected " + uneval(v2) +
     66          (m ? ": " + m : "");
     67  }
     68 }
     69 
     70 function SameValue(v1, v2)
     71 {
     72  if (v1 === 0 && v2 === 0)
     73    return 1 / v1 === 1 / v2;
     74  if (v1 !== v1 && v2 !== v2)
     75    return true;
     76  return v1 === v2;
     77 }
     78 
     79 function PropertyDescriptor(pd)
     80 {
     81  if (pd)
     82    this.update(pd);
     83 }
     84 PropertyDescriptor.prototype.update = function update(pd)
     85 {
     86  if ("get" in pd)
     87    this.get = pd.get;
     88  if ("set" in pd)
     89    this.set = pd.set;
     90  if ("configurable" in pd)
     91    this.configurable = pd.configurable;
     92  if ("writable" in pd)
     93    this.writable = pd.writable;
     94  if ("enumerable" in pd)
     95    this.enumerable = pd.enumerable;
     96  if ("value" in pd)
     97    this.value = pd.value;
     98 };
     99 PropertyDescriptor.prototype.convertToDataDescriptor = function convertToDataDescriptor()
    100 {
    101  delete this.get;
    102  delete this.set;
    103  this.writable = false;
    104  this.value = undefined;
    105 };
    106 PropertyDescriptor.prototype.convertToAccessorDescriptor = function convertToAccessorDescriptor()
    107 {
    108  delete this.writable;
    109  delete this.value;
    110  this.get = undefined;
    111  this.set = undefined;
    112 };
    113 
    114 function compareDescriptors(d1, d2)
    115 {
    116  if (d1 === undefined)
    117  {
    118    assertEq(d2, undefined, "non-descriptors");
    119    return;
    120  }
    121  if (d2 === undefined)
    122  {
    123    assertEq(true, false, "descriptor-equality mismatch: " + uneval(d1) + ", " + uneval(d2));
    124    return;
    125  }
    126 
    127  var props = ["value", "get", "set", "enumerable", "configurable", "writable"];
    128  for (var i = 0, sz = props.length; i < sz; i++)
    129  {
    130    var p = props[i];
    131    assertEq(p in d1, p in d2, p + " different in d1/d2");
    132    if (p in d1)
    133      assertEq(d1[p], d2[p], p);
    134  }
    135 }
    136 
    137 function examine(desc, field, allowDefault)
    138 {
    139  if (field in desc)
    140    return desc[field];
    141  assertEq(allowDefault, true, "reimplementation error");
    142  switch (field)
    143  {
    144    case "value":
    145    case "get":
    146    case "set":
    147      return undefined;
    148    case "writable":
    149    case "enumerable":
    150    case "configurable":
    151      return false;
    152    default:
    153      assertEq(true, false, "bad field name: " + field);
    154  }
    155 }
    156 
    157 function IsAccessorDescriptor(desc)
    158 {
    159  if (!desc)
    160    return false;
    161  if (!("get" in desc) && !("set" in desc))
    162    return false;
    163  return true;
    164 }
    165 
    166 function IsDataDescriptor(desc)
    167 {
    168  if (!desc)
    169    return false;
    170  if (!("value" in desc) && !("writable" in desc))
    171    return false;
    172  return true;
    173 }
    174 
    175 function IsGenericDescriptor(desc)
    176 {
    177  if (!desc)
    178    return false;
    179  if (!IsAccessorDescriptor(desc) && !IsDataDescriptor(desc))
    180    return true;
    181  return false;
    182 }
    183 
    184 
    185 
    186 function CustomObject()
    187 {
    188  this.properties = {};
    189  this.extensible = true;
    190 }
    191 CustomObject.prototype =
    192 {
    193  _reject: function _reject(throwing, msg)
    194  {
    195    if (throwing)
    196      throw new TypeError(msg + "; rejected!");
    197    return false;
    198  },
    199  defineOwnProperty: function defineOwnProperty(propname, desc, throwing)
    200  {
    201    assertEq(typeof propname, "string", "non-string propname");
    202 
    203    // Step 1.
    204    var current = this.properties[propname];
    205 
    206    // Step 2.
    207    var extensible = this.extensible;
    208 
    209    // Step 3.
    210    if (current === undefined && !extensible)
    211      return this._reject(throwing, "object not extensible");
    212 
    213    // Step 4.
    214    if (current === undefined && extensible)
    215    {
    216      var p;
    217      // Step 4(a).
    218      if (IsGenericDescriptor(desc) || IsDataDescriptor(desc))
    219      {
    220        p = new PropertyDescriptor();
    221        p.value = examine(desc, "value", true);
    222        p.writable = examine(desc, "writable", true);
    223        p.enumerable = examine(desc, "enumerable", true);
    224        p.configurable = examine(desc, "configurable", true);
    225      }
    226      // Step 4(b).
    227      else
    228      {
    229        p = new PropertyDescriptor();
    230        p.get = examine(desc, "get", true);
    231        p.set = examine(desc, "set", true);
    232        p.enumerable = examine(desc, "enumerable", true);
    233        p.configurable = examine(desc, "configurable", true);
    234      }
    235 
    236      this.properties[propname] = p;
    237 
    238      // Step 4(c).
    239      return true;
    240    }
    241 
    242    // Step 5.
    243    if (!("value" in desc) && !("get" in desc) && !("set" in desc) &&
    244        !("writable" in desc) && !("enumerable" in desc) &&
    245        !("configurable" in desc))
    246    {
    247      return;
    248    }
    249 
    250    // Step 6.
    251    do
    252    {
    253      if ("value" in desc)
    254      {
    255        if (!("value" in current) || !SameValue(desc.value, current.value))
    256          break;
    257      }
    258      if ("get" in desc)
    259      {
    260        if (!("get" in current) || !SameValue(desc.get, current.get))
    261          break;
    262      }
    263      if ("set" in desc)
    264      {
    265        if (!("set" in current) || !SameValue(desc.set, current.set))
    266          break;
    267      }
    268      if ("writable" in desc)
    269      {
    270        if (!("writable" in current) ||
    271            !SameValue(desc.writable, current.writable))
    272        {
    273          break;
    274        }
    275      }
    276      if ("enumerable" in desc)
    277      {
    278        if (!("enumerable" in current) ||
    279            !SameValue(desc.enumerable, current.enumerable))
    280        {
    281          break;
    282        }
    283      }
    284      if ("configurable" in desc)
    285      {
    286        if (!("configurable" in current) ||
    287            !SameValue(desc.configurable, current.configurable))
    288        {
    289          break;
    290        }
    291      }
    292 
    293      // all fields in desc also in current, with the same values
    294      return true;
    295    }
    296    while (false);
    297 
    298    // Step 7.
    299    if (!examine(current, "configurable"))
    300    {
    301      if ("configurable" in desc && examine(desc, "configurable"))
    302        return this._reject(throwing, "can't make configurable again");
    303      if ("enumerable" in desc &&
    304          examine(current, "enumerable") !== examine(desc, "enumerable"))
    305      {
    306        return this._reject(throwing, "can't change enumerability");
    307      }
    308    }
    309 
    310    // Step 8.
    311    if (IsGenericDescriptor(desc))
    312    {
    313      // do nothing
    314    }
    315    // Step 9.
    316    else if (IsDataDescriptor(current) !== IsDataDescriptor(desc))
    317    {
    318      // Step 9(a).
    319      if (!examine(current, "configurable"))
    320        return this._reject(throwing, "can't change unconfigurable descriptor's type");
    321      // Step 9(b).
    322      if (IsDataDescriptor(current))
    323        current.convertToAccessorDescriptor();
    324      // Step 9(c).
    325      else
    326        current.convertToDataDescriptor();
    327    }
    328    // Step 10.
    329    else if (IsDataDescriptor(current) && IsDataDescriptor(desc))
    330    {
    331      // Step 10(a)
    332      if (!examine(current, "configurable"))
    333      {
    334        // Step 10(a).i.
    335        if (!examine(current, "writable") &&
    336            "writable" in desc && examine(desc, "writable"))
    337        {
    338          return this._reject(throwing, "can't make data property writable again");
    339        }
    340        // Step 10(a).ii.
    341        if (!examine(current, "writable"))
    342        {
    343          if ("value" in desc &&
    344              !SameValue(examine(desc, "value"), examine(current, "value")))
    345          {
    346            return this._reject(throwing, "can't change value if not writable");
    347          }
    348        }
    349      }
    350      // Step 10(b).
    351      else
    352      {
    353        assertEq(examine(current, "configurable"), true,
    354                 "spec bug step 10(b)");
    355      }
    356    }
    357    // Step 11.
    358    else
    359    {
    360      assertEq(IsAccessorDescriptor(current) && IsAccessorDescriptor(desc),
    361               true,
    362               "spec bug");
    363 
    364      // Step 11(a).
    365      if (!examine(current, "configurable"))
    366      {
    367        // Step 11(a).i.
    368        if ("set" in desc &&
    369            !SameValue(examine(desc, "set"), examine(current, "set")))
    370        {
    371          return this._reject(throwing, "can't change setter if not configurable");
    372        }
    373        // Step 11(a).ii.
    374        if ("get" in desc &&
    375            !SameValue(examine(desc, "get"), examine(current, "get")))
    376        {
    377          return this._reject(throwing, "can't change getter if not configurable");
    378        }
    379      }
    380    }
    381 
    382    // Step 12.
    383    current.update(desc);
    384 
    385    // Step 13.
    386    return true;
    387  }
    388 };
    389 
    390 function IsCallable(v)
    391 {
    392  return typeof v === "undefined" || typeof v === "function";
    393 }
    394 
    395 var NativeTest =
    396  {
    397    newObject: function newObject()
    398    {
    399      return {};
    400    },
    401    defineProperty: function defineProperty(obj, propname, propdesc)
    402    {
    403      Object.defineProperty(obj, propname, propdesc);
    404    },
    405    getDescriptor: function getDescriptor(obj, propname)
    406    {
    407      return Object.getOwnPropertyDescriptor(obj, propname);
    408    }
    409  };
    410 
    411 var ReimplTest =
    412  {
    413    newObject: function newObject()
    414    {
    415      return new CustomObject();
    416    },
    417    defineProperty: function defineProperty(obj, propname, propdesc)
    418    {
    419      assertEq(obj instanceof CustomObject, true, "obj not instanceof CustomObject");
    420      if ("get" in propdesc || "set" in propdesc)
    421      {
    422        if ("value" in propdesc || "writable" in propdesc)
    423          throw new TypeError("get/set and value/writable");
    424        if (!IsCallable(propdesc.get))
    425          throw new TypeError("get defined, uncallable");
    426        if (!IsCallable(propdesc.set))
    427          throw new TypeError("set defined, uncallable");
    428      }
    429      return obj.defineOwnProperty(propname, propdesc, true);
    430    },
    431    getDescriptor: function getDescriptor(obj, propname)
    432    {
    433      if (!(propname in obj.properties))
    434        return undefined;
    435 
    436      return new PropertyDescriptor(obj.properties[propname]);
    437    }
    438  };
    439 
    440 var JSVAL_INT_MAX = Math.pow(2, 30) - 1;
    441 var JSVAL_INT_MIN = -Math.pow(2, 30);
    442 
    443 
    444 function isValidDescriptor(propdesc)
    445 {
    446  if ("get" in propdesc || "set" in propdesc)
    447  {
    448    if ("value" in propdesc || "writable" in propdesc)
    449      return false;
    450 
    451    // We permit null here simply because this test's author believes the
    452    // implementation may sometime be susceptible to making mistakes in this
    453    // regard and would prefer to be cautious.
    454    if (propdesc.get !== null && propdesc.get !== undefined && !IsCallable(propdesc.get))
    455      return false;
    456    if (propdesc.set !== null && propdesc.set !== undefined && !IsCallable(propdesc.set))
    457      return false;
    458  }
    459 
    460  return true;
    461 }
    462 
    463 
    464 var OMIT = {};
    465 var VALUES =
    466  [-Infinity, JSVAL_INT_MIN, -0, +0, 1.5, JSVAL_INT_MAX, Infinity,
    467   NaN, "foo", "bar", null, undefined, true, false, {}, /a/, OMIT];
    468 var GETS =
    469  [undefined, function get1() { return 1; }, function get2() { return 2; },
    470   null, 5, OMIT];
    471 var SETS =
    472  [undefined, function set1() { return 1; }, function set2() { return 2; },
    473   null, 5, OMIT];
    474 var ENUMERABLES = [true, false, OMIT];
    475 var CONFIGURABLES = [true, false, OMIT];
    476 var WRITABLES = [true, false, OMIT];
    477 
    478 function mapTestDescriptors(filter)
    479 {
    480  var descs = [];
    481  var desc = {};
    482 
    483  function put(field, value)
    484  {
    485    if (value !== OMIT)
    486      desc[field] = value;
    487  }
    488 
    489  VALUES.forEach(function(value)
    490  {
    491    GETS.forEach(function(get)
    492    {
    493      SETS.forEach(function(set)
    494      {
    495        ENUMERABLES.forEach(function(enumerable)
    496        {
    497          CONFIGURABLES.forEach(function(configurable)
    498          {
    499            WRITABLES.forEach(function(writable)
    500            {
    501              desc = {};
    502              put("value", value);
    503              put("get", get);
    504              put("set", set);
    505              put("enumerable", enumerable);
    506              put("configurable", configurable);
    507              put("writable", writable);
    508              if (filter(desc))
    509                descs.push(desc);
    510            });
    511          });
    512        });
    513      });
    514    });
    515  });
    516 
    517  return descs;
    518 }
    519 
    520 var ALL_DESCRIPTORS = mapTestDescriptors(function(d) { return true; });
    521 var VALID_DESCRIPTORS = mapTestDescriptors(isValidDescriptor);
    522 
    523 function TestRunner()
    524 {
    525  this._logLines = [];
    526 }
    527 TestRunner.prototype =
    528  {
    529    // MAIN METHODS
    530 
    531    runFunctionLengthTests: function runFunctionLengthTests()
    532    {
    533      var self = this;
    534      function functionLengthTests()
    535      {
    536        self._fullFunctionLengthTests(() => Function("one", "/* body */"), 1);
    537        self._fullFunctionLengthTests(() => function(one, two, three=null) { }, 2);
    538        self._fullFunctionLengthTests(() => (one, two, ...etc) => 0, 2);
    539        self._fullFunctionLengthTests(() => ({method(){}}.method), 0);
    540        self._fullFunctionLengthTests(() => Object.getOwnPropertyDescriptor({set x(v){}}, "x").set, 1);
    541      }
    542 
    543      this._runTestSet(functionLengthTests, "Function length tests completed!");
    544    },
    545 
    546    runNotPresentTests: function runNotPresentTests()
    547    {
    548      var self = this;
    549      function notPresentTests()
    550      {
    551        print("Running not-present tests now...");
    552 
    553        for (var i = 0, sz = ALL_DESCRIPTORS.length; i < sz; i++)
    554          self._runSingleNotPresentTest(ALL_DESCRIPTORS[i]);
    555      };
    556 
    557      this._runTestSet(notPresentTests, "Not-present length tests completed!");
    558    },
    559 
    560    runPropertyPresentTestsFraction:
    561    function runPropertyPresentTestsFraction(part, parts)
    562    {
    563      var self = this;
    564      function propertyPresentTests()
    565      {
    566        print("Running already-present tests now...");
    567 
    568        var total = VALID_DESCRIPTORS.length;
    569        var start = Math.floor((part - 1) / parts * total);
    570        var end = Math.floor(part / parts * total);
    571 
    572        for (var i = start; i < end; i++)
    573        {
    574          var old = VALID_DESCRIPTORS[i];
    575          print("Starting test with old descriptor " + old.toSource() + "...");
    576 
    577          for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
    578            self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []);
    579        }
    580      }
    581 
    582      this._runTestSet(propertyPresentTests,
    583                       "Property-present fraction " + part + " of " + parts +
    584                       " completed!");
    585    },
    586 
    587    runNonTerminalPropertyPresentTestsFraction:
    588    function runNonTerminalPropertyPresentTestsFraction(part, parts)
    589    {
    590      var self = this;
    591 
    592      /*
    593       * A plain old property to define on the object before redefining the
    594       * originally-added property, to test redefinition of a property that's
    595       * not also lastProperty.  NB: we could loop over every possible
    596       * descriptor here if we wanted, even try adding more than one, but we'd
    597       * hit cubic complexity and worse, and SpiderMonkey only distinguishes by
    598       * the mere presence of the middle property, not its precise details.
    599       */
    600      var middleDefines =
    601        [{
    602           property: "middle",
    603           descriptor:
    604             { value: 17, writable: true, configurable: true, enumerable: true }
    605         }];
    606 
    607      function nonTerminalPropertyPresentTests()
    608      {
    609        print("Running non-terminal already-present tests now...");
    610 
    611        var total = VALID_DESCRIPTORS.length;
    612        var start = Math.floor((part - 1) / parts * total);
    613        var end = Math.floor(part / parts * total);
    614 
    615        for (var i = start; i < end; i++)
    616        {
    617          var old = VALID_DESCRIPTORS[i];
    618          print("Starting test with old descriptor " + old.toSource() + "...");
    619 
    620          for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
    621          {
    622            self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j],
    623                                               middleDefines);
    624          }
    625        }
    626      }
    627 
    628      this._runTestSet(nonTerminalPropertyPresentTests,
    629                       "Non-terminal property-present fraction " +
    630                       part + " of " + parts + " completed!");
    631    },
    632 
    633    runDictionaryPropertyPresentTestsFraction:
    634    function runDictionaryPropertyPresentTestsFraction(part, parts)
    635    {
    636      var self = this;
    637 
    638      /*
    639       * Add and readd properties such that the scope for the object is in
    640       * dictionary mode.
    641       */
    642      var middleDefines =
    643        [
    644         {
    645           property: "mid1",
    646           descriptor:
    647             { value: 17, writable: true, configurable: true, enumerable: true }
    648         },
    649         {
    650           property: "mid2",
    651           descriptor:
    652             { value: 17, writable: true, configurable: true, enumerable: true }
    653         },
    654         {
    655           property: "mid1",
    656           descriptor:
    657             { get: function g() { }, set: function s(v){}, configurable: false,
    658               enumerable: true }
    659         },
    660         ];
    661 
    662      function dictionaryPropertyPresentTests()
    663      {
    664        print("Running dictionary already-present tests now...");
    665 
    666        var total = VALID_DESCRIPTORS.length;
    667        var start = Math.floor((part - 1) / parts * total);
    668        var end = Math.floor(part / parts * total);
    669 
    670        for (var i = start; i < end; i++)
    671        {
    672          var old = VALID_DESCRIPTORS[i];
    673          print("Starting test with old descriptor " + old.toSource() + "...");
    674 
    675          for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
    676          {
    677            self._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j],
    678                                               middleDefines);
    679          }
    680        }
    681      }
    682 
    683      this._runTestSet(dictionaryPropertyPresentTests,
    684                       "Dictionary property-present fraction " +
    685                       part + " of " + parts + " completed!");
    686    },
    687 
    688 
    689    // HELPERS
    690 
    691    runPropertyPresentTests: function runPropertyPresentTests()
    692    {
    693      print("Running already-present tests now...");
    694 
    695      for (var i = 0, sz = VALID_DESCRIPTORS.length; i < sz; i++)
    696      {
    697        var old = VALID_DESCRIPTORS[i];
    698        print("Starting test with old descriptor " + old.toSource() + "...");
    699 
    700        for (var j = 0, sz2 = VALID_DESCRIPTORS.length; j < sz2; j++)
    701          this._runSinglePropertyPresentTest(old, VALID_DESCRIPTORS[j], []);
    702      }
    703    },
    704    _runTestSet: function _runTestSet(fun, completeMessage)
    705    {
    706      try
    707      {
    708        fun();
    709 
    710        print(completeMessage);
    711      }
    712      catch (e)
    713      {
    714        print("ERROR, EXITING (line " + (e.lineNumber || -1) + "): " + e);
    715        throw e;
    716      }
    717      finally
    718      {
    719        this._reportAllErrors();
    720      }
    721    },
    722    _reportAllErrors: function _reportAllErrors()
    723    {
    724      var errorCount = this._logLines.length;
    725      print("Full accumulated number of errors: " + errorCount);
    726      if (errorCount > 0)
    727        throw errorCount + " errors detected, FAIL";
    728    },
    729    _fullFunctionLengthTests: function _fullFunctionLengthTests(funFactory, len)
    730    {
    731      print("Running Function.length (" + funFactory + ") tests now...");
    732 
    733      for (var i = 0, sz = VALID_DESCRIPTORS.length; i < sz; i++)
    734      {
    735        var desc = VALID_DESCRIPTORS[i];
    736        this._runSingleFunctionLengthTest(funFactory(), len, desc);
    737      }
    738    },
    739    _log: function _log(v)
    740    {
    741      var m = "" + v;
    742      print(m);
    743      this._logLines.push(m);
    744    },
    745    _runSingleNotPresentTest: function _runSingleNotPresentTest(desc)
    746    {
    747      var nativeObj = NativeTest.newObject();
    748      var reimplObj = ReimplTest.newObject();
    749 
    750      try
    751      {
    752        NativeTest.defineProperty(nativeObj, "foo", desc);
    753      }
    754      catch (e)
    755      {
    756        try
    757        {
    758          ReimplTest.defineProperty(reimplObj, "foo", desc);
    759        }
    760        catch (e2)
    761        {
    762          if (e.constructor !== e2.constructor)
    763          {
    764            this._log("Difference when comparing native/reimplementation " +
    765                      "behavior for new descriptor " + desc.toSource() +
    766                      ", native threw " + e + ", reimpl threw " + e2);
    767          }
    768          return;
    769        }
    770        this._log("Difference when comparing native/reimplementation " +
    771                  "behavior for new descriptor " + desc.toSource() +
    772                  ", error " + e);
    773        return;
    774      }
    775 
    776      try
    777      {
    778        ReimplTest.defineProperty(reimplObj, "foo", desc);
    779      }
    780      catch (e)
    781      {
    782        this._log("Reimpl threw defining new descriptor " + desc.toSource() +
    783                  ", error: " + e);
    784        return;
    785      }
    786 
    787      var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo");
    788      var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo");
    789      try
    790      {
    791        compareDescriptors(nativeDesc, reimplDesc);
    792      }
    793      catch (e)
    794      {
    795        this._log("Difference comparing returned descriptors for new " +
    796                  "property defined with descriptor " + desc.toSource() +
    797                  "; error: " + e);
    798        return;
    799      }
    800    },
    801    _runSinglePropertyPresentTest:
    802    function _runSinglePropertyPresentTest(old, add, middleDefines)
    803    {
    804      var nativeObj = NativeTest.newObject();
    805      var reimplObj = ReimplTest.newObject();
    806 
    807      try
    808      {
    809        NativeTest.defineProperty(nativeObj, "foo", old);
    810      }
    811      catch (e)
    812      {
    813        if (!SameValue(NativeTest.getDescriptor(nativeObj, "foo"), undefined))
    814        {
    815          this._log("defining bad property descriptor: " + old.toSource());
    816          return;
    817        }
    818 
    819        try
    820        {
    821          ReimplTest.defineProperty(reimplObj, "foo", old);
    822        }
    823        catch (e2)
    824        {
    825          if (!SameValue(ReimplTest.getDescriptor(reimplObj, "foo"),
    826                         undefined))
    827          {
    828            this._log("defining bad property descriptor: " + old.toSource() +
    829                      "; reimplObj: " + uneval(reimplObj));
    830          }
    831 
    832          if (e.constructor !== e2.constructor)
    833          {
    834            this._log("Different errors defining bad property descriptor: " +
    835                      old.toSource() + "; native threw " + e + ", reimpl " +
    836                      "threw " + e2);
    837          }
    838 
    839          return;
    840        }
    841 
    842        this._log("Difference defining a property with descriptor " +
    843                  old.toSource() + ", error " + e);
    844        return;
    845      }
    846 
    847      try
    848      {
    849        ReimplTest.defineProperty(reimplObj, "foo", old);
    850      }
    851      catch (e)
    852      {
    853        this._log("Difference when comparing native/reimplementation " +
    854                  "behavior when adding descriptor " + add.toSource() +
    855                  ", error: " + e);
    856        return;
    857      }
    858 
    859      // Now add (or even readd) however many properties were specified between
    860      // the original property to add and the new one, to test redefining
    861      // non-last-properties and properties in scopes in dictionary mode.
    862      for (var i = 0, sz = middleDefines.length; i < sz; i++)
    863      {
    864        var middle = middleDefines[i];
    865        var prop = middle.property;
    866        var desc = middle.descriptor;
    867 
    868        try
    869        {
    870          NativeTest.defineProperty(nativeObj, prop, desc);
    871          ReimplTest.defineProperty(reimplObj, prop, desc);
    872        }
    873        catch (e)
    874        {
    875          this._log("failure defining middle descriptor: " + desc.toSource() +
    876                    ", error " + e);
    877          return;
    878        }
    879 
    880        // Sanity check
    881        var nativeDesc = NativeTest.getDescriptor(nativeObj, prop);
    882        var reimplDesc = ReimplTest.getDescriptor(reimplObj, prop);
    883 
    884        compareDescriptors(nativeDesc, reimplDesc);
    885        compareDescriptors(nativeDesc, desc);
    886      }
    887 
    888      try
    889      {
    890        NativeTest.defineProperty(nativeObj, "foo", add);
    891      }
    892      catch (e)
    893      {
    894        try
    895        {
    896          ReimplTest.defineProperty(reimplObj, "foo", add);
    897        }
    898        catch (e2)
    899        {
    900          if (e.constructor !== e2.constructor)
    901          {
    902            this._log("Difference when comparing native/reimplementation " +
    903                      "behavior for descriptor " + add.toSource() +
    904                      " overwriting descriptor " + old.toSource() + "; " +
    905                      "native threw " + e + ", reimpl threw " + e2);
    906          }
    907          return;
    908        }
    909        this._log("Difference when comparing native/reimplementation " +
    910                  "behavior for added descriptor " + add.toSource() + ", " +
    911                  "initial was " + old.toSource() + "; error: " + e);
    912        return;
    913      }
    914 
    915      try
    916      {
    917        ReimplTest.defineProperty(reimplObj, "foo", add);
    918      }
    919      catch (e)
    920      {
    921        this._log("Difference when comparing native/reimplementation " +
    922                  "behavior for readded descriptor " + add.toSource() + ", " +
    923                  "initial was " + old.toSource() + "; native readd didn't " +
    924                  "throw, reimpl add did, error: " + e);
    925        return;
    926      }
    927 
    928      var nativeDesc = NativeTest.getDescriptor(nativeObj, "foo");
    929      var reimplDesc = ReimplTest.getDescriptor(reimplObj, "foo");
    930      try
    931      {
    932        compareDescriptors(nativeDesc, reimplDesc);
    933      }
    934      catch (e)
    935      {
    936        this._log("Difference comparing returned descriptors for readded " +
    937                  "property defined with descriptor " + add.toSource() + "; " +
    938                  "initial was " + old.toSource() + "; error: " + e);
    939        return;
    940      }
    941    },
    942    _runSingleFunctionLengthTest: function _runSingleFunctionLengthTest(fun, len, desc)
    943    {
    944      var nativeObj = fun;
    945      var reimplObj = ReimplTest.newObject();
    946      ReimplTest.defineProperty(reimplObj, "length",
    947      {
    948        value: len,
    949        enumerable: false,
    950        configurable: true,
    951        writable: false
    952      });
    953 
    954      try
    955      {
    956        NativeTest.defineProperty(nativeObj, "length", desc);
    957      }
    958      catch (e)
    959      {
    960        try
    961        {
    962          ReimplTest.defineProperty(reimplObj, "length", desc);
    963        }
    964        catch (e2)
    965        {
    966          if (e.constructor !== e2.constructor)
    967          {
    968            this._log("Difference when comparing native/reimplementation " +
    969                      "behavior defining fun.length with " + desc.toSource() +
    970                      "; native threw " + e + ", reimpl threw " + e2);
    971          }
    972          return;
    973        }
    974        this._log("Difference when comparing Function.length native/reimpl " +
    975                  "behavior for descriptor " + desc.toSource() +
    976                  ", native impl threw error " + e);
    977        return;
    978      }
    979 
    980      try
    981      {
    982        ReimplTest.defineProperty(reimplObj, "length", desc);
    983      }
    984      catch (e)
    985      {
    986        this._log("Difference defining new Function.length descriptor: impl " +
    987                  "succeeded, reimpl threw for descriptor " +
    988                  desc.toSource() + ", error: " + e);
    989        return;
    990      }
    991 
    992      var nativeDesc = NativeTest.getDescriptor(nativeObj, "length");
    993      var reimplDesc = ReimplTest.getDescriptor(reimplObj, "length");
    994      try
    995      {
    996        compareDescriptors(nativeDesc, reimplDesc);
    997      }
    998      catch (e)
    999      {
   1000        this._log("Difference comparing returned descriptors for " +
   1001                  "Function.length with descriptor " + desc.toSource() +
   1002                  "; error: " + e);
   1003        return;
   1004      }
   1005    }
   1006  };
   1007 
   1008 function runDictionaryPropertyPresentTestsFraction(PART, PARTS)
   1009 {
   1010  var testfile =
   1011    '15.2.3.6-dictionary-redefinition-' + PART + '-of-' + PARTS + '.js';
   1012  var BUGNUMBER = 560566;
   1013  var summary =
   1014    'ES5 Object.defineProperty(O, P, Attributes): dictionary redefinition ' +
   1015    PART + ' of ' + PARTS;
   1016 
   1017  print(BUGNUMBER + ": " + summary);
   1018 
   1019  try
   1020  {
   1021    new TestRunner().runDictionaryPropertyPresentTestsFraction(PART, PARTS);
   1022  }
   1023  catch (e)
   1024  {
   1025    throw "Error thrown during testing: " + e +
   1026            " at line " + e.lineNumber + "\n" +
   1027          (e.stack
   1028            ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n"
   1029            : "");
   1030  }
   1031 
   1032  if (typeof reportCompare === "function")
   1033    reportCompare(true, true);
   1034 
   1035  print("Tests complete!");
   1036 }
   1037 
   1038 function runNonTerminalPropertyPresentTestsFraction(PART, PARTS)
   1039 {
   1040  var BUGNUMBER = 560566;
   1041  var summary =
   1042    'ES5 Object.defineProperty(O, P, Attributes): middle redefinition ' +
   1043    PART + ' of ' + PARTS;
   1044 
   1045  print(BUGNUMBER + ": " + summary);
   1046 
   1047 
   1048  /**************
   1049   * BEGIN TEST *
   1050   **************/
   1051 
   1052  try
   1053  {
   1054    new TestRunner().runNonTerminalPropertyPresentTestsFraction(PART, PARTS);
   1055  }
   1056  catch (e)
   1057  {
   1058    throw "Error thrown during testing: " + e +
   1059            " at line " + e.lineNumber + "\n" +
   1060          (e.stack
   1061            ? "Stack: " + e.stack.split("\n").slice(2).join("\n") + "\n"
   1062            : "");
   1063  }
   1064 
   1065  /******************************************************************************/
   1066 
   1067  if (typeof reportCompare === "function")
   1068    reportCompare(true, true);
   1069 
   1070  print("Tests complete!");
   1071 }