|
|
|
/*===
|
|
|
|
*** test_ex_writable (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
put rc=1
|
|
|
|
result: {"foo":"bar"}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_ex_writable (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
put rc=1
|
|
|
|
result: {"foo":"bar"}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_ex_nonwritable (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
get Math -> rc=1
|
|
|
|
Math.PI=3.141592653589793
|
|
|
|
put rc=0
|
|
|
|
Math.PI=3.141592653589793
|
|
|
|
final top: 2
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_ex_nonwritable (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
get Math -> rc=1
|
|
|
|
Math.PI=3.141592653589793
|
|
|
|
==> rc=1, result='TypeError: property not writable'
|
|
|
|
*** test_ex_accessor_wo_setter (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
eval:
|
|
|
|
(function () {
|
|
|
|
var o = {};
|
|
|
|
Object.defineProperty(o, 'foo', {
|
|
|
|
configurable: true,
|
|
|
|
extensible: true,
|
|
|
|
get: function() { print('getter'); }
|
|
|
|
// no setter
|
|
|
|
});
|
|
|
|
return o;
|
|
|
|
})()
|
|
|
|
top after eval: 1
|
|
|
|
put rc=0
|
|
|
|
result: {}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_ex_accessor_wo_setter (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
eval:
|
|
|
|
(function () {
|
|
|
|
var o = {};
|
|
|
|
Object.defineProperty(o, 'foo', {
|
|
|
|
configurable: true,
|
|
|
|
extensible: true,
|
|
|
|
get: function() { print('getter'); }
|
|
|
|
// no setter
|
|
|
|
});
|
|
|
|
return o;
|
|
|
|
})()
|
|
|
|
top after eval: 1
|
|
|
|
==> rc=1, result='TypeError: undefined setter for accessor'
|
|
|
|
*** test_ex_setter_throws (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
eval:
|
|
|
|
(function () {
|
|
|
|
var o = {};
|
|
|
|
Object.defineProperty(o, 'foo', {
|
|
|
|
configurable: true,
|
|
|
|
extensible: true,
|
|
|
|
get: function() { print('getter'); },
|
|
|
|
set: function() { print('setter, throw error'); throw 'setter error' }
|
|
|
|
});
|
|
|
|
return o;
|
|
|
|
})()
|
|
|
|
top after eval: 1
|
|
|
|
setter, throw error
|
|
|
|
==> rc=1, result='setter error'
|
|
|
|
*** test_ex_setter_throws (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
eval:
|
|
|
|
(function () {
|
|
|
|
var o = {};
|
|
|
|
Object.defineProperty(o, 'foo', {
|
|
|
|
configurable: true,
|
|
|
|
extensible: true,
|
|
|
|
get: function() { print('getter'); },
|
|
|
|
set: function() { print('setter, throw error'); throw 'setter error' }
|
|
|
|
});
|
|
|
|
return o;
|
|
|
|
})()
|
|
|
|
top after eval: 1
|
|
|
|
setter, throw error
|
|
|
|
==> rc=1, result='setter error'
|
|
|
|
*** test_new_extensible (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
put rc=1
|
|
|
|
result: {"foo":1,"bar":"quux"}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_new_extensible (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
put rc=1
|
|
|
|
result: {"foo":1,"bar":"quux"}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_new_not_extensible (duk_safe_call)
|
|
|
|
strict: 0
|
|
|
|
eval:
|
|
|
|
(function () { var o = { foo: 1 }; Object.preventExtensions(o); return o; })()
|
|
|
|
top after eval: 1
|
|
|
|
put rc=0
|
|
|
|
result: {"foo":1}
|
|
|
|
final top: 1
|
|
|
|
==> rc=0, result='undefined'
|
|
|
|
*** test_new_not_extensible (duk_pcall)
|
|
|
|
strict: 1
|
|
|
|
eval:
|
|
|
|
(function () { var o = { foo: 1 }; Object.preventExtensions(o); return o; })()
|
|
|
|
top after eval: 1
|
|
|
|
==> rc=1, result='TypeError: object not extensible'
|
|
|
|
===*/
|
|
|
|
|
|
|
|
/* Test property writing API call.
|
|
|
|
*
|
|
|
|
* Property write behavior is quite complex in Ecmascript and there
|
|
|
|
* are many Ecmascript testcases to cover the behavior. The purpose
|
|
|
|
* of this testcase is to ensure the exposed API behavior is as
|
|
|
|
* expected without covering every specification case. In particular,
|
|
|
|
* different throwing / return code combinations need to be covered,
|
|
|
|
* in both strict and non-strict mode.
|
|
|
|
*
|
|
|
|
* The test case functions are called both with duk_safe_call()
|
|
|
|
* and duk_pcall(). These two establish different execution
|
|
|
|
* contexts: one is called outside a Duktape/C activation and
|
|
|
|
* is non-strict, while the other is called inside a Duktape/C
|
|
|
|
* activation and is strict. A single test function is called
|
|
|
|
* from both contexts.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not covered cases include:
|
|
|
|
*
|
|
|
|
* - new property, ancestor has writable data property
|
|
|
|
* - new property, ancestor has write-protected data property
|
|
|
|
* - new property, ancestor has accessor with setter
|
|
|
|
* + setter succeeds
|
|
|
|
* + setter fails
|
|
|
|
* - new property, ancestor has accessor without setter
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* success */
|
|
|
|
int test_ex_writable(duk_context *ctx) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_string(ctx, "{ \"foo\": 1 }");
|
|
|
|
duk_json_decode(ctx, 0);
|
|
|
|
|
|
|
|
duk_push_string(ctx, "foo");
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
duk_json_encode(ctx, 0);
|
|
|
|
printf("result: %s\n", duk_to_string(ctx, 0));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strict: error
|
|
|
|
* non-strict: return 0
|
|
|
|
*/
|
|
|
|
int test_ex_nonwritable(duk_context *ctx) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
/* Math.PI is not writable */
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_global_object(ctx);
|
|
|
|
rc = duk_get_prop_string(ctx, -1, "Math"); /* -> [ global Math ] */
|
|
|
|
printf("get Math -> rc=%d\n", rc);
|
|
|
|
|
|
|
|
rc = duk_get_prop_string(ctx, -1, "PI");
|
|
|
|
printf("Math.PI=%s\n", duk_to_string(ctx, -1));
|
|
|
|
duk_pop(ctx);
|
|
|
|
|
|
|
|
duk_push_string(ctx, "PI");
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
rc = duk_get_prop_string(ctx, -1, "PI");
|
|
|
|
printf("Math.PI=%s\n", duk_to_string(ctx, -1));
|
|
|
|
duk_pop(ctx);
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strict: error
|
|
|
|
* non-strict: return 0
|
|
|
|
*/
|
|
|
|
int test_ex_accessor_wo_setter(duk_context *ctx) {
|
|
|
|
const char *src;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
src = "(function () {\n"
|
|
|
|
" var o = {};\n"
|
|
|
|
" Object.defineProperty(o, 'foo', {\n"
|
|
|
|
" configurable: true,\n"
|
|
|
|
" extensible: true,\n"
|
|
|
|
" get: function() { print('getter'); }\n"
|
|
|
|
" // no setter\n"
|
|
|
|
" });\n"
|
|
|
|
" return o;\n"
|
|
|
|
"})()";
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_string(ctx, src);
|
|
|
|
printf("eval:\n%s\n", duk_get_string(ctx, -1));
|
|
|
|
duk_eval(ctx);
|
|
|
|
printf("top after eval: %d\n", duk_get_top(ctx));
|
|
|
|
|
|
|
|
duk_push_string(ctx, "foo");
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
duk_json_encode(ctx, 0);
|
|
|
|
printf("result: %s\n", duk_to_string(ctx, 0));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strict: setter error propagates
|
|
|
|
* non-strict: same
|
|
|
|
*/
|
|
|
|
int test_ex_setter_throws(duk_context *ctx) {
|
|
|
|
const char *src;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
src = "(function () {\n"
|
|
|
|
" var o = {};\n"
|
|
|
|
" Object.defineProperty(o, 'foo', {\n"
|
|
|
|
" configurable: true,\n"
|
|
|
|
" extensible: true,\n"
|
|
|
|
" get: function() { print('getter'); },\n"
|
|
|
|
" set: function() { print('setter, throw error'); throw 'setter error' }\n"
|
|
|
|
" });\n"
|
|
|
|
" return o;\n"
|
|
|
|
"})()";
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_string(ctx, src);
|
|
|
|
printf("eval:\n%s\n", duk_get_string(ctx, -1));
|
|
|
|
duk_eval(ctx);
|
|
|
|
printf("top after eval: %d\n", duk_get_top(ctx));
|
|
|
|
|
|
|
|
duk_push_string(ctx, "foo");
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
duk_json_encode(ctx, 0);
|
|
|
|
printf("result: %s\n", duk_to_string(ctx, 0));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* success */
|
|
|
|
int test_new_extensible(duk_context *ctx) {
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_string(ctx, "{ \"foo\": 1 }");
|
|
|
|
duk_json_decode(ctx, 0);
|
|
|
|
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
duk_push_string(ctx, "quux");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
duk_json_encode(ctx, 0);
|
|
|
|
printf("result: %s\n", duk_to_string(ctx, 0));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strict: error
|
|
|
|
* non-strict: return 0
|
|
|
|
*/
|
|
|
|
int test_new_not_extensible(duk_context *ctx) {
|
|
|
|
const char *src;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
printf("strict: %d\n", duk_is_strict_call(ctx));
|
|
|
|
|
|
|
|
src = "(function () { var o = { foo: 1 }; Object.preventExtensions(o); return o; })()";
|
|
|
|
|
|
|
|
duk_set_top(ctx, 0);
|
|
|
|
duk_push_string(ctx, src);
|
|
|
|
printf("eval:\n%s\n", duk_get_string(ctx, -1));
|
|
|
|
duk_eval(ctx);
|
|
|
|
printf("top after eval: %d\n", duk_get_top(ctx));
|
|
|
|
|
|
|
|
duk_push_string(ctx, "bar");
|
|
|
|
duk_push_string(ctx, "quux");
|
|
|
|
rc = duk_put_prop(ctx, -3);
|
|
|
|
printf("put rc=%d\n", rc);
|
|
|
|
|
|
|
|
duk_json_encode(ctx, 0);
|
|
|
|
printf("result: %s\n", duk_to_string(ctx, 0));
|
|
|
|
|
|
|
|
printf("final top: %d\n", duk_get_top(ctx));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TEST(func) do { \
|
|
|
|
TEST_SAFE_CALL(func); \
|
|
|
|
TEST_PCALL(func); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
void test(duk_context *ctx) {
|
|
|
|
/*
|
|
|
|
* Cases where own property already exists
|
|
|
|
*/
|
|
|
|
|
|
|
|
TEST(test_ex_writable);
|
|
|
|
TEST(test_ex_nonwritable);
|
|
|
|
TEST(test_ex_accessor_wo_setter);
|
|
|
|
TEST(test_ex_setter_throws);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cases where no own property, possibly ancestor
|
|
|
|
* property of same name
|
|
|
|
*/
|
|
|
|
|
|
|
|
TEST(test_new_extensible);
|
|
|
|
TEST(test_new_not_extensible);
|
|
|
|
}
|
|
|
|
|