tor-browser

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

window-named-properties-object.html (10825B)


      1 <!doctype html>
      2 <meta charset="utf-8">
      3 <title>Internal methods of Window's named properties object</title>
      4 <link rel="help" href="https://webidl.spec.whatwg.org/#named-properties-object">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <body>
      8 <script>
      9 function sloppyModeSet(base, key, value) { base[key] = value; }
     10 </script>
     11 <script>
     12 "use strict";
     13 
     14 const supportedNonIndex = "supported non-index property name";
     15 const supportedIndex = "supported indexed property name";
     16 const unsupportedNonIndex = "unsupported non-index property name";
     17 const unsupportedIndex = "unsupported indexed property name";
     18 const existingSymbol = "existing symbol property name";
     19 const nonExistingSymbol = "non-existing symbol property name";
     20 
     21 test(t => {
     22    const { w, wp } = createWindowProperties(t);
     23 
     24    Object.setPrototypeOf(wp, w.EventTarget.prototype); // Setting current [[Prototype]] value shouldn't throw
     25 
     26    assert_throws_js(TypeError, () => { Object.setPrototypeOf(wp, {}); });
     27    assert_throws_js(w.TypeError, () => { wp.__proto__ = null; });
     28    assert_false(Reflect.setPrototypeOf(wp, w.Object.prototype));
     29 
     30    assert_equals(Object.getPrototypeOf(wp), w.EventTarget.prototype);
     31 }, "[[SetPrototypeOf]] and [[GetPrototypeOf]]");
     32 
     33 test(t => {
     34    const { wp } = createWindowProperties(t);
     35 
     36    assert_throws_js(TypeError, () => { Object.preventExtensions(wp); });
     37    assert_false(Reflect.preventExtensions(wp));
     38 
     39    assert_true(Object.isExtensible(wp));
     40 }, "[[PreventExtensions]] and [[IsExtensible]]");
     41 
     42 test(t => {
     43    const { w, wp } = createWindowProperties(t);
     44 
     45    const elA = appendElementWithId(w, "a");
     46    const el0 = appendIframeWithName(w, 0);
     47 
     48    assert_prop_desc(Object.getOwnPropertyDescriptor(wp, "a"), elA, supportedNonIndex);
     49    assert_prop_desc(Reflect.getOwnPropertyDescriptor(wp, 0), el0, supportedIndex);
     50    assert_equals(Reflect.getOwnPropertyDescriptor(wp, "b"), undefined, unsupportedNonIndex);
     51    assert_equals(Object.getOwnPropertyDescriptor(wp, 1), undefined, unsupportedIndex);
     52 }, "[[GetOwnProperty]]");
     53 
     54 test(t => {
     55    const { w, wp } = createWindowProperties(t);
     56 
     57    appendIframeWithName(w, "hasOwnProperty");
     58    appendFormWithName(w, "addEventListener");
     59    appendElementWithId(w, "a");
     60    appendIframeWithName(w, 0);
     61 
     62    w.Object.prototype.a = {};
     63    w.EventTarget.prototype[0] = {};
     64 
     65    // These are shadowed by properties higher in [[Prototype]] chain. See https://webidl.spec.whatwg.org/#dfn-named-property-visibility
     66    assert_equals(Object.getOwnPropertyDescriptor(wp, "hasOwnProperty"), undefined, supportedNonIndex);
     67    assert_equals(Reflect.getOwnPropertyDescriptor(wp, "addEventListener"), undefined, supportedNonIndex);
     68    assert_equals(Object.getOwnPropertyDescriptor(wp, "a"), undefined, supportedNonIndex);
     69    assert_equals(Reflect.getOwnPropertyDescriptor(wp, 0), undefined, supportedIndex);
     70 }, "[[GetOwnProperty]] (named property visibility algorithm)");
     71 
     72 test(t => {
     73    const { w, wp } = createWindowProperties(t);
     74 
     75    appendElementWithId(w, "a");
     76    appendFormWithName(w, 0);
     77 
     78    assert_define_own_property_fails(wp, "a", {}, supportedNonIndex);
     79    assert_define_own_property_fails(wp, 0, {}, supportedIndex);
     80    assert_define_own_property_fails(wp, "b", {}, unsupportedNonIndex);
     81    assert_define_own_property_fails(wp, 1, {}, unsupportedIndex);
     82    assert_define_own_property_fails(wp, Symbol.toStringTag, {}, existingSymbol);
     83    assert_define_own_property_fails(wp, Symbol(), {}, nonExistingSymbol);
     84 }, "[[DefineOwnProperty]]");
     85 
     86 test(t => {
     87    const { w, wp } = createWindowProperties(t);
     88 
     89    appendFormWithName(w, "a");
     90    appendElementWithId(w, 0);
     91 
     92    assert_true("a" in wp, supportedNonIndex);
     93    assert_true(Reflect.has(wp, "a"), supportedNonIndex);
     94    assert_true(0 in wp, supportedIndex);
     95    assert_true(Reflect.has(wp, 0), supportedIndex);
     96 
     97    assert_false("b" in wp, unsupportedNonIndex);
     98    assert_false(Reflect.has(wp, 1), unsupportedIndex);
     99 }, "[[HasProperty]]");
    100 
    101 test(t => {
    102    const { w, wp } = createWindowProperties(t);
    103    const elA = appendFormWithName(w, "a");
    104    const el0 = appendIframeWithName(w, 0);
    105 
    106    assert_equals(wp.a, elA, supportedNonIndex);
    107    assert_equals(wp[0], el0, supportedIndex);
    108    assert_equals(wp[Symbol.toStringTag], "WindowProperties", existingSymbol);
    109 
    110    assert_equals(wp.b, undefined, unsupportedNonIndex);
    111    assert_equals(wp[1], undefined, unsupportedIndex);
    112    assert_equals(wp[Symbol.iterator], undefined, nonExistingSymbol);
    113 }, "[[Get]]");
    114 
    115 test(t => {
    116    const { w, wp } = createWindowProperties(t);
    117 
    118    appendIframeWithName(w, "isPrototypeOf");
    119    appendFormWithName(w, "dispatchEvent");
    120    appendElementWithId(w, "a");
    121    appendElementWithId(w, 0);
    122 
    123    w.EventTarget.prototype.a = 10;
    124    w.Object.prototype[0] = 20;
    125 
    126    // These are shadowed by properties higher in [[Prototype]] chain. See https://webidl.spec.whatwg.org/#dfn-named-property-visibility
    127    assert_equals(wp.isPrototypeOf, w.Object.prototype.isPrototypeOf, supportedNonIndex);
    128    assert_equals(wp.dispatchEvent, w.EventTarget.prototype.dispatchEvent, supportedNonIndex);
    129    assert_equals(wp.a, 10, supportedNonIndex);
    130    assert_equals(wp[0], 20, supportedIndex);
    131 }, "[[Get]] (named property visibility algorithm)");
    132 
    133 test(t => {
    134    const { w, wp } = createWindowProperties(t);
    135    const elA = appendIframeWithName(w, "a");
    136    const el0 = appendFormWithName(w, 0);
    137 
    138    assert_set_fails(wp, "a", supportedNonIndex);
    139    assert_set_fails(wp, "b", unsupportedNonIndex);
    140    assert_set_fails(wp, 0, supportedIndex);
    141    assert_set_fails(wp, 1, unsupportedIndex);
    142    assert_set_fails(wp, Symbol.toStringTag, existingSymbol);
    143    assert_set_fails(wp, Symbol(), nonExistingSymbol);
    144 
    145    assert_equals(wp.a, elA, supportedNonIndex);
    146    assert_equals(wp[0], el0, supportedIndex);
    147    assert_equals(wp.b, undefined, unsupportedNonIndex);
    148    assert_equals(wp[1], undefined, unsupportedIndex);
    149 }, "[[Set]] (direct)");
    150 
    151 test(t => {
    152    const { w, wp } = createWindowProperties(t);
    153    const receiver = Object.create(wp);
    154 
    155    appendIframeWithName(w, "a");
    156    appendElementWithId(w, 0);
    157 
    158    let setterThisValue;
    159    Object.defineProperty(w.Object.prototype, 1, { set() { setterThisValue = this; } });
    160    Object.defineProperty(w.EventTarget.prototype, "b", { writable: false });
    161 
    162    receiver.a = 10;
    163    assert_throws_js(TypeError, () => { receiver.b = {}; }, unsupportedNonIndex);
    164    receiver[0] = 20;
    165    receiver[1] = {};
    166 
    167    assert_equals(receiver.a, 10, supportedNonIndex);
    168    assert_equals(receiver[0], 20, supportedIndex);
    169    assert_false(receiver.hasOwnProperty("b"), unsupportedNonIndex);
    170    assert_false(receiver.hasOwnProperty(1), unsupportedIndex);
    171    assert_equals(setterThisValue, receiver, "setter |this| value is receiver");
    172 }, "[[Set]] (prototype chain)");
    173 
    174 test(t => {
    175    const { w, wp } = createWindowProperties(t);
    176    const receiver = {};
    177 
    178    appendFormWithName(w, "a");
    179    appendIframeWithName(w, 0);
    180 
    181    let setterThisValue;
    182    Object.defineProperty(w.Object.prototype, "b", { set() { setterThisValue = this; } });
    183    Object.defineProperty(w.EventTarget.prototype, 1, { writable: false });
    184 
    185    assert_true(Reflect.set(wp, "a", 10, receiver), supportedNonIndex);
    186    assert_true(Reflect.set(wp, 0, 20, receiver), supportedIndex);
    187    assert_true(Reflect.set(wp, "b", {}, receiver), unsupportedNonIndex);
    188    assert_false(Reflect.set(wp, 1, {}, receiver), unsupportedIndex);
    189 
    190    assert_equals(receiver.a, 10, supportedNonIndex);
    191    assert_equals(receiver[0], 20, supportedIndex);
    192    assert_false(receiver.hasOwnProperty("b"), unsupportedNonIndex);
    193    assert_equals(setterThisValue, receiver, "setter |this| value is receiver");
    194    assert_false(receiver.hasOwnProperty(1), unsupportedIndex);
    195 }, "[[Set]] (Reflect.set)");
    196 
    197 test(t => {
    198    const { w, wp } = createWindowProperties(t);
    199    const elA = appendFormWithName(w, "a");
    200    const el0 = appendElementWithId(w, 0);
    201 
    202    assert_delete_fails(wp, "a", supportedNonIndex);
    203    assert_delete_fails(wp, 0, supportedIndex);
    204    assert_delete_fails(wp, "b", unsupportedNonIndex);
    205    assert_delete_fails(wp, 1, unsupportedIndex);
    206    assert_delete_fails(wp, Symbol.toStringTag, existingSymbol);
    207    assert_delete_fails(wp, Symbol("foo"), nonExistingSymbol);
    208 
    209    assert_equals(wp.a, elA, supportedNonIndex);
    210    assert_equals(wp[0], el0, supportedIndex);
    211    assert_equals(wp[Symbol.toStringTag], "WindowProperties", existingSymbol);
    212 }, "[[Delete]]");
    213 
    214 test(t => {
    215    const { w, wp } = createWindowProperties(t);
    216 
    217    appendIframeWithName(w, "a");
    218    appendElementWithId(w, 0);
    219    appendFormWithName(w, "b");
    220 
    221    const forInKeys = [];
    222    for (const key in wp)
    223        forInKeys.push(key);
    224 
    225    assert_array_equals(forInKeys, Object.keys(w.EventTarget.prototype));
    226    assert_array_equals(Object.getOwnPropertyNames(wp), []);
    227    assert_array_equals(Reflect.ownKeys(wp), [Symbol.toStringTag]);
    228 }, "[[OwnPropertyKeys]]");
    229 
    230 function createWindowProperties(t) {
    231    const iframe = document.createElement("iframe");
    232    document.body.append(iframe);
    233    t.add_cleanup(() => { iframe.remove(); });
    234 
    235    const w = iframe.contentWindow;
    236    const wp = Object.getPrototypeOf(w.Window.prototype);
    237    return { w, wp };
    238 }
    239 
    240 function appendIframeWithName(w, name) {
    241    const el = w.document.createElement("iframe");
    242    el.name = name;
    243    w.document.body.append(el);
    244    return el.contentWindow;
    245 }
    246 
    247 function appendFormWithName(w, name) {
    248    const el = w.document.createElement("form");
    249    el.name = name;
    250    w.document.body.append(el);
    251    return el;
    252 }
    253 
    254 function appendElementWithId(w, id) {
    255    const el = w.document.createElement("div");
    256    el.id = id;
    257    w.document.body.append(el);
    258    return el;
    259 }
    260 
    261 function assert_prop_desc(desc, value, testInfo) {
    262    assert_equals(typeof desc, "object", `${testInfo} typeof desc`);
    263    assert_equals(desc.value, value, `${testInfo} [[Value]]`);
    264    assert_true(desc.writable, `${testInfo} [[Writable]]`);
    265    assert_false(desc.enumerable, `${testInfo} [[Enumerable]]`);
    266    assert_true(desc.configurable, `${testInfo} [[Configurable]]`);
    267 }
    268 
    269 function assert_define_own_property_fails(object, key, desc, testInfo) {
    270    assert_throws_js(TypeError, () => { Object.defineProperty(object, key, desc); }, testInfo);
    271    assert_false(Reflect.defineProperty(object, key, desc), testInfo);
    272 }
    273 
    274 function assert_set_fails(object, key, value, testInfo) {
    275    sloppyModeSet(object, key, value);
    276    assert_throws_js(TypeError, () => { object[key] = value; }, testInfo);
    277    assert_false(Reflect.set(object, key, value), testInfo);
    278 }
    279 
    280 function assert_delete_fails(object, key, testInfo) {
    281    assert_throws_js(TypeError, () => { delete object[key]; }, testInfo);
    282    assert_false(Reflect.deleteProperty(object, key), testInfo);
    283 }
    284 </script>