mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
997 lines
36 KiB
997 lines
36 KiB
10 years ago
|
/*
|
||
|
* duk_def_prop()
|
||
|
*/
|
||
|
|
||
|
/*===
|
||
|
*** test_value_only (duk_safe_call)
|
||
|
top before: 4
|
||
|
top after: 2
|
||
|
"my_key" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
final top: 2
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_value_redefine (duk_safe_call)
|
||
|
top before: 4
|
||
|
top after: 2
|
||
|
"my_key" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
top before: 4
|
||
|
top after: 2
|
||
|
"my_key" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
top before: 4
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_value_attr_combinations (duk_safe_call)
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
top before: 3
|
||
|
top after: 1
|
||
|
"my_key_0" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_2" {value:123,writable:false,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"my_key_3" {value:123,writable:true,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"my_key_4" {value:123,writable:false,enumerable:false,configurable:true} no-getter no-setter
|
||
|
"my_key_5" {value:123,writable:true,enumerable:false,configurable:true} no-getter no-setter
|
||
|
"my_key_6" {value:123,writable:false,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"my_key_7" {value:123,writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_value_attr_presence (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:true} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_2" {value:321,writable:false,enumerable:false,configurable:true} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_2" {value:321,writable:true,enumerable:false,configurable:true} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_2" {value:321,writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_setget_only (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:undefined,enumerable:false,configurable:false} getter no-setter
|
||
|
"my_key_1" {get:{_func:true},set:undefined,enumerable:false,configurable:false} getter no-setter
|
||
|
"my_key_2" {get:undefined,set:{_func:true},enumerable:false,configurable:true} no-getter setter
|
||
|
"my_key_1" {get:{_func:true},set:undefined,enumerable:false,configurable:false} getter no-setter
|
||
|
"my_key_2" {get:undefined,set:{_func:true},enumerable:false,configurable:true} no-getter setter
|
||
|
"my_key_3" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} getter setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_value_and_setget (duk_safe_call)
|
||
|
==> rc=1, result='TypeError: invalid descriptor'
|
||
|
*** test_writable_and_set (duk_safe_call)
|
||
|
==> rc=1, result='TypeError: invalid descriptor'
|
||
|
*** test_setget_undefined (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:true} getter setter
|
||
|
"my_key_1" {get:undefined,set:{_func:true},enumerable:false,configurable:true} no-getter setter
|
||
|
"my_key_1" {get:undefined,set:undefined,enumerable:false,configurable:true} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_getter_nonobject (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:true} getter setter
|
||
|
==> rc=1, result='TypeError: unexpected type'
|
||
|
*** test_setter_nonobject (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:true} getter setter
|
||
|
==> rc=1, result='TypeError: unexpected type'
|
||
|
*** test_getter_noncallable (duk_safe_call)
|
||
|
==> rc=1, result='TypeError: not callable'
|
||
|
*** test_setter_noncallable (duk_safe_call)
|
||
|
==> rc=1, result='TypeError: not callable'
|
||
|
*** test_setget_lightfunc (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:true} func func
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_nonextensible (duk_safe_call)
|
||
|
==> rc=1, result='TypeError: not extensible'
|
||
|
*** test_force_nonextensible (duk_safe_call)
|
||
|
"my_key_1" {value:321,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_configurable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:true,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_configurable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:true,configurable:true} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_enumerable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_enumerable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:false,enumerable:true,configurable:false} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_writable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_writable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:123,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_value (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_value (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {value:321,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_getter (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_getter (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} getter func
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_set_setter (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_set_setter (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_data2accessor (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_data2accessor (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:true,configurable:false} getter setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_accessor2data (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_accessor2data (duk_safe_call)
|
||
|
"my_key_1" {get:{_func:true},set:{_func:true},enumerable:false,configurable:false} func func
|
||
|
"my_key_1" {value:321,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_array_smaller (duk_safe_call)
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"1" {value:"bar",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"2" {value:"quux",writable:true,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"3" {value:"baz",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:4,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: array length write failed'
|
||
|
*** test_force_array_smaller (duk_safe_call)
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"1" {value:"bar",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"2" {value:"quux",writable:true,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"3" {value:"baz",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:4,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:1,writable:true,enumerable:false,configurable:false} no-getter no-setter
|
||
|
json: ["foo"]
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_array_smaller_nonwritablelength (duk_safe_call)
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"1" {value:"bar",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"2" {value:"quux",writable:true,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"3" {value:"baz",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:4,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
==> rc=1, result='TypeError: array length non-writable'
|
||
|
*** test_force_array_smaller_nonwritablelength (duk_safe_call)
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"1" {value:"bar",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"2" {value:"quux",writable:true,enumerable:true,configurable:false} no-getter no-setter
|
||
|
"3" {value:"baz",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:4,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
"0" {value:"foo",writable:true,enumerable:true,configurable:true} no-getter no-setter
|
||
|
"length" {value:1,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
json: ["foo"]
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
*** test_fail_nondeletable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
my_key_1 present: 1
|
||
|
==> rc=1, result='TypeError: not configurable'
|
||
|
*** test_force_nondeletable (duk_safe_call)
|
||
|
"my_key_1" {value:123,writable:false,enumerable:false,configurable:false} no-getter no-setter
|
||
|
my_key_1 present: 1
|
||
|
my_key_1 present: 0
|
||
|
final top: 1
|
||
|
==> rc=0, result='undefined'
|
||
|
===*/
|
||
|
|
||
|
static void dump_object(duk_context *ctx, duk_idx_t idx) {
|
||
|
idx = duk_require_normalize_index(ctx, idx);
|
||
|
|
||
|
/* The weird fn() helper is to handle lightfunc name printing (= avoid it). */
|
||
|
duk_eval_string(ctx,
|
||
|
"(function (o) {\n"
|
||
|
" Object.getOwnPropertyNames(o).forEach(function (k) {\n"
|
||
|
" var pd = Object.getOwnPropertyDescriptor(o, k);\n"
|
||
|
" function fn(x) { if (x.name !== 'getter' && x.name !== 'setter') { return 'func' }; return x.name; }\n"
|
||
|
" print(Duktape.enc('jx', k), Duktape.enc('jx', pd), (pd.get ? fn(pd.get) : 'no-getter'), (pd.set ? fn(pd.set) : 'no-setter'));\n"
|
||
|
" });\n"
|
||
|
"})");
|
||
|
duk_dup(ctx, idx);
|
||
|
duk_call(ctx, 1);
|
||
|
duk_pop(ctx);
|
||
|
}
|
||
|
|
||
|
static duk_ret_t my_getter(duk_context *ctx) {
|
||
|
printf("my_getter called\n");
|
||
|
duk_push_string(ctx, "fakeGetterValue");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static duk_ret_t my_setter(duk_context *ctx) {
|
||
|
printf("my_setter called\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void push_getter(duk_context *ctx) {
|
||
|
duk_push_c_function(ctx, my_getter, 0 /*nargs*/);
|
||
|
duk_push_string(ctx, "getter");
|
||
|
duk_put_prop_string(ctx, -2, "name");
|
||
|
}
|
||
|
|
||
|
static void push_getter_lightfunc(duk_context *ctx) {
|
||
|
duk_push_c_lightfunc(ctx, my_getter, 0 /*nargs*/, 0 /*length*/, 0 /*magic*/);
|
||
|
}
|
||
|
|
||
|
static void push_setter(duk_context *ctx) {
|
||
|
duk_push_c_function(ctx, my_setter, 1 /*nargs*/);
|
||
|
duk_push_string(ctx, "setter");
|
||
|
duk_put_prop_string(ctx, -2, "name");
|
||
|
}
|
||
|
|
||
|
static void push_setter_lightfunc(duk_context *ctx) {
|
||
|
duk_push_c_lightfunc(ctx, my_setter, 1 /*nargs*/, 1 /*length*/, 0 /*magic*/);
|
||
|
}
|
||
|
|
||
|
/* Define new property, value only. Other attributes get defaults. */
|
||
|
static duk_ret_t test_value_only(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
duk_push_string(ctx, "dummy");
|
||
|
duk_push_string(ctx, "my_key");
|
||
|
duk_push_int(ctx, 123);
|
||
|
printf("top before: %ld\n", (long) duk_get_top(ctx));
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_VALUE);
|
||
|
printf("top after: %ld\n", (long) duk_get_top(ctx));
|
||
|
dump_object(ctx, -2);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Try to re-define a value for a non-configurable property. */
|
||
|
static duk_ret_t test_value_redefine(duk_context *ctx) {
|
||
|
/* Define new property, value only. Other attributes will have
|
||
|
* default values (false).
|
||
|
*/
|
||
|
|
||
|
duk_push_object(ctx);
|
||
|
duk_push_string(ctx, "dummy");
|
||
|
duk_push_string(ctx, "my_key");
|
||
|
duk_push_int(ctx, 123);
|
||
|
printf("top before: %ld\n", (long) duk_get_top(ctx));
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_VALUE);
|
||
|
printf("top after: %ld\n", (long) duk_get_top(ctx));
|
||
|
dump_object(ctx, -2);
|
||
|
|
||
|
/* Attempt to redefine value with exact SameValue succeeds even
|
||
|
* when not configurable. (This, like most other things in this
|
||
|
* test case, is standard Object.defineProperty() behavior.)
|
||
|
*/
|
||
|
|
||
|
duk_push_string(ctx, "my_key");
|
||
|
duk_push_int(ctx, 123);
|
||
|
printf("top before: %ld\n", (long) duk_get_top(ctx));
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_VALUE);
|
||
|
printf("top after: %ld\n", (long) duk_get_top(ctx));
|
||
|
dump_object(ctx, -2);
|
||
|
|
||
|
/* Attempt to redefine value fails because the property is not
|
||
|
* configurable. A TypeError gets thrown.
|
||
|
*/
|
||
|
|
||
|
duk_push_string(ctx, "my_key");
|
||
|
duk_push_int(ctx, 321);
|
||
|
printf("top before: %ld\n", (long) duk_get_top(ctx));
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_VALUE);
|
||
|
printf("top after: %ld\n", (long) duk_get_top(ctx));
|
||
|
dump_object(ctx, -2);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Define a property with a value and all attribute combinations. */
|
||
|
static duk_ret_t test_value_attr_combinations(duk_context *ctx) {
|
||
|
int i;
|
||
|
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
for (i = 0; i < 8; i++) {
|
||
|
duk_push_sprintf(ctx, "my_key_%d", i);
|
||
|
duk_push_int(ctx, 123);
|
||
|
printf("top before: %ld\n", (long) duk_get_top(ctx));
|
||
|
duk_def_prop(ctx,
|
||
|
-3,
|
||
|
DUK_DEFPROP_HAVE_VALUE |
|
||
|
DUK_DEFPROP_HAVE_WRITABLE |
|
||
|
DUK_DEFPROP_HAVE_ENUMERABLE |
|
||
|
DUK_DEFPROP_HAVE_CONFIGURABLE |
|
||
|
(i & 1 ? DUK_DEFPROP_WRITABLE : 0) |
|
||
|
(i & 2 ? DUK_DEFPROP_ENUMERABLE : 0) |
|
||
|
(i & 4 ? DUK_DEFPROP_CONFIGURABLE : 0));
|
||
|
printf("top after: %ld\n", (long) duk_get_top(ctx));
|
||
|
}
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test presence of value and attributes; exercises the "tri-state"
|
||
|
* nature of attributes.
|
||
|
*/
|
||
|
static duk_ret_t test_value_attr_presence(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
/* First set the property to have all attributes true. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 123);
|
||
|
duk_def_prop(ctx,
|
||
|
-3,
|
||
|
DUK_DEFPROP_HAVE_VALUE |
|
||
|
DUK_DEFPROP_HAVE_WRITABLE |
|
||
|
DUK_DEFPROP_HAVE_ENUMERABLE |
|
||
|
DUK_DEFPROP_HAVE_CONFIGURABLE |
|
||
|
DUK_DEFPROP_WRITABLE |
|
||
|
DUK_DEFPROP_ENUMERABLE |
|
||
|
DUK_DEFPROP_CONFIGURABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Then turn the attributes off one-by-one. Configurable must
|
||
|
* be last to avoid TypeErrors.
|
||
|
*/
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_WRITABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_ENUMERABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_CONFIGURABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Same test for another property, but start with attributes
|
||
|
* cleared. However, configurable must be set for this to
|
||
|
* work so leave that out from the test.
|
||
|
*/
|
||
|
|
||
|
duk_push_string(ctx, "my_key_2");
|
||
|
duk_push_int(ctx, 321);
|
||
|
duk_def_prop(ctx,
|
||
|
-3,
|
||
|
DUK_DEFPROP_HAVE_VALUE |
|
||
|
DUK_DEFPROP_HAVE_WRITABLE |
|
||
|
DUK_DEFPROP_HAVE_ENUMERABLE |
|
||
|
DUK_DEFPROP_HAVE_CONFIGURABLE |
|
||
|
DUK_DEFPROP_CONFIGURABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Then turn the attributes on one-by-one. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_2");
|
||
|
duk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_2");
|
||
|
duk_def_prop(ctx, -2, DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test property creation with setter, getter, or both. Use a few attribute
|
||
|
* combinations at the same time (including not present = default).
|
||
|
*/
|
||
|
static duk_ret_t test_setget_only(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
/* Getter only. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter(ctx);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Setter only. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_2");
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_SETTER |
|
||
|
DUK_DEFPROP_HAVE_ENUMERABLE | 0 |
|
||
|
DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Getter and setter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_3");
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER |
|
||
|
DUK_DEFPROP_WRITABLE | /* Note: ignored, no "have writable" flag */
|
||
|
/* enumerable defaults */
|
||
|
DUK_DEFPROP_HAVE_CONFIGURABLE | 0);
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where we "have" a value, a getter, and a setter.
|
||
|
* This is an invalid property descriptor.
|
||
|
*/
|
||
|
static duk_ret_t test_value_and_setget(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 123); /* value */
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -5, DUK_DEFPROP_HAVE_VALUE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where we "have" writable (implies plain property)
|
||
|
* and setter (implies accessor property).
|
||
|
*/
|
||
|
static duk_ret_t test_writable_and_set(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_WRITABLE |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test a valid call where setter and getter are undefined. This causes
|
||
|
* them to be removed from the property.
|
||
|
*/
|
||
|
static duk_ret_t test_setget_undefined(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
/* First setup a setter and a getter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Remove getter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_undefined(ctx);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Remove setter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_undefined(ctx);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where getter is a non-object (but not undefined). */
|
||
|
static duk_ret_t test_getter_nonobject(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
/* First setup a setter and a getter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Try to set getter to a non-object */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 987);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where setter is a non-object (but not undefined). */
|
||
|
static duk_ret_t test_setter_nonobject(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
/* First setup a setter and a getter. */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
/* Try to set setter to a non-object */
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 987);
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where getter is a non-callable object. */
|
||
|
static duk_ret_t test_getter_noncallable(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_object(ctx); /* getter */
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test an invalid call where setter is a non-callable object. */
|
||
|
static duk_ret_t test_setter_noncallable(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_object(ctx); /* setter */
|
||
|
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Test that lightfuncs work as setter and getter. They get coerced to
|
||
|
* a full function in the process though.
|
||
|
*/
|
||
|
static duk_ret_t test_setget_lightfunc(duk_context *ctx) {
|
||
|
duk_push_object(ctx);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter_lightfunc(ctx);
|
||
|
push_setter_lightfunc(ctx);
|
||
|
duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER);
|
||
|
|
||
|
dump_object(ctx, -1);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Force addition of a new property into a non-extensible object. */
|
||
|
static duk_ret_t test_force_nonextensible_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.preventExtensions(obj);\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 321);
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_VALUE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_nonextensible(duk_context *ctx) {
|
||
|
return test_force_nonextensible_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_nonextensible(duk_context *ctx) {
|
||
|
return test_force_nonextensible_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force a non-configurable property configurable. */
|
||
|
static duk_ret_t test_force_set_configurable_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: true, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_configurable(duk_context *ctx) {
|
||
|
return test_force_set_configurable_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_configurable(duk_context *ctx) {
|
||
|
return test_force_set_configurable_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force a non-configurable property enumerable. */
|
||
|
static duk_ret_t test_force_set_enumerable_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_enumerable(duk_context *ctx) {
|
||
|
return test_force_set_enumerable_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_enumerable(duk_context *ctx) {
|
||
|
return test_force_set_enumerable_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force a non-configurable property writable. */
|
||
|
static duk_ret_t test_force_set_writable_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_writable(duk_context *ctx) {
|
||
|
return test_force_set_writable_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_writable(duk_context *ctx) {
|
||
|
return test_force_set_writable_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force value change for a non-configurable property. */
|
||
|
static duk_ret_t test_force_set_value_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 321);
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_VALUE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_value(duk_context *ctx) {
|
||
|
return test_force_set_value_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_value(duk_context *ctx) {
|
||
|
return test_force_set_value_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force setter/getter change for a non-configurable property. */
|
||
|
static duk_ret_t test_force_set_setget_raw(duk_context *ctx, duk_bool_t setter, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { set: function () {}, get: function () {}, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
if (setter) {
|
||
|
push_setter(ctx);
|
||
|
} else {
|
||
|
push_getter(ctx);
|
||
|
}
|
||
|
duk_def_prop(ctx, 0, (setter ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER) |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_getter(duk_context *ctx) {
|
||
|
return test_force_set_setget_raw(ctx, 0, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_getter(duk_context *ctx) {
|
||
|
return test_force_set_setget_raw(ctx, 0, 1);
|
||
|
}
|
||
|
static duk_ret_t test_fail_set_setter(duk_context *ctx) {
|
||
|
return test_force_set_setget_raw(ctx, 1, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_set_setter(duk_context *ctx) {
|
||
|
return test_force_set_setget_raw(ctx, 1, 1);
|
||
|
}
|
||
|
|
||
|
/* Force change from data to accessor property for non-configurable property.
|
||
|
* Also set the new value enumerable (to cover more cases).
|
||
|
*/
|
||
|
static duk_ret_t test_force_data2accessor_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
push_getter(ctx);
|
||
|
push_setter(ctx);
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE |
|
||
|
DUK_DEFPROP_HAVE_GETTER |
|
||
|
DUK_DEFPROP_HAVE_SETTER |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_data2accessor(duk_context *ctx) {
|
||
|
return test_force_data2accessor_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_data2accessor(duk_context *ctx) {
|
||
|
return test_force_data2accessor_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Force change from accessor to data property for non-configurable property.
|
||
|
* Also set the new value writable (to cover more cases).
|
||
|
*/
|
||
|
static duk_ret_t test_force_accessor2data_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { set: function () {}, get: function () {}, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_push_int(ctx, 321);
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_VALUE |
|
||
|
DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_accessor2data(duk_context *ctx) {
|
||
|
return test_force_accessor2data_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_accessor2data(duk_context *ctx) {
|
||
|
return test_force_accessor2data_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
/* Make array smaller, ignoring non-configurable elements. */
|
||
|
static duk_ret_t test_force_array_smaller_raw(duk_context *ctx, duk_bool_t length_writable, duk_bool_t forced) {
|
||
|
if (length_writable) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = [ 'foo', 'bar', 'quux' /*non-configurable*/, 'baz' ];\n"
|
||
|
" Object.defineProperty(obj, '2', { configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
} else {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = [ 'foo', 'bar', 'quux' /*non-configurable*/, 'baz' ];\n"
|
||
|
" Object.defineProperty(obj, '2', { configurable: false });\n"
|
||
|
" Object.defineProperty(obj, 'length', { writable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
}
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_push_string(ctx, "length");
|
||
|
duk_push_int(ctx, 1);
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_VALUE |
|
||
|
(forced ? DUK_DEFPROP_FORCE : 0));
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
|
||
|
duk_json_encode(ctx, 0);
|
||
|
printf("json: %s\n", duk_get_string(ctx, 0));
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_array_smaller(duk_context *ctx) {
|
||
|
return test_force_array_smaller_raw(ctx, 1, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_array_smaller(duk_context *ctx) {
|
||
|
return test_force_array_smaller_raw(ctx, 1, 1);
|
||
|
}
|
||
|
static duk_ret_t test_fail_array_smaller_nonwritablelength(duk_context *ctx) {
|
||
|
return test_force_array_smaller_raw(ctx, 0, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_array_smaller_nonwritablelength(duk_context *ctx) {
|
||
|
return test_force_array_smaller_raw(ctx, 0, 1);
|
||
|
}
|
||
|
|
||
|
/* Delete a non-deletable property in two steps: first use duk_def_prop()
|
||
|
* to make it configurable by force, and then delete it normally. Ideally
|
||
|
* duk_del_prop() would provide a forced variant so this could be done in
|
||
|
* one step.
|
||
|
*/
|
||
|
static duk_ret_t test_force_nondeletable_raw(duk_context *ctx, duk_bool_t forced) {
|
||
|
duk_eval_string(ctx,
|
||
|
"(function () {\n"
|
||
|
" var obj = {};\n"
|
||
|
" Object.defineProperty(obj, 'my_key_1', { value: 123, writable: false, enumerable: false, configurable: false });\n"
|
||
|
" return obj;\n"
|
||
|
"})()\n");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
printf("my_key_1 present: %d\n", (int) duk_has_prop_string(ctx, -1, "my_key_1"));
|
||
|
|
||
|
if (forced) {
|
||
|
duk_push_string(ctx, "my_key_1");
|
||
|
duk_def_prop(ctx, 0, DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE |
|
||
|
DUK_DEFPROP_FORCE);
|
||
|
} else {
|
||
|
/* Keep non-configurable for delete. */
|
||
|
}
|
||
|
|
||
|
duk_del_prop_string(ctx, -1, "my_key_1");
|
||
|
|
||
|
dump_object(ctx, 0);
|
||
|
printf("my_key_1 present: %d\n", (int) duk_has_prop_string(ctx, -1, "my_key_1"));
|
||
|
|
||
|
printf("final top: %ld\n", (long) duk_get_top(ctx));
|
||
|
return 0;
|
||
|
}
|
||
|
static duk_ret_t test_fail_nondeletable(duk_context *ctx) {
|
||
|
return test_force_nondeletable_raw(ctx, 0);
|
||
|
}
|
||
|
static duk_ret_t test_force_nondeletable(duk_context *ctx) {
|
||
|
return test_force_nondeletable_raw(ctx, 1);
|
||
|
}
|
||
|
|
||
|
void test(duk_context *ctx) {
|
||
|
/* Behaviors matching Object.defineProperty() */
|
||
|
TEST_SAFE_CALL(test_value_only);
|
||
|
TEST_SAFE_CALL(test_value_redefine);
|
||
|
TEST_SAFE_CALL(test_value_attr_combinations);
|
||
|
TEST_SAFE_CALL(test_value_attr_presence);
|
||
|
TEST_SAFE_CALL(test_setget_only);
|
||
|
TEST_SAFE_CALL(test_value_and_setget);
|
||
|
TEST_SAFE_CALL(test_writable_and_set);
|
||
|
TEST_SAFE_CALL(test_setget_undefined);
|
||
|
TEST_SAFE_CALL(test_getter_nonobject);
|
||
|
TEST_SAFE_CALL(test_setter_nonobject);
|
||
|
TEST_SAFE_CALL(test_getter_noncallable);
|
||
|
TEST_SAFE_CALL(test_setter_noncallable);
|
||
|
TEST_SAFE_CALL(test_setget_lightfunc);
|
||
|
|
||
|
/* Forced changes: ignore non-extensibility and non-configurability
|
||
|
* whenever possible and make changes anyway. Not all operations can
|
||
|
* still be forced, e.g. virtual properties cannot be changed.
|
||
|
*/
|
||
|
TEST_SAFE_CALL(test_fail_nonextensible);
|
||
|
TEST_SAFE_CALL(test_force_nonextensible);
|
||
|
TEST_SAFE_CALL(test_fail_set_configurable);
|
||
|
TEST_SAFE_CALL(test_force_set_configurable);
|
||
|
TEST_SAFE_CALL(test_fail_set_enumerable);
|
||
|
TEST_SAFE_CALL(test_force_set_enumerable);
|
||
|
TEST_SAFE_CALL(test_fail_set_writable);
|
||
|
TEST_SAFE_CALL(test_force_set_writable);
|
||
|
TEST_SAFE_CALL(test_fail_set_value);
|
||
|
TEST_SAFE_CALL(test_force_set_value);
|
||
|
TEST_SAFE_CALL(test_fail_set_getter);
|
||
|
TEST_SAFE_CALL(test_force_set_getter);
|
||
|
TEST_SAFE_CALL(test_fail_set_setter);
|
||
|
TEST_SAFE_CALL(test_force_set_setter);
|
||
|
TEST_SAFE_CALL(test_fail_data2accessor);
|
||
|
TEST_SAFE_CALL(test_force_data2accessor);
|
||
|
TEST_SAFE_CALL(test_fail_accessor2data);
|
||
|
TEST_SAFE_CALL(test_force_accessor2data);
|
||
|
TEST_SAFE_CALL(test_fail_array_smaller);
|
||
|
TEST_SAFE_CALL(test_force_array_smaller);
|
||
|
TEST_SAFE_CALL(test_fail_array_smaller_nonwritablelength);
|
||
|
TEST_SAFE_CALL(test_force_array_smaller_nonwritablelength);
|
||
|
TEST_SAFE_CALL(test_fail_nondeletable);
|
||
|
TEST_SAFE_CALL(test_force_nondeletable);
|
||
|
}
|