v8/test/mjsunit/harmony/private-brand-checks.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

568 lines
11 KiB
JavaScript
Raw Normal View History

// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-brand-checks --allow-natives-syntax
// Objects for which all our brand checks return false.
const commonFalseCases = [{}, function() {}, []];
// Values for which all our brand checks throw.
const commonThrowCases = [100, 'foo', undefined, null];
(function TestReturnValue() {
class A {
m() {
assertEquals(typeof (#x in this), 'boolean');
assertEquals(typeof (#x in {}), 'boolean');
}
#x = 1;
}
})();
(function TestPrivateField() {
class A {
m(other) {
return #x in other;
}
#x = 1;
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
#x = 5;
}
assertFalse(a.m(new B()));
})();
(function TestPrivateFieldWithValueUndefined() {
class A {
m(other) {
return #x in other;
}
#x;
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
#x;
}
assertFalse(a.m(new B()));
})();
(function TestPrivateMethod() {
class A {
#pm() {
}
m(other) {
return #pm in other;
}
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
#pm() {}
}
assertFalse(a.m(new B()));
})();
(function TestPrivateGetter() {
class A {
get #foo() {
}
m(other) {
return #foo in other;
}
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
get #foo() {}
}
assertFalse(a.m(new B()));
})();
(function TestPrivateSetter() {
class A {
set #foo(a) {
}
m(other) {
return #foo in other;
}
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
set #foo(a) {}
}
assertFalse(a.m(new B()));
})();
(function TestPrivateGetterAndSetter() {
class A {
get #foo() {}
set #foo(a) {
}
m(other) {
return #foo in other;
}
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
class B {
get #foo() {}
set #foo(a) {}
}
assertFalse(a.m(new B()));
})();
(function TestPrivateStaticField() {
class A {
static m(other) {
return #x in other;
}
static #x = 1;
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
class B {
static #x = 5;
}
assertFalse(A.m(B));
})();
(function TestPrivateStaticMethod() {
class A {
static m(other) {
return #pm in other;
}
static #pm() {}
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
class B {
static #pm() {};
}
assertFalse(A.m(B));
})();
(function TestPrivateStaticGetter() {
class A {
static m(other) {
return #x in other;
}
static get #x() {}
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
class B {
static get #x() {};
}
assertFalse(A.m(B));
})();
(function TestPrivateStaticSetter() {
class A {
static m(other) {
return #x in other;
}
static set #x(x) {}
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
class B {
static set #x(x) {};
}
assertFalse(A.m(B));
})();
(function TestPrivateStaticGetterAndSetter() {
class A {
static m(other) {
return #x in other;
}
static get #x() {}
static set #x(x) {}
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
class B {
static get #x() {}
static set #x(x) {};
}
assertFalse(A.m(B));
})();
(function TestPrivateIdentifiersAreDistinct() {
function GenerateClass() {
class A {
m(other) {
return #x in other;
}
#x = 0;
}
return new A();
}
let a1 = GenerateClass();
let a2 = GenerateClass();
assertTrue(a1.m(a1));
assertFalse(a1.m(a2));
assertFalse(a2.m(a1));
assertTrue(a2.m(a2));
})();
(function TestSubclasses() {
class A {
m(other) { return #foo in other; }
#foo;
}
class B extends A {}
assertTrue((new A()).m(new B()));
})();
(function TestFakeSubclassesWithPrivateField() {
class A {
#foo;
m() { return #foo in this; }
}
let a = new A();
assertTrue(a.m());
// Plug an object into the prototype chain; it's not a real instance of the
// class.
let fake = {__proto__: a};
assertFalse(fake.m());
})();
(function TestFakeSubclassesWithPrivateMethod() {
class A {
#pm() {}
m() { return #pm in this; }
}
let a = new A();
assertTrue(a.m());
// Plug an object into the prototype chain; it's not a real instance of the
// class.
let fake = {__proto__: a};
assertFalse(fake.m());
})();
(function TestPrivateNameUnknown() {
assertThrows(() => { eval(`
class A {
m(other) { return #lol in other; }
}
new A().m();
`)}, SyntaxError, /must be declared in an enclosing class/);
})();
(function TestEvalWithPrivateField() {
class A {
m(other) {
let result;
eval('result = #x in other;');
return result;
}
#x = 1;
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
})();
(function TestEvalWithPrivateMethod() {
class A {
m(other) {
let result;
eval('result = #pm in other;');
return result;
}
#pm() {}
}
let a = new A();
assertTrue(a.m(a));
assertTrue(a.m(new A()));
for (o of commonFalseCases) {
assertFalse(a.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { a.m(o) }, TypeError);
}
})();
(function TestEvalWithStaticPrivateField() {
class A {
static m(other) {
let result;
eval('result = #x in other;');
return result;
}
static #x = 1;
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
})();
(function TestEvalWithStaticPrivateMethod() {
class A {
static m(other) {
let result;
eval('result = #pm in other;');
return result;
}
static #pm() {}
}
assertTrue(A.m(A));
assertFalse(A.m(new A()));
for (o of commonFalseCases) {
assertFalse(A.m(o));
}
for (o of commonThrowCases) {
assertThrows(() => { A.m(o) }, TypeError);
}
})();
(function TestCombiningWithOtherExpressions() {
class A {
m() {
assertFalse(#x in {} in {} in {});
assertTrue(#x in this in {true: 0});
assertTrue(#x in {} < 1 + 1);
assertFalse(#x in this < 1);
assertThrows(() => { eval('#x in {} = 4')});
assertThrows(() => { eval('(#x in {}) = 4')});
}
#x;
}
new A().m();
})();
(function TestHalfConstructedObjects() {
let half_constructed;
class A {
m() {
assertTrue(#x in this);
assertFalse(#y in this);
}
#x = 0;
#y = (() => { half_constructed = this; throw 'lol';})();
}
try {
new A();
} catch {
}
half_constructed.m();
})();
(function TestPrivateFieldOpt() {
class A {
m(other) {
return #x in other;
}
#x = 1;
}
let a = new A();
%PrepareFunctionForOptimization(A.prototype.m);
assertTrue(a.m(a));
assertTrue(a.m(new A()));
%OptimizeFunctionOnNextCall(A.prototype.m);
assertTrue(a.m(a));
assertTrue(a.m(new A()));
class B {
#x = 5;
}
assertFalse(a.m(new B()));
})();
(function TestPrivateMethodOpt() {
class A {
#pm() {
}
m(other) {
return #pm in other;
}
}
let a = new A();
%PrepareFunctionForOptimization(A.prototype.m);
assertTrue(a.m(a));
assertTrue(a.m(new A()));
%OptimizeFunctionOnNextCall(A.prototype.m);
assertTrue(a.m(a));
assertTrue(a.m(new A()));
class B {
#pm() {}
}
assertFalse(a.m(new B()));
})();
(function TestPrivateStaticFieldOpt() {
class A {
static m(other) {
return #x in other;
}
static #x = 1;
}
%PrepareFunctionForOptimization(A.m);
assertTrue(A.m(A));
%OptimizeFunctionOnNextCall(A.m);
assertTrue(A.m(A));
class B {
static #x = 5;
}
assertFalse(A.m(B));
})();
(function TestPrivateStaticMethodOpt() {
class A {
static m(other) {
return #pm in other;
}
static #pm() {}
}
%PrepareFunctionForOptimization(A.m);
assertTrue(A.m(A));
%OptimizeFunctionOnNextCall(A.m);
assertTrue(A.m(A));
class B {
static #pm() {};
}
assertFalse(A.m(B));
})();
(function TestPrivateFieldWithProxy() {
class A {
m(other) {
return #x in other;
}
#x = 1;
}
let a = new A();
const p = new Proxy(a, {get: function() { assertUnreachable(); } });
assertFalse(a.m(p));
})();
(function TestHeritagePosition() {
class A {
#x; // A.#x
static C = class C extends (function () {
return class D {
exfil(obj) { return #x in obj; }
exfilEval(obj) { return eval("#x in obj"); }
};
}) { // C body starts
#x; // C.#x
} // C body ends
} // A ends
let c = new A.C();
let d = new c();
// #x inside D binds to A.#x, so only objects of A pass the check.
assertTrue(d.exfil(new A()));
assertFalse(d.exfil(c));
assertFalse(d.exfil(d));
assertTrue(d.exfilEval(new A()));
assertFalse(d.exfilEval(c));
assertFalse(d.exfilEval(d));
})();