|
|
@ -9,12 +9,33 @@ |
|
|
|
* Even so, user code is expected to never create a prototype loop on purpose. |
|
|
|
*/ |
|
|
|
|
|
|
|
/* XXX: missing tests for API call type validation */ |
|
|
|
|
|
|
|
/*===
|
|
|
|
*** test_1 (duk_safe_call) |
|
|
|
==> rc=0, result='undefined' |
|
|
|
*** test_2 (duk_safe_call) |
|
|
|
*** test_basic (duk_safe_call) |
|
|
|
top before set: 2 |
|
|
|
top after set: 1 |
|
|
|
top before get: 1 |
|
|
|
top after get: 2 |
|
|
|
prototype: undefined |
|
|
|
top before get: 2 |
|
|
|
top after get: 3 |
|
|
|
obj1 proto === Object.prototype: 1 |
|
|
|
obj1.isPrototypeOf is undefined: 0 |
|
|
|
top before set: 3 |
|
|
|
top after set: 2 |
|
|
|
top before get: 2 |
|
|
|
top after get: 3 |
|
|
|
prototype: TypeError: [[DefaultValue]] coerce failed |
|
|
|
top before get: 2 |
|
|
|
top after get: 3 |
|
|
|
obj1 proto === Object.prototype: 0 |
|
|
|
obj1 proto === obj0: 1 |
|
|
|
obj1.isPrototypeOf is undefined: 1 |
|
|
|
obj1.foo=123 |
|
|
|
final top: 2 |
|
|
|
==> rc=0, result='undefined' |
|
|
|
*** test_3 (duk_safe_call) |
|
|
|
*** test_loop (duk_safe_call) |
|
|
|
set obj0 prototype to obj1 |
|
|
|
set obj1 prototype to obj0 |
|
|
|
obj0.foo=123 |
|
|
@ -22,17 +43,84 @@ obj0.bar=123 |
|
|
|
==> rc=1, result='Error: prototype chain limit' |
|
|
|
===*/ |
|
|
|
|
|
|
|
static duk_ret_t test_1(duk_context *ctx) { |
|
|
|
(void) ctx; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/* Multiple basic tests in one: test duk_set_prototype() and duk_get_prototype()
|
|
|
|
* stack top changes, and object/undefined for duk_set_prototype(). Also checks |
|
|
|
* how a naked object works. |
|
|
|
*/ |
|
|
|
static duk_ret_t test_basic(duk_context *ctx) { |
|
|
|
/* Prototype object: { foo: 123 }, internal prototype is null. */ |
|
|
|
duk_push_object(ctx); |
|
|
|
duk_push_undefined(ctx); |
|
|
|
printf("top before set: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_set_prototype(ctx, -2); |
|
|
|
printf("top after set: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_push_int(ctx, 123); |
|
|
|
duk_put_prop_string(ctx, -2, "foo"); |
|
|
|
|
|
|
|
/* The prototype object is "naked", read back its prototype. */ |
|
|
|
printf("top before get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_get_prototype(ctx, 0); |
|
|
|
printf("top after get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
printf("prototype: %s\n", duk_safe_to_string(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
static duk_ret_t test_2(duk_context *ctx) { |
|
|
|
(void) ctx; |
|
|
|
/* Target object, initially inherits from Object.prototype. */ |
|
|
|
duk_push_object(ctx); |
|
|
|
|
|
|
|
/* Check original prototype. */ |
|
|
|
printf("top before get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_get_prototype(ctx, 1); |
|
|
|
printf("top after get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_eval_string(ctx, "Object.prototype"); |
|
|
|
printf("obj1 proto === Object.prototype: %d\n", (int) duk_strict_equals(ctx, -2, -1)); |
|
|
|
duk_pop_2(ctx); |
|
|
|
|
|
|
|
/* Check Object.prototype inheritance in practice. */ |
|
|
|
duk_get_prop_string(ctx, 1, "isPrototypeOf"); |
|
|
|
printf("obj1.isPrototypeOf is undefined: %d\n", (int) duk_is_undefined(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
/* Change prototype. */ |
|
|
|
duk_dup(ctx, 0); |
|
|
|
printf("top before set: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_set_prototype(ctx, -2); |
|
|
|
printf("top after set: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
|
|
|
|
/* Read back the prototype. The object is "naked" and doesn't have
|
|
|
|
* valueOf() or toString(), so that the string coercion will fail |
|
|
|
* here on purpose. Unfortunately this check depends on the specific |
|
|
|
* error message and is brittle. |
|
|
|
*/ |
|
|
|
printf("top before get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_get_prototype(ctx, 1); |
|
|
|
printf("top after get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
printf("prototype: %s\n", duk_safe_to_string(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
/* Check that prototype is no longer Object.prototype. */ |
|
|
|
printf("top before get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_get_prototype(ctx, 1); |
|
|
|
printf("top after get: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
duk_eval_string(ctx, "Object.prototype"); |
|
|
|
printf("obj1 proto === Object.prototype: %d\n", (int) duk_strict_equals(ctx, -2, -1)); |
|
|
|
printf("obj1 proto === obj0: %d\n", (int) duk_strict_equals(ctx, -2, 0)); |
|
|
|
duk_pop_2(ctx); |
|
|
|
|
|
|
|
/* Check that isPrototypeOf can no longer be accessed. */ |
|
|
|
duk_get_prop_string(ctx, 1, "isPrototypeOf"); |
|
|
|
printf("obj1.isPrototypeOf is undefined: %d\n", (int) duk_is_undefined(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
/* Check that 'foo' can be accessed. */ |
|
|
|
duk_get_prop_string(ctx, 1, "foo"); |
|
|
|
printf("obj1.foo=%s\n", duk_safe_to_string(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
printf("final top: %ld\n", (long) duk_get_top(ctx)); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static duk_ret_t test_3(duk_context *ctx) { |
|
|
|
static duk_ret_t test_loop(duk_context *ctx) { |
|
|
|
duk_push_object(ctx); |
|
|
|
duk_push_int(ctx, 123); |
|
|
|
duk_put_prop_string(ctx, -2, "foo"); |
|
|
@ -74,11 +162,14 @@ static duk_ret_t test_3(duk_context *ctx) { |
|
|
|
printf("obj0.foo=%s\n", duk_safe_to_string(ctx, -1)); |
|
|
|
duk_pop(ctx); |
|
|
|
|
|
|
|
/* NOTE: there are much more extensive prototype loop tests in
|
|
|
|
* test-dev-prototype-loop.c |
|
|
|
*/ |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void test(duk_context *ctx) { |
|
|
|
TEST_SAFE_CALL(test_1); |
|
|
|
TEST_SAFE_CALL(test_2); |
|
|
|
TEST_SAFE_CALL(test_3); |
|
|
|
TEST_SAFE_CALL(test_basic); |
|
|
|
TEST_SAFE_CALL(test_loop); |
|
|
|
} |
|
|
|