Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
duktape/tests/api/test-get-set-magic.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
167 lines (138 sloc)
3.95 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Test setting and getting the Duktape/C function magic value. | |
* | |
* The magic value is useful in sharing a single native helper | |
* with multiple ECMAScript bindings, with the helper's behavior | |
* being controlled by flags or other values in the magic value. | |
* The magic value is stored cheaply without needing a property | |
* slot. | |
*/ | |
/*=== | |
*** test_1 (duk_safe_call) | |
magic: 4660 | |
magic: 4660 | |
magic: 32767 | |
magic: 32767 | |
magic: -32768 | |
magic: -32768 | |
magic: -16657 | |
magic: -16657 | |
final top: 2 | |
==> rc=0, result='undefined' | |
*** test_2 (duk_safe_call) | |
==> rc=1, result='TypeError: unexpected type' | |
*** test_3 (duk_safe_call) | |
==> rc=1, result='TypeError: nativefunction required, found [object Function] (stack index -1)' | |
*** test_4 (duk_safe_call) | |
INFO: log line<LF> | |
WARN: log line<LF> | |
ERROR: log line<CR><LF> | |
FATAL: log line<LF> | |
final top: 4 | |
==> rc=0, result='undefined' | |
===*/ | |
static duk_ret_t my_func(duk_context *ctx) { | |
printf("magic: %ld\n", (long) duk_get_current_magic(ctx)); | |
return 0; | |
} | |
static duk_ret_t test_1(duk_context *ctx, void *udata) { | |
(void) udata; | |
duk_push_c_function(ctx, my_func, 0); | |
duk_push_undefined(ctx); /* dummy filler */ | |
duk_set_magic(ctx, -2, 0x1234); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -2)); | |
duk_dup(ctx, -2); | |
duk_call(ctx, 0); | |
duk_pop(ctx); | |
duk_set_magic(ctx, -2, 0x7fff); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -2)); | |
duk_dup(ctx, -2); | |
duk_call(ctx, 0); | |
duk_pop(ctx); | |
duk_set_magic(ctx, -2, -0x8000); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -2)); | |
duk_dup(ctx, -2); | |
duk_call(ctx, 0); | |
duk_pop(ctx); | |
/* 0xdeadbeef gets truncated to 0xffffbeef == -16657 */ | |
duk_set_magic(ctx, -2, 0xdeadbeefUL); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -2)); | |
duk_dup(ctx, -2); | |
duk_call(ctx, 0); | |
duk_pop(ctx); | |
printf("final top: %ld\n", (long) duk_get_top(ctx)); | |
return 0; | |
} | |
static duk_ret_t test_2(duk_context *ctx, void *udata) { | |
(void) udata; | |
/* duk_get_magic() is strict: incorrect target type throws an error. | |
* This minimizes compiled function size and magic manipulation is | |
* rare. | |
*/ | |
duk_eval_string(ctx, "(function () {})"); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -1)); | |
return 0; | |
} | |
static duk_ret_t test_3(duk_context *ctx, void *udata) { | |
(void) udata; | |
/* duk_set_magic() is similarly strict. */ | |
duk_eval_string(ctx, "(function () {})"); | |
duk_set_magic(ctx, -1, 0x4321); | |
printf("magic: %ld\n", (long) duk_get_magic(ctx, -1)); | |
return 0; | |
} | |
/* | |
* Extended version of the guide example: illustrate how a magic value can | |
* be used to share a single native log write helper. | |
*/ | |
static duk_ret_t guide_example(duk_context *ctx) { | |
const char *prefix[4] = { "INFO", "WARN", "ERROR", "FATAL" }; | |
duk_int_t magic = duk_get_current_magic(ctx); | |
printf("%s: %s", prefix[magic & 0x03], duk_safe_to_string(ctx, 0)); | |
if (magic & 0x04) { | |
printf("<CR><LF>\n"); | |
} else { | |
printf("<LF>\n"); | |
} | |
return 0; | |
} | |
static duk_ret_t test_4(duk_context *ctx, void *udata) { | |
(void) udata; | |
duk_push_c_function(ctx, guide_example, 1); | |
duk_set_magic(ctx, -1, 0); /* INFO */ | |
duk_push_c_function(ctx, guide_example, 1); | |
duk_set_magic(ctx, -1, 1); /* WARN */ | |
duk_push_c_function(ctx, guide_example, 1); | |
duk_set_magic(ctx, -1, 2 | 0x04); /* ERROR */ | |
duk_push_c_function(ctx, guide_example, 1); | |
duk_set_magic(ctx, -1, 3); /* FATAL */ | |
/* 0: func with INFO level | |
* 1: func with WARN level | |
* 2: func with ERROR level and CRLF newline | |
* 3: func with FATAL level | |
*/ | |
duk_dup(ctx, 0); | |
duk_push_string(ctx, "log line"); | |
duk_call(ctx, 1); | |
duk_pop(ctx); | |
duk_dup(ctx, 1); | |
duk_push_string(ctx, "log line"); | |
duk_call(ctx, 1); | |
duk_pop(ctx); | |
duk_dup(ctx, 2); | |
duk_push_string(ctx, "log line"); | |
duk_call(ctx, 1); | |
duk_pop(ctx); | |
duk_dup(ctx, 3); | |
duk_push_string(ctx, "log line"); | |
duk_call(ctx, 1); | |
duk_pop(ctx); | |
printf("final top: %ld\n", (long) duk_get_top(ctx)); | |
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_4); | |
} |