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.
348 lines
8.7 KiB
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);
|
|
}
|
|
|