Skip to content

Commit 0bc7bba

Browse files
committed
Testcases for @@hasInstance and instanceof
1 parent e9b7bd1 commit 0bc7bba

2 files changed

Lines changed: 217 additions & 0 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* duk_instanceof() with rhs having @@hasInstance
3+
*/
4+
5+
/*===
6+
*** test_1 (duk_safe_call)
7+
hasinst called
8+
instanceof: 1
9+
final top: 2
10+
==> rc=0, result='undefined'
11+
===*/
12+
13+
static duk_ret_t test_1(duk_context *ctx, void *udata) {
14+
(void) udata;
15+
16+
/* Function.prototype[@@hasInstance] is not writable or configurable.
17+
* To set it, use duk_def_prop() or Object.defineProperty() to avoid
18+
* the ancestor blocking the write.
19+
*/
20+
duk_eval_string(ctx, "123");
21+
duk_eval_string(ctx, "(function foo() {})");
22+
duk_push_string(ctx, DUK_WELLKNOWN_SYMBOL("Symbol.hasInstance"));
23+
duk_eval_string(ctx, "(function hasinst() { print('hasinst called'); return true; })");
24+
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE);
25+
26+
/* [ lhs rhs ] */
27+
28+
printf("instanceof: %d\n", (int) duk_instanceof(ctx, 0, 1));
29+
30+
printf("final top: %ld\n", (long) duk_get_top(ctx));
31+
return 0;
32+
}
33+
34+
void test(duk_context *ctx) {
35+
TEST_SAFE_CALL(test_1);
36+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* instanceof and @@hasInstance
3+
*/
4+
5+
/*===
6+
- No @@hasInstance case; inherited from Function.prototype
7+
false
8+
true
9+
- Function overrides @@hasInstance
10+
false
11+
true
12+
- Function inherits a non-standard @@hasInstance
13+
inherited hasInstance true 123
14+
true
15+
inherited hasInstance true [object Object]
16+
true
17+
- Function inherits a non-standard @@hasInstance, but function itself also provides an undefined @@hasInstance
18+
false
19+
true
20+
true
21+
- Same but overriding value is null
22+
false
23+
true
24+
true
25+
- Same but overriding value is not undefined/null, but also not a callable object
26+
TypeError
27+
- Same, plain non-callable object
28+
TypeError
29+
- @@hasInstance is a getter with side effects
30+
@@hasInstance getter
31+
hasInstance true 123
32+
true
33+
@@hasInstance getter
34+
hasInstance true [object Object]
35+
true
36+
- Function.prototype[@@hasInstance] exists
37+
true
38+
true
39+
false
40+
function false false false
41+
- Function.prototype[@@hasInstance] access to OrdinaryHasInstance()
42+
false
43+
true
44+
false
45+
true
46+
===*/
47+
48+
function basicTest() {
49+
print('- No @@hasInstance case; inherited from Function.prototype');
50+
var rhs = function () {};
51+
print(123 instanceof rhs);
52+
print(Object.create(rhs.prototype) instanceof rhs);
53+
54+
print('- Function overrides @@hasInstance');
55+
var rhs = function () {};
56+
rhs[Symbol.hasInstance] = function (v) {
57+
print('hasInstance', this === rhs, v);
58+
return 1;
59+
}
60+
print(123 instanceof rhs);
61+
print(Object.create(rhs.prototype) instanceof rhs);
62+
63+
print('- Function inherits a non-standard @@hasInstance');
64+
var rhs = function () {};
65+
var o = {};
66+
Object.setPrototypeOf(rhs, o);
67+
o[Symbol.hasInstance] = function (v) {
68+
print('inherited hasInstance', this === rhs, v);
69+
return true;
70+
}
71+
print(123 instanceof rhs);
72+
print(Object.create(rhs.prototype) instanceof rhs);
73+
74+
// In this case we fall back to OrdinaryHasInstance().
75+
print('- Function inherits a non-standard @@hasInstance, but function itself also provides an undefined @@hasInstance');
76+
var rhs = function () {};
77+
var o = {};
78+
Object.setPrototypeOf(rhs, o);
79+
o[Symbol.hasInstance] = function (v) {
80+
print('undefined hasInstance', this === rhs, v);
81+
return 1;
82+
}
83+
rhs[Symbol.hasInstance] = void 0;
84+
print(123 instanceof rhs);
85+
print(Object.create(rhs.prototype) instanceof rhs);
86+
var inst = new rhs();
87+
print(inst instanceof rhs);
88+
89+
// For null value, GetMethod (https://www.ecma-international.org/ecma-262/6.0/#sec-getmethod)
90+
// returns 'undefined' for both undefined AND null, so that InstanceofOperator(O, C)
91+
// handles them the same in Step 4 of https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator.
92+
// In other words, for both undefined and null we must fall back to the
93+
// OrdinaryHasInstance() algorithm. V8 treats null and undefined differently
94+
// (TypeError for null), Firefox treats them the same.
95+
96+
// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator
97+
// A non-undefined/null value, causes a "not callable" TypeError
98+
print('- Same but overriding value is null');
99+
var rhs = function () {};
100+
var o = {};
101+
Object.setPrototypeOf(rhs, o);
102+
o[Symbol.hasInstance] = function (v) {
103+
print('null hasInstance', this === rhs, v);
104+
return 1;
105+
}
106+
rhs[Symbol.hasInstance] = null;
107+
print(123 instanceof rhs);
108+
print(Object.create(rhs.prototype) instanceof rhs);
109+
var inst = new rhs();
110+
print(inst instanceof rhs);
111+
112+
print('- Same but overriding value is not undefined/null, but also not a callable object');
113+
var rhs = function () {};
114+
var o = {};
115+
Object.setPrototypeOf(rhs, o);
116+
o[Symbol.hasInstance] = function (v) {
117+
print('fail hasInstance', this === rhs, v);
118+
return 1;
119+
}
120+
try {
121+
rhs[Symbol.hasInstance] = true;
122+
print(123 instanceof rhs);
123+
} catch (e) {
124+
print(e.name);
125+
}
126+
127+
print('- Same, plain non-callable object');
128+
var rhs = function () {};
129+
var o = {};
130+
Object.setPrototypeOf(rhs, o);
131+
o[Symbol.hasInstance] = function (v) {
132+
print('fail hasInstance', this === rhs, v);
133+
return 1;
134+
}
135+
try {
136+
rhs[Symbol.hasInstance] = { plain: true };
137+
print(123 instanceof rhs);
138+
} catch (e) {
139+
print(e.name);
140+
}
141+
142+
print('- @@hasInstance is a getter with side effects');
143+
var rhs = function () {};
144+
Object.defineProperty(rhs, Symbol.hasInstance, {
145+
get: function () {
146+
print('@@hasInstance getter');
147+
return function (v) {
148+
print('hasInstance', this === rhs, v);
149+
return 1;
150+
}
151+
}
152+
 });
153+
print(123 instanceof rhs);
154+
print(Object.create(rhs.prototype) instanceof rhs);
155+
156+
print('- Function.prototype[@@hasInstance] exists');
157+
print(Symbol.hasInstance in Function.prototype);
158+
print(Function.prototype[Symbol.hasInstance].call(Error, new RangeError()));
159+
print(Function.prototype[Symbol.hasInstance].call(Error, new Date()));
160+
var pd = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance);
161+
print(typeof pd.value, pd.writable, pd.enumerable, pd.configurable);
162+
163+
// Function.prototype[@@hasInstance] allows direct access to the
164+
// ES2015 OrdinaryHasInstance() specification method.
165+
print('- Function.prototype[@@hasInstance] access to OrdinaryHasInstance()');
166+
var rhs = function () {};
167+
rhs[Symbol.hasInstance] = function (v) {
168+
print('hasInstance', this === rhs, v);
169+
return 0;
170+
}
171+
print(123 instanceof rhs);
172+
print(Object.create(rhs.prototype) instanceof rhs);
173+
print(Function.prototype[Symbol.hasInstance].call(rhs, {}));
174+
print(Function.prototype[Symbol.hasInstance].call(rhs, Object.create(rhs.prototype)));
175+
}
176+
177+
try {
178+
basicTest();
179+
} catch (e) {
180+
print(e.stack || e);
181+
}

0 commit comments

Comments
 (0)