tor-browser

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

private-field-basics.js (4995B)


      1 class A {
      2  #x = 10
      3 
      4  x() {
      5    return this.#x;
      6  }
      7  ix() {
      8    this.#x++;
      9  }
     10  static readx(o) {
     11    return o.#x;
     12  }
     13  static optionalx(o) {
     14    return o?.#x;
     15  }
     16 
     17  static orEqual(o, v) {
     18    o.#x ||= v;
     19    return o.#x;
     20  }
     21 
     22  setX(v) {
     23    this.#x = v;
     24  }
     25 
     26  compoundInc() {
     27    this.#x += 1;
     28    return this.#x;
     29  }
     30 
     31  compoundDec() {
     32    this.#x -= 1;
     33    return this.#x;
     34  }
     35 
     36  #y = () => 'hi';
     37  invoke() {
     38    return this.#y();
     39  }
     40 
     41  static #z = 'static';
     42  gz() {
     43    return A.#z;
     44  }
     45 
     46  sz(o) {
     47    A.#z = o;
     48  }
     49 
     50  static sgz() {
     51    return this.#z;
     52  }
     53 
     54  static ssz(o) {
     55    this.#z = o;
     56  }
     57 
     58  static six(o) {
     59    o.#x++;
     60  }
     61 
     62  static dix(o) {
     63    o.#x--;
     64  }
     65 };
     66 
     67 for (var i = 0; i < 1000; i++) {
     68  var a = new A();
     69  assertEq(a.x(), 10);
     70  a.ix();
     71  assertEq(a.x(), 11);
     72  assertEq(A.readx(a), 11);
     73  assertEq(a.compoundInc(), 12);
     74  assertEq(A.orEqual(a, 13), 12);
     75  a.setX(null);
     76  assertEq(A.orEqual(a, 12), 12);
     77  assertEq(a.compoundDec(), 11);
     78  assertEq(a.invoke(), 'hi');
     79  assertEq(a.gz(), 'static');
     80  assertEq(A.sgz(), 'static');
     81  A.ssz(i);
     82  assertEq(A.sgz(), i);
     83  a.sz(i + 1);
     84  assertEq(A.sgz(), i + 1);
     85  A.ssz('static');  // reset for next iteration!
     86 
     87  assertEq(A.optionalx(a), 11);
     88  assertEq(A.optionalx(null), undefined);
     89  try {
     90    A.optionalx({});  // Should throw type error
     91    assertEq(0, 1);
     92  } catch (TypeError) {
     93  }
     94 }
     95 
     96 function assertThrows(fun, errorType) {
     97  try {
     98    fun();
     99    throw 'Expected error, but none was thrown';
    100  } catch (e) {
    101    if (!(e instanceof errorType)) {
    102      throw 'Wrong error type thrown';
    103    }
    104  }
    105 }
    106 
    107 function testTypeErrors(v) {
    108  assertThrows(() => A.readx(v), TypeError);  // Read value
    109  assertThrows(() => A.six(v), TypeError);    // increment
    110  assertThrows(() => A.dix(v), TypeError);    // decrement
    111 }
    112 
    113 testTypeErrors(undefined);  // Undefined
    114 testTypeErrors({});         // Random object
    115 testTypeErrors(1);          // Random primitive
    116 
    117 assertThrows(
    118  () => eval('class B extends class { #x; } { g() { return super.#x; } }'),
    119  SyntaxError);  // Access super.#private
    120 assertThrows(
    121  () => eval('class C { #x = 10; static #x = 14; }'),
    122  SyntaxError);  // Duplicate name declaration.
    123 assertThrows(
    124  () => eval('delete this.#x'),
    125  SyntaxError);  // deleting a private field in non-strict mode.
    126 
    127 class B extends class {
    128  constructor(o) {
    129    return o;
    130  }
    131 }
    132 {
    133  #x = 12;
    134  static gx(o) {
    135    return o.#x;
    136  }
    137  static sx(o) {
    138    o.#x++;
    139  }
    140 }
    141 
    142 var bn = new B(1);
    143 var bu = new B(undefined);
    144 
    145 // Test we can read an outer classes private fields.
    146 class Outer {
    147  #outer = 3;
    148  test() {
    149    let outerThis = this;
    150    class Inner {
    151      #inner = 2;
    152      test() {
    153        return outerThis.#outer;
    154      }
    155    }
    156    return new Inner().test();
    157  }
    158 }
    159 
    160 var o = new Outer;
    161 assertEq(o.test(), 3);
    162 
    163 // IC tests:
    164 
    165 var alreadyConstructedB = new B();
    166 assertEq(B.gx(alreadyConstructedB), 12);
    167 
    168 function initIC(o) {
    169  new B(o);
    170 }
    171 var array = [];
    172 // warm up init IC
    173 for (var i = 1; i < 1000; i++) {
    174  var newB = {};
    175  initIC(newB);
    176 }
    177 
    178 // Successfully catch double initialization type error.
    179 assertThrows(() => initIC(alreadyConstructedB), TypeError);
    180 // Do it again, to make sure we didn't attach a stub that is invalid.
    181 assertThrows(() => initIC(alreadyConstructedB), TypeError);
    182 
    183 // Test getters work, and ICs can't be tricked. Setup an array of
    184 //
    185 //    [B, B, B, B, ..., {}, {}]
    186 //
    187 // Then test that as we execute the sudden appearance of {} doesn't
    188 // trick our ICs into setting or getting anything -- do it twice
    189 // to make sure that we didn't get a stub that is invalid.
    190 var elements = [];
    191 for (var i = 0; i < 99; i++) {
    192  elements.push(new B);
    193 }
    194 elements.push({});
    195 elements.push({});
    196 
    197 function getterCheck(e) {
    198  assertEq(B.gx(e), 12);
    199 }
    200 
    201 function setterCheck(e) {
    202  B.sx(e);
    203 }
    204 
    205 var checksPassed = 0;
    206 try {
    207  for (var e of elements) {
    208    getterCheck(e);
    209    checksPassed++;
    210  }
    211  throw `Shouldn't arrive here`;
    212 } catch (e) {
    213  if (!(e instanceof TypeError)) {
    214    throw e;
    215  }
    216  // All but last element should have done the right thing.
    217  assertEq(checksPassed, elements.length - 2);
    218 }
    219 
    220 checksPassed = 0;
    221 try {
    222  for (var e of elements) {
    223    setterCheck(e);
    224    checksPassed++;
    225  }
    226  throw `Shouldn't arrive here`;
    227 } catch (e) {
    228  if (!(e instanceof TypeError)) {
    229    throw e;
    230  }
    231  // All but last element should have done the right thing.
    232  assertEq(checksPassed, elements.length - 2);
    233 }
    234 
    235 // Verify setter did the thing, but throws in the correct places
    236 for (var index in elements) {
    237  if (index < elements.length - 2) {
    238    assertEq(B.gx(elements[index]), 13);
    239  } else {
    240    assertThrows(() => {
    241      B.gx(elements[index]);
    242    }, TypeError);
    243  }
    244 }
    245 
    246 // Megamorphic Cache Testing:
    247 for (var i = 0; i < 100; i++) {
    248  var inputs = [{ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 }, { e: 5 }, new Proxy({}, {})];
    249  for (var o of inputs) {
    250    assertThrows(() => B.gx(o), TypeError);
    251    assertThrows(() => B.sx(o), TypeError);
    252    new B(o);
    253    assertEq(B.gx(o), 12);
    254    B.sx(o);
    255    assertEq(B.gx(o), 13);
    256  }
    257 }