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.
 
 
 
 
 
 

348 lines
8.7 KiB

/*===
*** test_ex_writable (duk_safe_call)
strict: 1
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: 1
get Math -> rc=1
Math.PI=3.141592653589793
==> rc=1, result='TypeError: not writable'
*** test_ex_nonwritable (duk_pcall)
strict: 1
get Math -> rc=1
Math.PI=3.141592653589793
==> rc=1, result='TypeError: not writable'
*** test_ex_accessor_wo_setter (duk_safe_call)
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: setter 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: setter undefined'
*** test_ex_setter_throws (duk_safe_call)
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_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: 1
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: 1
eval:
(function () { var o = { foo: 1 }; Object.preventExtensions(o); return o; })()
top after eval: 1
==> rc=1, result='TypeError: not extensible'
*** 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: 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.
* Duktape/C contexts are now (since Duktape 0.12.0) always strict,
* so the non-strict case doesn't happen when using Duktape/C API.
*
* 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 the other is called
* inside a Duktape/C activation. Both cases are now 'strict' (since
* Duktape 0.12.0). 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 */
static duk_ret_t test_ex_writable(duk_context *ctx) {
duk_ret_t rc;
printf("strict: %d\n", (int) 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", (int) rc);
duk_json_encode(ctx, 0);
printf("result: %s\n", duk_to_string(ctx, 0));
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/* strict: error
* (non-strict: return 0)
*/
static duk_ret_t test_ex_nonwritable(duk_context *ctx) {
duk_ret_t rc;
printf("strict: %d\n", (int) 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", (int) 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", (int) 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: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/* strict: error
* (non-strict: return 0)
*/
static duk_ret_t test_ex_accessor_wo_setter(duk_context *ctx) {
const char *src;
duk_ret_t rc;
printf("strict: %d\n", (int) 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: %ld\n", (long) 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", (int) rc);
duk_json_encode(ctx, 0);
printf("result: %s\n", duk_to_string(ctx, 0));
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/* strict: setter error propagates
* (non-strict: same)
*/
static duk_ret_t test_ex_setter_throws(duk_context *ctx) {
const char *src;
duk_ret_t rc;
printf("strict: %d\n", (int) 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: %ld\n", (long) 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", (int) rc);
duk_json_encode(ctx, 0);
printf("result: %s\n", duk_to_string(ctx, 0));
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
printf("strict: %d\n", (int) duk_is_strict_call(ctx));
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/* success */
static duk_ret_t test_new_extensible(duk_context *ctx) {
duk_ret_t rc;
printf("strict: %d\n", (int) 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", (int) rc);
duk_json_encode(ctx, 0);
printf("result: %s\n", duk_to_string(ctx, 0));
printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0;
}
/* strict: error
* (non-strict: return 0)
*/
static duk_ret_t test_new_not_extensible(duk_context *ctx) {
const char *src;
duk_ret_t rc;
printf("strict: %d\n", (int) 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: %ld\n", (long) 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", (int) rc);
duk_json_encode(ctx, 0);
printf("result: %s\n", duk_to_string(ctx, 0));
printf("final top: %ld\n", (long) 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);
}