jerryscript/tests/unit-ext/test-ext-arg.c
Dániel Bátyai 9860d66a56
Rework the public API (#4829)
Related to #4186.

Some notable changes:
  - The term 'Error' now strictly refers to native Error objects defined in
    the ECMA standard, which are ordinary objects. All other uses of
    'error' or 'error reference' where the term refers to a thrown value is
    now called 'exception'.

  - Simplified the naming scheme of many String API functions. These functions
    will now also take an 'encoding' argument to specify the desired
    encoding in which to operate.

  - Removed the substring-copy-to-buffer functions. These functions
    behaved awkwardly, as they use character index to specify the
    start/end positions, and were mostly used incorrectly with byte
    offsets instead. The functionality can still be replicated with
    other functions if necessary.

  - String-to-buffer functions will no longer fail if the buffer is not
    sufficiently large, the string will instead be cropped.

  - Fixed the usage of the '_sz' prefix in many API functions. The term
    'sz' means zero-terminated string in hungarian notation, this was
    used incorrectly in many cases.

  - Renamed most of the public API functions to have shorter, more on-point
    names, rather than the often too long descriptive names. Functions are now
    also grouped by the type of value they operate on, where this makes
    sense.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2021-12-06 10:20:09 +01:00

869 lines
32 KiB
C

/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Unit test for jerry-ext/args.
*/
#include <string.h>
#include "jerryscript.h"
#include "jerryscript-ext/arg.h"
#include "test-common.h"
static const jerry_char_t test_source[] =
TEST_STRING_LITERAL ("var arg1 = true;"
"var arg2 = 10.5;"
"var arg3 = 'abc';"
"var arg4 = function foo() {};"
"test_validator1(arg1, arg2, arg3, arg4);"
"arg1 = new Boolean(true);"
"arg3 = new String('abc');"
"test_validator1(arg1, arg2, arg3);"
"test_validator1(arg1, arg2, '');"
"arg2 = new Number(10.5);"
"test_validator1(arg1, arg2, arg3);"
"test_validator1(arg1, 10.5, 'abcdef');"
"test_validator3(arg1, arg1);"
"test_validator3(arg1);"
"test_validator3();"
"test_validator3(undefined, undefined);"
"var obj_a = new MyObjectA();"
"var obj_b = new MyObjectB();"
"test_validator2.call(obj_a, 5);"
"test_validator2.call(obj_b, 5);"
"test_validator2.call(obj_a, 1);"
"var obj1 = {prop1:true, prop2:'1.5'};"
"test_validator_prop1(obj1);"
"test_validator_prop2(obj1);"
"test_validator_prop2();"
"var obj2 = {prop1:true};"
"Object.defineProperty(obj2, 'prop2', {"
" get: function() { throw new TypeError('prop2 error') }"
"});"
"test_validator_prop3(obj2);"
"test_validator_int1(-1000, 1000, 128, -1000, 1000, -127,"
" -1000, 4294967297, 65536, -2200000000, 4294967297, -2147483647);"
"test_validator_int2(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5, Infinity, -Infinity, 300.5, 300.5);"
"test_validator_int3(NaN);"
"var arr = [1, 2];"
"test_validator_array1(arr);"
"test_validator_array1();"
"test_validator_array2(arr);"
"test_validator_restore(false, 3.0);"
"test_validator_restore(3.0, false);");
static const jerry_object_native_info_t thing_a_info = {
.free_cb = NULL,
.number_of_references = 0,
.offset_of_references = 0,
};
static const jerry_object_native_info_t thing_b_info = {
.free_cb = NULL,
.number_of_references = 0,
.offset_of_references = 0,
};
typedef struct
{
int x;
} my_type_a_t;
typedef struct
{
bool x;
} my_type_b_t;
static my_type_a_t my_thing_a;
static my_type_b_t my_thing_b;
static int validator1_count = 0;
static int validator2_count = 0;
static int validator3_count = 0;
static int validator_int_count = 0;
static int validator_prop_count = 0;
static int validator_array_count = 0;
static int validator_restore_count = 0;
/**
* The handler should have following arguments:
* this: Ignore.
* arg1: Bool.
* arg2: Number. It must be strict primitive number.
* arg3: String.
* arg4: function. It is an optional argument.
*
*/
static jerry_value_t
test_validator1_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
bool arg1;
double arg2 = 0.0;
char arg3[5] = "1234";
jerry_value_t arg4 = jerry_undefined ();
jerryx_arg_t mapping[] = { /* ignore this */
jerryx_arg_ignore (),
/* 1st argument should be boolean */
jerryx_arg_boolean (&arg1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
/* 2nd argument should be strict number */
jerryx_arg_number (&arg2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED),
/* 3th argument should be string */
jerryx_arg_string (arg3, 5, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
/* 4th argument should be function, and it is optional */
jerryx_arg_function (&arg4, JERRYX_ARG_OPTIONAL)
};
jerry_value_t is_ok =
jerryx_arg_transform_this_and_args (call_info_p->this_value, args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
if (validator1_count == 0)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "abc") == 0);
TEST_ASSERT (jerry_value_is_function (arg4));
}
else if (validator1_count == 1)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "abc") == 0);
TEST_ASSERT (jerry_value_is_undefined (arg4));
}
else if (validator1_count == 2)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2 == 10.5);
TEST_ASSERT (strcmp (arg3, "") == 0);
TEST_ASSERT (jerry_value_is_undefined (arg4));
}
else
{
TEST_ASSERT (jerry_value_is_exception (is_ok));
}
jerry_value_free (is_ok);
jerry_value_free (arg4);
validator1_count++;
return jerry_undefined ();
} /* test_validator1_handler */
/**
* The JS argument should be number, whose value is equal with the extra_info .
*/
static jerry_value_t
my_custom_transform (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
const jerryx_arg_t *c_arg_p) /**< the native arg */
{
jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
jerry_value_t to_number = jerry_value_to_number (js_arg);
if (jerry_value_is_exception (to_number))
{
jerry_value_free (to_number);
return jerry_throw_sz (JERRY_ERROR_TYPE, "It can not be converted to a number.");
}
int expected_num = (int) c_arg_p->extra_info;
int get_num = (int) jerry_value_as_number (to_number);
if (get_num != expected_num)
{
return jerry_throw_sz (JERRY_ERROR_TYPE, "Number value is not expected.");
}
return jerry_undefined ();
} /* my_custom_transform */
/**
* The handler should have following arguments:
* this: with native pointer whose type is bind_a_info.
* arg1: should pass the custom tranform function.
*/
static jerry_value_t
test_validator2_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
my_type_a_t *thing_p;
jerryx_arg_t mapping[] = { /* this should has native pointer, whose type is thing_a_info */
jerryx_arg_native_pointer ((void **) &thing_p, &thing_a_info, JERRYX_ARG_REQUIRED),
/* custom tranform function */
jerryx_arg_custom (NULL, 5, my_custom_transform)
};
jerry_value_t is_ok =
jerryx_arg_transform_this_and_args (call_info_p->this_value, args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
if (validator2_count == 0)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (thing_p == &my_thing_a);
TEST_ASSERT (thing_p->x == 1);
}
else
{
TEST_ASSERT (jerry_value_is_exception (is_ok));
}
jerry_value_free (is_ok);
validator2_count++;
return jerry_undefined ();
} /* test_validator2_handler */
/**
* The handler should have following arguments:
* arg1: Bool. It is an optional argument.
*
*/
static jerry_value_t
test_validator3_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
bool arg1 = false;
bool arg2 = false;
jerryx_arg_t mapping[] = {
/* ignore this */
jerryx_arg_ignore (),
/* 1th argument should be boolean, and it is optional */
jerryx_arg_boolean (&arg1, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL),
/* 2nd argument should be boolean, and it is optional */
jerryx_arg_boolean (&arg2, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL),
};
jerry_value_t is_ok =
jerryx_arg_transform_this_and_args (call_info_p->this_value, args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
if (validator3_count == 0)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (arg1);
TEST_ASSERT (arg2);
}
else if (validator3_count == 1)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (arg1);
/* arg2 must be unchanged */
TEST_ASSERT (!arg2);
}
else if (validator3_count == 2)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
/* arg1 must be unchanged */
TEST_ASSERT (!arg1);
/* arg2 must be unchanged */
TEST_ASSERT (!arg2);
}
else if (validator3_count == 3)
{
TEST_ASSERT (!jerry_value_is_exception (is_ok));
/* arg1 must be unchanged */
TEST_ASSERT (!arg1);
/* arg2 must be unchanged */
TEST_ASSERT (!arg2);
}
jerry_value_free (is_ok);
validator3_count++;
return jerry_undefined ();
} /* test_validator3_handler */
/**
* Calling jerryx_arg_transform_object_properties directly.
*/
static jerry_value_t
test_validator_prop1_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
JERRY_UNUSED (args_cnt);
bool native1 = false;
double native2 = 0;
double native3 = 3;
const char *name_p[] = { "prop1", "prop2", "prop3" };
jerryx_arg_t mapping[] = { jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL) };
jerry_value_t is_ok = jerryx_arg_transform_object_properties (args_p[0],
(const jerry_char_t **) name_p,
ARRAY_SIZE (name_p),
mapping,
ARRAY_SIZE (mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (native1);
TEST_ASSERT (native2 == 1.5);
TEST_ASSERT (native3 == 3);
validator_prop_count++;
return jerry_undefined ();
} /* test_validator_prop1_handler */
/**
* Calling jerryx_arg_transform_object_properties indirectly by
* using jerryx_arg_object_properties.
*/
static jerry_value_t
test_validator_prop2_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
bool native1 = false;
double native2 = 0;
double native3 = 3;
jerryx_arg_object_props_t prop_info;
const char *name_p[] = { "prop1", "prop2", "prop3" };
jerryx_arg_t prop_mapping[] = { jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL) };
prop_info.name_p = (const jerry_char_t **) name_p;
prop_info.name_cnt = 3;
prop_info.c_arg_p = prop_mapping;
prop_info.c_arg_cnt = 3;
jerryx_arg_t mapping[] = {
jerryx_arg_object_properties (&prop_info, JERRYX_ARG_OPTIONAL),
};
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
if (validator_prop_count == 1)
{
TEST_ASSERT (native1);
TEST_ASSERT (native2 == 1.5);
TEST_ASSERT (native3 == 3);
}
validator_prop_count++;
return jerry_undefined ();
} /* test_validator_prop2_handler */
static jerry_value_t
test_validator_prop3_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
JERRY_UNUSED (args_cnt);
bool native1 = false;
bool native2 = true;
const char *name_p[] = { "prop1", "prop2" };
jerryx_arg_t mapping[] = {
jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_boolean (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
};
jerry_value_t is_ok = jerryx_arg_transform_object_properties (args_p[0],
(const jerry_char_t **) name_p,
ARRAY_SIZE (name_p),
mapping,
ARRAY_SIZE (mapping));
TEST_ASSERT (jerry_value_is_exception (is_ok));
TEST_ASSERT (!native1);
TEST_ASSERT (native2);
validator_prop_count++;
jerry_value_free (is_ok);
return jerry_undefined ();
} /* test_validator_prop3_handler */
/*
* args_p[0-2] are uint8, args_p[3-5] are int8, args_p[6-8] are uint32, args_p[9-11] are int32.
*/
static jerry_value_t
test_validator_int1_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
uint8_t num0, num1, num2;
int8_t num3, num4, num5;
uint32_t num6, num7, num8;
int32_t num9, num10, num11;
jerryx_arg_t mapping[] = {
jerryx_arg_uint8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_uint8 (&num1, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_uint8 (&num2, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num3, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num4, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num5, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_uint32 (&num6, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_uint32 (&num7, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_uint32 (&num8, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int32 (&num9, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int32 (&num10, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int32 (&num11, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED)
};
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (num0 == 0);
TEST_ASSERT (num1 == 255);
TEST_ASSERT (num2 == 128);
TEST_ASSERT (num3 == -128);
TEST_ASSERT (num4 == 127);
TEST_ASSERT (num5 == -127);
TEST_ASSERT (num6 == 0);
TEST_ASSERT (num7 == 4294967295);
TEST_ASSERT (num8 == 65536);
TEST_ASSERT (num9 == -2147483648);
TEST_ASSERT (num10 == 2147483647);
TEST_ASSERT (num11 == -2147483647);
jerry_value_free (is_ok);
validator_int_count++;
return jerry_undefined ();
} /* test_validator_int1_handler */
static jerry_value_t
test_validator_int2_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
int8_t num0, num1, num2, num3, num4, num5, num6, num7, num8, num9;
num8 = 123;
num9 = 123;
jerryx_arg_t mapping[] = {
jerryx_arg_int8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num1, JERRYX_ARG_FLOOR, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num2, JERRYX_ARG_CEIL, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num3, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num4, JERRYX_ARG_FLOOR, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num5, JERRYX_ARG_CEIL, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num6, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num7, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num8, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_int8 (&num9, JERRYX_ARG_ROUND, JERRYX_ARG_NO_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
};
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (jerry_value_is_exception (is_ok));
TEST_ASSERT (num0 == -2);
TEST_ASSERT (num1 == -2);
TEST_ASSERT (num2 == -1);
TEST_ASSERT (num3 == 2);
TEST_ASSERT (num4 == 1);
TEST_ASSERT (num5 == 2);
TEST_ASSERT (num6 == 127);
TEST_ASSERT (num7 == -128);
TEST_ASSERT (num8 == 127);
TEST_ASSERT (num9 == 123);
jerry_value_free (is_ok);
validator_int_count++;
return jerry_undefined ();
} /* test_validator_int2_handler */
static jerry_value_t
test_validator_int3_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
int8_t num0;
jerryx_arg_t mapping[] = {
jerryx_arg_int8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
};
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (jerry_value_is_exception (is_ok));
jerry_value_free (is_ok);
validator_int_count++;
return jerry_undefined ();
} /* test_validator_int3_handler */
static jerry_value_t
test_validator_array1_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
double native1 = 0;
double native2 = 0;
double native3 = 0;
jerryx_arg_array_items_t arr_info;
jerryx_arg_t item_mapping[] = { jerryx_arg_number (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL) };
arr_info.c_arg_p = item_mapping;
arr_info.c_arg_cnt = 3;
jerryx_arg_t mapping[] = {
jerryx_arg_array (&arr_info, JERRYX_ARG_OPTIONAL),
};
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
if (validator_array_count == 0)
{
TEST_ASSERT (native1 == 1);
TEST_ASSERT (native2 == 2);
TEST_ASSERT (native3 == 0);
}
validator_array_count++;
return jerry_undefined ();
} /* test_validator_array1_handler */
static jerry_value_t
test_validator_array2_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
JERRY_UNUSED (args_cnt);
double native1 = 0;
bool native2 = false;
jerryx_arg_t item_mapping[] = { jerryx_arg_number (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_boolean (&native2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED) };
jerry_value_t is_ok = jerryx_arg_transform_array (args_p[0], item_mapping, ARRAY_SIZE (item_mapping));
TEST_ASSERT (jerry_value_is_exception (is_ok));
TEST_ASSERT (native1 == 1);
TEST_ASSERT (!native2);
validator_array_count++;
jerry_value_free (is_ok);
return jerry_undefined ();
} /* test_validator_array2_handler */
/**
* This validator is designed to test the
* jerryx_arg_js_iterator_restore function. We'll introduce a union
* type to hold a bool or double and a transform function that will
* look for this type. Then, we'll call the handler with two
* parameters, one bool and one double and see if we correctly build
* the union types for each parameter. To check that the code protects
* against backing up too far, when the check for the double fails,
* we'll "restore" the stack three times; this shouldn't break
* anything.
*/
/*
* This enumeration type specifies the kind of thing held in the union.
*/
typedef enum
{
DOUBLE_VALUE,
BOOL_VALUE
} union_type_t;
/*
* This struct holds either a boolean or double in a union and has a
* second field that describes the type held in the union.
*/
typedef struct
{
union_type_t type_of_value;
union
{
double double_field;
bool bool_field;
} value;
} double_or_bool_t;
/**
* This creates a jerryx_arg_t that can be used like any
* of the installed functions, like jerryx_arg_bool().
*/
#define jerryx_arg_double_or_bool_t(value_ptr, coerce_or_not, optional_or_not, last_parameter) \
jerryx_arg_custom ( \
value_ptr, \
(uintptr_t) \
& ((uintptr_t[]){ (uintptr_t) coerce_or_not, (uintptr_t) optional_or_not, (uintptr_t) last_parameter }), \
jerry_arg_to_double_or_bool_t)
/*
* This function is the argument validator used in the above macro called
* jerryx_arg_double_or_bool. It calls jerryx_arg_js_iterator_restore()
* more times than it should to ensure that calling that function too
* often doesn't cause an error.
*/
static jerry_value_t
jerry_arg_to_double_or_bool_t (jerryx_arg_js_iterator_t *js_arg_iter_p, const jerryx_arg_t *c_arg_p)
{
/* c_arg_p has two fields: dest, which is a pointer to the data that
* gets filled in, and extra_info, which contains the flags used to
* control coercion and optional-ness, respectively. For this test,
* we added an extra flag that tells us that we're working on the
* last parameter; when we know it's the last parameter, we'll "restore"
* the stack more times than there are actual stack values to ensure
* that the restore function doesn't produce an error. */
double_or_bool_t *destination = c_arg_p->dest;
uintptr_t *extra_info = (uintptr_t *) (c_arg_p->extra_info);
jerryx_arg_t conversion_function;
jerry_value_t conversion_result;
jerry_value_t restore_result;
bool last_parameter = (extra_info[2] == 1);
validator_restore_count++;
conversion_function = jerryx_arg_number ((double *) (&(destination->value.double_field)),
(jerryx_arg_coerce_t) extra_info[0],
JERRYX_ARG_OPTIONAL);
conversion_result = conversion_function.func (js_arg_iter_p, &conversion_function);
if (!jerry_value_is_exception (conversion_result))
{
if (last_parameter)
{
/* The stack is only two parameters high, but we want to ensure that
* excessive calls will not result in aberrant behavior... */
jerryx_arg_js_iterator_restore (js_arg_iter_p);
jerryx_arg_js_iterator_restore (js_arg_iter_p);
jerryx_arg_js_iterator_restore (js_arg_iter_p);
restore_result = jerryx_arg_js_iterator_restore (js_arg_iter_p);
TEST_ASSERT (jerry_value_is_undefined (restore_result));
}
destination->type_of_value = DOUBLE_VALUE;
return conversion_result;
}
jerryx_arg_js_iterator_restore (js_arg_iter_p);
conversion_function = jerryx_arg_boolean ((bool *) (&(destination->value.bool_field)),
(jerryx_arg_coerce_t) extra_info[0],
(jerryx_arg_optional_t) extra_info[1]);
jerry_value_free (conversion_result);
conversion_result = conversion_function.func (js_arg_iter_p, &conversion_function);
if (!jerry_value_is_exception (conversion_result))
{
if (last_parameter)
{
/* The stack is only two parameters high, but we want to ensure that
* excessive calls will not result in aberrant behavior... */
jerryx_arg_js_iterator_restore (js_arg_iter_p);
jerryx_arg_js_iterator_restore (js_arg_iter_p);
jerryx_arg_js_iterator_restore (js_arg_iter_p);
restore_result = jerryx_arg_js_iterator_restore (js_arg_iter_p);
TEST_ASSERT (jerry_value_is_undefined (restore_result));
}
destination->type_of_value = BOOL_VALUE;
return conversion_result;
}
/* Fall through indicates that whatever they gave us, it wasn't
* one of the types we were expecting... */
jerry_value_free (conversion_result);
return jerry_throw_sz (JERRY_ERROR_TYPE, "double_or_bool-type error.");
} /* jerry_arg_to_double_or_bool_t */
/**
* This validator expects two parameters, one a bool and one a double -- the
* order doesn't matter (so we'll call it twice with the orders reversed).
*/
static jerry_value_t
test_validator_restore_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (call_info_p);
double_or_bool_t arg1;
double_or_bool_t arg2;
jerryx_arg_t item_mapping[] = { jerryx_arg_double_or_bool_t (&arg1, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED, 0),
jerryx_arg_double_or_bool_t (&arg2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED, 1) };
jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, item_mapping, ARRAY_SIZE (item_mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
/* We are going to call this with [false, 3.0] and [3.0, false] parameters... */
bool arg1_is_false = (arg1.type_of_value == BOOL_VALUE && arg1.value.bool_field == false);
bool arg1_is_three = (arg1.type_of_value == DOUBLE_VALUE && arg1.value.double_field == 3.0);
bool arg2_is_false = (arg2.type_of_value == BOOL_VALUE && arg2.value.bool_field == false);
bool arg2_is_three = (arg2.type_of_value == DOUBLE_VALUE && arg2.value.double_field == 3.0);
TEST_ASSERT ((arg1_is_false && arg2_is_three) || (arg1_is_three && arg2_is_false));
jerry_value_free (is_ok);
return jerry_undefined ();
} /* test_validator_restore_handler */
static void
test_utf8_string (void)
{
/* test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
jerry_value_t str = jerry_string_sz ("\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
char expect_utf8_buf[] = "\x73\x74\x72\x3a \xf0\x90\x90\x80";
size_t buf_len = sizeof (expect_utf8_buf) - 1;
JERRY_VLA (char, buf, buf_len + 1);
jerryx_arg_t mapping[] = {
jerryx_arg_utf8_string (buf, (uint32_t) buf_len + 1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
};
jerry_value_t is_ok = jerryx_arg_transform_args (&str, 1, mapping, ARRAY_SIZE (mapping));
TEST_ASSERT (!jerry_value_is_exception (is_ok));
TEST_ASSERT (!strcmp (buf, expect_utf8_buf));
jerry_value_free (str);
} /* test_utf8_string */
static jerry_value_t
create_object_a_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (args_p);
JERRY_UNUSED (args_cnt);
TEST_ASSERT (jerry_value_is_object (call_info_p->this_value));
my_thing_a.x = 1;
jerry_object_set_native_ptr (call_info_p->this_value, &thing_a_info, &my_thing_a);
return jerry_boolean (true);
} /* create_object_a_handler */
static jerry_value_t
create_object_b_handler (const jerry_call_info_t *call_info_p, /**< call information */
const jerry_value_t args_p[], /**< arguments list */
const jerry_length_t args_cnt) /**< arguments length */
{
JERRY_UNUSED (args_p);
JERRY_UNUSED (args_cnt);
TEST_ASSERT (jerry_value_is_object (call_info_p->this_value));
my_thing_b.x = false;
jerry_object_set_native_ptr (call_info_p->this_value, &thing_b_info, &my_thing_b);
return jerry_boolean (true);
} /* create_object_b_handler */
/**
* Register a JavaScript function in the global object.
*/
static void
register_js_function (const char *name_p, /**< name of the function */
jerry_external_handler_t handler_p) /**< function callback */
{
jerry_value_t global_obj_val = jerry_current_realm ();
jerry_value_t function_val = jerry_function_external (handler_p);
jerry_value_t function_name_val = jerry_string_sz (name_p);
jerry_value_t result_val = jerry_object_set (global_obj_val, function_name_val, function_val);
jerry_value_free (function_name_val);
jerry_value_free (function_val);
jerry_value_free (global_obj_val);
jerry_value_free (result_val);
} /* register_js_function */
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
test_utf8_string ();
register_js_function ("test_validator1", test_validator1_handler);
register_js_function ("test_validator2", test_validator2_handler);
register_js_function ("test_validator3", test_validator3_handler);
register_js_function ("test_validator_int1", test_validator_int1_handler);
register_js_function ("test_validator_int2", test_validator_int2_handler);
register_js_function ("test_validator_int3", test_validator_int3_handler);
register_js_function ("MyObjectA", create_object_a_handler);
register_js_function ("MyObjectB", create_object_b_handler);
register_js_function ("test_validator_prop1", test_validator_prop1_handler);
register_js_function ("test_validator_prop2", test_validator_prop2_handler);
register_js_function ("test_validator_prop3", test_validator_prop3_handler);
register_js_function ("test_validator_array1", test_validator_array1_handler);
register_js_function ("test_validator_array2", test_validator_array2_handler);
register_js_function ("test_validator_restore", test_validator_restore_handler);
jerry_value_t parsed_code_val = jerry_parse (test_source, sizeof (test_source) - 1, NULL);
TEST_ASSERT (!jerry_value_is_exception (parsed_code_val));
jerry_value_t res = jerry_run (parsed_code_val);
TEST_ASSERT (!jerry_value_is_exception (res));
TEST_ASSERT (validator1_count == 5);
TEST_ASSERT (validator2_count == 3);
TEST_ASSERT (validator_prop_count == 4);
TEST_ASSERT (validator_int_count == 3);
TEST_ASSERT (validator_array_count == 3);
TEST_ASSERT (validator_restore_count == 4);
jerry_value_free (res);
jerry_value_free (parsed_code_val);
jerry_cleanup ();
} /* main */