1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * Unit test for jerry-ext/args.
18 */
19
20 #include <string.h>
21 #include "jerryscript.h"
22 #include "jerryscript-ext/arg.h"
23 #include "test-common.h"
24
25 static const jerry_char_t test_source[] = TEST_STRING_LITERAL (
26 "var arg1 = true;"
27 "var arg2 = 10.5;"
28 "var arg3 = 'abc';"
29 "var arg4 = function foo() {};"
30 "test_validator1(arg1, arg2, arg3, arg4);"
31 "arg1 = new Boolean(true);"
32 "arg3 = new String('abc');"
33 "test_validator1(arg1, arg2, arg3);"
34 "test_validator1(arg1, arg2, '');"
35 "arg2 = new Number(10.5);"
36 "test_validator1(arg1, arg2, arg3);"
37 "test_validator1(arg1, 10.5, 'abcdef');"
38 "test_validator3(arg1, arg1);"
39 "test_validator3(arg1);"
40 "test_validator3();"
41 "test_validator3(undefined, undefined);"
42 "var obj_a = new MyObjectA();"
43 "var obj_b = new MyObjectB();"
44 "test_validator2.call(obj_a, 5);"
45 "test_validator2.call(obj_b, 5);"
46 "test_validator2.call(obj_a, 1);"
47 "var obj1 = {prop1:true, prop2:'1.5'};"
48 "test_validator_prop1(obj1);"
49 "test_validator_prop2(obj1);"
50 "test_validator_prop2();"
51 "var obj2 = {prop1:true};"
52 "Object.defineProperty(obj2, 'prop2', {"
53 " get: function() { throw new TypeError('prop2 error') }"
54 "});"
55 "test_validator_prop3(obj2);"
56 "test_validator_int1(-1000, 1000, 128, -1000, 1000, -127,"
57 " -1000, 4294967297, 65536, -2200000000, 4294967297, -2147483647);"
58 "test_validator_int2(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5, Infinity, -Infinity, 300.5, 300.5);"
59 "test_validator_int3(NaN);"
60 "var arr = [1, 2];"
61 "test_validator_array1(arr);"
62 "test_validator_array1();"
63 "test_validator_array2(arr);"
64 "test_validator_restore(false, 3.0);"
65 "test_validator_restore(3.0, false);"
66 );
67
68 static const jerry_object_native_info_t thing_a_info =
69 {
70 .free_cb = NULL
71 };
72
73 static const jerry_object_native_info_t thing_b_info =
74 {
75 .free_cb = NULL
76 };
77
78 typedef struct
79 {
80 int x;
81 } my_type_a_t;
82
83 typedef struct
84 {
85 bool x;
86 } my_type_b_t;
87
88 static my_type_a_t my_thing_a;
89 static my_type_b_t my_thing_b;
90
91 static int validator1_count = 0;
92 static int validator2_count = 0;
93 static int validator3_count = 0;
94 static int validator_int_count = 0;
95 static int validator_prop_count = 0;
96 static int validator_array_count = 0;
97 static int validator_restore_count = 0;
98
99 /**
100 * The handler should have following arguments:
101 * this: Ignore.
102 * arg1: Bool.
103 * arg2: Number. It must be strict primitive number.
104 * arg3: String.
105 * arg4: function. It is an optional argument.
106 *
107 */
108 static jerry_value_t
test_validator1_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)109 test_validator1_handler (const jerry_value_t func_obj_val, /**< function object */
110 const jerry_value_t this_val, /**< this value */
111 const jerry_value_t args_p[], /**< arguments list */
112 const jerry_length_t args_cnt) /**< arguments length */
113 {
114 JERRY_UNUSED (func_obj_val);
115
116 bool arg1;
117 double arg2 = 0.0;
118 char arg3[5] = "1234";
119 jerry_value_t arg4 = jerry_create_undefined ();
120
121 jerryx_arg_t mapping[] =
122 {
123 /* ignore this */
124 jerryx_arg_ignore (),
125 /* 1st argument should be boolean */
126 jerryx_arg_boolean (&arg1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
127 /* 2nd argument should be strict number */
128 jerryx_arg_number (&arg2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED),
129 /* 3th argument should be string */
130 jerryx_arg_string (arg3, 5, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
131 /* 4th argument should be function, and it is optional */
132 jerryx_arg_function (&arg4, JERRYX_ARG_OPTIONAL)
133 };
134
135 jerry_value_t is_ok = jerryx_arg_transform_this_and_args (this_val,
136 args_p,
137 args_cnt,
138 mapping,
139 ARRAY_SIZE (mapping));
140
141 if (validator1_count == 0)
142 {
143 TEST_ASSERT (!jerry_value_is_error (is_ok));
144 TEST_ASSERT (arg1);
145 TEST_ASSERT (arg2 == 10.5);
146 TEST_ASSERT (strcmp (arg3, "abc") == 0);
147 TEST_ASSERT (jerry_value_is_function (arg4));
148 }
149 else if (validator1_count == 1)
150 {
151 TEST_ASSERT (!jerry_value_is_error (is_ok));
152 TEST_ASSERT (arg1);
153 TEST_ASSERT (arg2 == 10.5);
154 TEST_ASSERT (strcmp (arg3, "abc") == 0);
155 TEST_ASSERT (jerry_value_is_undefined (arg4));
156 }
157 else if (validator1_count == 2)
158 {
159 TEST_ASSERT (!jerry_value_is_error (is_ok));
160 TEST_ASSERT (arg1);
161 TEST_ASSERT (arg2 == 10.5);
162 TEST_ASSERT (strcmp (arg3, "") == 0);
163 TEST_ASSERT (jerry_value_is_undefined (arg4));
164 }
165 else
166 {
167 TEST_ASSERT (jerry_value_is_error (is_ok));
168 }
169
170 jerry_release_value (is_ok);
171 jerry_release_value (arg4);
172 validator1_count++;
173
174 return jerry_create_undefined ();
175 } /* test_validator1_handler */
176
177 /**
178 * The JS argument should be number, whose value is equal with the extra_info .
179 */
180 static jerry_value_t
my_custom_transform(jerryx_arg_js_iterator_t * js_arg_iter_p,const jerryx_arg_t * c_arg_p)181 my_custom_transform (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */
182 const jerryx_arg_t *c_arg_p) /**< the native arg */
183 {
184 jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p);
185 jerry_value_t to_number = jerry_value_to_number (js_arg);
186
187 if (jerry_value_is_error (to_number))
188 {
189 jerry_release_value (to_number);
190
191 return jerry_create_error (JERRY_ERROR_TYPE,
192 (jerry_char_t *) "It can not be converted to a number.");
193 }
194
195 int expected_num = (int) c_arg_p->extra_info;
196 int get_num = (int) jerry_get_number_value (to_number);
197
198 if (get_num != expected_num)
199 {
200 return jerry_create_error (JERRY_ERROR_TYPE,
201 (jerry_char_t *) "Number value is not expected.");
202 }
203
204 return jerry_create_undefined ();
205 } /* my_custom_transform */
206
207 /**
208 * The handler should have following arguments:
209 * this: with native pointer whose type is bind_a_info.
210 * arg1: should pass the custom tranform function.
211 */
212 static jerry_value_t
test_validator2_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)213 test_validator2_handler (const jerry_value_t func_obj_val, /**< function object */
214 const jerry_value_t this_val, /**< this value */
215 const jerry_value_t args_p[], /**< arguments list */
216 const jerry_length_t args_cnt) /**< arguments length */
217 {
218 JERRY_UNUSED (func_obj_val);
219
220 my_type_a_t *thing_p;
221
222 jerryx_arg_t mapping[] =
223 {
224 /* this should has native pointer, whose type is thing_a_info */
225 jerryx_arg_native_pointer ((void **) &thing_p, &thing_a_info, JERRYX_ARG_REQUIRED),
226 /* custom tranform function */
227 jerryx_arg_custom (NULL, 5, my_custom_transform)
228 };
229
230 jerry_value_t is_ok = jerryx_arg_transform_this_and_args (this_val,
231 args_p,
232 args_cnt,
233 mapping,
234 ARRAY_SIZE (mapping));
235
236 if (validator2_count == 0)
237 {
238 TEST_ASSERT (!jerry_value_is_error (is_ok));
239 TEST_ASSERT (thing_p == &my_thing_a);
240 TEST_ASSERT (thing_p->x == 1);
241 }
242 else
243 {
244 TEST_ASSERT (jerry_value_is_error (is_ok));
245 }
246
247 jerry_release_value (is_ok);
248 validator2_count++;
249
250 return jerry_create_undefined ();
251 } /* test_validator2_handler */
252
253 /**
254 * The handler should have following arguments:
255 * arg1: Bool. It is an optional argument.
256 *
257 */
258 static jerry_value_t
test_validator3_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)259 test_validator3_handler (const jerry_value_t func_obj_val, /**< function object */
260 const jerry_value_t this_val, /**< this value */
261 const jerry_value_t args_p[], /**< arguments list */
262 const jerry_length_t args_cnt) /**< arguments length */
263 {
264
265 JERRY_UNUSED (func_obj_val);
266
267 bool arg1 = false;
268 bool arg2 = false;
269
270 jerryx_arg_t mapping[] =
271 {
272 /* ignore this */
273 jerryx_arg_ignore (),
274 /* 1th argument should be boolean, and it is optional */
275 jerryx_arg_boolean (&arg1, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL),
276 /* 2nd argument should be boolean, and it is optional */
277 jerryx_arg_boolean (&arg2, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL),
278 };
279
280 jerry_value_t is_ok = jerryx_arg_transform_this_and_args (this_val,
281 args_p,
282 args_cnt,
283 mapping,
284 ARRAY_SIZE (mapping));
285
286 if (validator3_count == 0)
287 {
288 TEST_ASSERT (!jerry_value_is_error (is_ok));
289 TEST_ASSERT (arg1);
290 TEST_ASSERT (arg2);
291 }
292 else if (validator3_count == 1)
293 {
294 TEST_ASSERT (!jerry_value_is_error (is_ok));
295 TEST_ASSERT (arg1);
296 /* arg2 must be unchanged */
297 TEST_ASSERT (!arg2);
298 }
299 else if (validator3_count == 2)
300 {
301 TEST_ASSERT (!jerry_value_is_error (is_ok));
302 /* arg1 must be unchanged */
303 TEST_ASSERT (!arg1);
304 /* arg2 must be unchanged */
305 TEST_ASSERT (!arg2);
306 }
307 else if (validator3_count == 3)
308 {
309 TEST_ASSERT (!jerry_value_is_error (is_ok));
310 /* arg1 must be unchanged */
311 TEST_ASSERT (!arg1);
312 /* arg2 must be unchanged */
313 TEST_ASSERT (!arg2);
314 }
315
316 jerry_release_value (is_ok);
317 validator3_count++;
318
319 return jerry_create_undefined ();
320 } /* test_validator3_handler */
321
322 /**
323 * Calling jerryx_arg_transform_object_properties directly.
324 */
325 static jerry_value_t
test_validator_prop1_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)326 test_validator_prop1_handler (const jerry_value_t func_obj_val, /**< function object */
327 const jerry_value_t this_val, /**< this value */
328 const jerry_value_t args_p[], /**< arguments list */
329 const jerry_length_t args_cnt) /**< arguments length */
330 {
331 JERRY_UNUSED (func_obj_val);
332 JERRY_UNUSED (this_val);
333 JERRY_UNUSED (args_cnt);
334
335 bool native1 = false;
336 double native2 = 0;
337 double native3 = 3;
338
339 const char *name_p[] = {"prop1", "prop2", "prop3"};
340
341 jerryx_arg_t mapping[] =
342 {
343 jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
344 jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
345 jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL)
346 };
347
348 jerry_value_t is_ok = jerryx_arg_transform_object_properties (args_p[0],
349 (const jerry_char_t **) name_p,
350 ARRAY_SIZE (name_p),
351 mapping,
352 ARRAY_SIZE (mapping));
353
354 TEST_ASSERT (!jerry_value_is_error (is_ok));
355 TEST_ASSERT (native1);
356 TEST_ASSERT (native2 == 1.5);
357 TEST_ASSERT (native3 == 3);
358
359 validator_prop_count++;
360
361 return jerry_create_undefined ();
362 } /* test_validator_prop1_handler */
363
364 /**
365 * Calling jerryx_arg_transform_object_properties indirectly by
366 * using jerryx_arg_object_properties.
367 */
368 static jerry_value_t
test_validator_prop2_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)369 test_validator_prop2_handler (const jerry_value_t func_obj_val, /**< function object */
370 const jerry_value_t this_val, /**< this value */
371 const jerry_value_t args_p[], /**< arguments list */
372 const jerry_length_t args_cnt) /**< arguments length */
373 {
374 JERRY_UNUSED (func_obj_val);
375 JERRY_UNUSED (this_val);
376
377 bool native1 = false;
378 double native2 = 0;
379 double native3 = 3;
380
381 jerryx_arg_object_props_t prop_info;
382
383 const char *name_p[] = { "prop1", "prop2", "prop3" };
384
385 jerryx_arg_t prop_mapping[] =
386 {
387 jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
388 jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
389 jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL)
390 };
391
392 prop_info.name_p = (const jerry_char_t **) name_p;
393 prop_info.name_cnt = 3;
394 prop_info.c_arg_p = prop_mapping;
395 prop_info.c_arg_cnt = 3;
396
397 jerryx_arg_t mapping[] =
398 {
399 jerryx_arg_object_properties (&prop_info, JERRYX_ARG_OPTIONAL),
400 };
401
402 jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
403
404 TEST_ASSERT (!jerry_value_is_error (is_ok));
405
406 if (validator_prop_count == 1)
407 {
408 TEST_ASSERT (native1);
409 TEST_ASSERT (native2 == 1.5);
410 TEST_ASSERT (native3 == 3);
411 }
412
413 validator_prop_count++;
414
415 return jerry_create_undefined ();
416 } /* test_validator_prop2_handler */
417
418 static jerry_value_t
test_validator_prop3_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)419 test_validator_prop3_handler (const jerry_value_t func_obj_val, /**< function object */
420 const jerry_value_t this_val, /**< this value */
421 const jerry_value_t args_p[], /**< arguments list */
422 const jerry_length_t args_cnt) /**< arguments length */
423 {
424 JERRY_UNUSED (func_obj_val);
425 JERRY_UNUSED (this_val);
426 JERRY_UNUSED (args_cnt);
427
428 bool native1 = false;
429 bool native2 = true;
430
431 const char *name_p[] = { "prop1", "prop2" };
432
433 jerryx_arg_t mapping[] =
434 {
435 jerryx_arg_boolean (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
436 jerryx_arg_boolean (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
437 };
438
439 jerry_value_t is_ok = jerryx_arg_transform_object_properties (args_p[0],
440 (const jerry_char_t **) name_p,
441 ARRAY_SIZE (name_p),
442 mapping,
443 ARRAY_SIZE (mapping));
444
445 TEST_ASSERT (jerry_value_is_error (is_ok));
446 TEST_ASSERT (!native1);
447 TEST_ASSERT (native2);
448
449 validator_prop_count++;
450 jerry_release_value (is_ok);
451
452 return jerry_create_undefined ();
453 } /* test_validator_prop3_handler */
454
455 /*
456 * args_p[0-2] are uint8, args_p[3-5] are int8, args_p[6-8] are uint32, args_p[9-11] are int32.
457 */
458 static jerry_value_t
test_validator_int1_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)459 test_validator_int1_handler (const jerry_value_t func_obj_val, /**< function object */
460 const jerry_value_t this_val, /**< this value */
461 const jerry_value_t args_p[], /**< arguments list */
462 const jerry_length_t args_cnt) /**< arguments length */
463 {
464 JERRY_UNUSED (func_obj_val);
465 JERRY_UNUSED (this_val);
466
467 uint8_t num0, num1, num2;
468 int8_t num3, num4, num5;
469 uint32_t num6, num7, num8;
470 int32_t num9, num10, num11;
471
472 jerryx_arg_t mapping[] =
473 {
474 jerryx_arg_uint8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
475 jerryx_arg_uint8 (&num1, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
476 jerryx_arg_uint8 (&num2, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
477 jerryx_arg_int8 (&num3, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
478 jerryx_arg_int8 (&num4, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
479 jerryx_arg_int8 (&num5, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
480 jerryx_arg_uint32 (&num6, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
481 jerryx_arg_uint32 (&num7, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
482 jerryx_arg_uint32 (&num8, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
483 jerryx_arg_int32 (&num9, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
484 jerryx_arg_int32 (&num10, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
485 jerryx_arg_int32 (&num11, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED)
486 };
487
488 jerry_value_t is_ok = jerryx_arg_transform_args (args_p,
489 args_cnt,
490 mapping,
491 ARRAY_SIZE (mapping));
492
493 TEST_ASSERT (!jerry_value_is_error (is_ok));
494 TEST_ASSERT (num0 == 0);
495 TEST_ASSERT (num1 == 255);
496 TEST_ASSERT (num2 == 128);
497 TEST_ASSERT (num3 == -128);
498 TEST_ASSERT (num4 == 127);
499 TEST_ASSERT (num5 == -127);
500 TEST_ASSERT (num6 == 0);
501 TEST_ASSERT (num7 == 4294967295);
502 TEST_ASSERT (num8 == 65536);
503 TEST_ASSERT (num9 == -2147483648);
504 TEST_ASSERT (num10 == 2147483647);
505 TEST_ASSERT (num11 == -2147483647);
506
507 jerry_release_value (is_ok);
508 validator_int_count++;
509
510 return jerry_create_undefined ();
511 } /* test_validator_int1_handler */
512
513 static jerry_value_t
test_validator_int2_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)514 test_validator_int2_handler (const jerry_value_t func_obj_val, /**< function object */
515 const jerry_value_t this_val, /**< this value */
516 const jerry_value_t args_p[], /**< arguments list */
517 const jerry_length_t args_cnt) /**< arguments length */
518 {
519 JERRY_UNUSED (func_obj_val);
520 JERRY_UNUSED (this_val);
521
522 int8_t num0, num1, num2, num3, num4, num5, num6, num7, num8, num9;
523 num8 = 123;
524 num9 = 123;
525
526 jerryx_arg_t mapping[] =
527 {
528 jerryx_arg_int8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
529 jerryx_arg_int8 (&num1, JERRYX_ARG_FLOOR, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
530 jerryx_arg_int8 (&num2, JERRYX_ARG_CEIL, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
531 jerryx_arg_int8 (&num3, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
532 jerryx_arg_int8 (&num4, JERRYX_ARG_FLOOR, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
533 jerryx_arg_int8 (&num5, JERRYX_ARG_CEIL, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
534 jerryx_arg_int8 (&num6, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
535 jerryx_arg_int8 (&num7, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
536 jerryx_arg_int8 (&num8, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
537 jerryx_arg_int8 (&num9, JERRYX_ARG_ROUND, JERRYX_ARG_NO_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
538 };
539
540 jerry_value_t is_ok = jerryx_arg_transform_args (args_p,
541 args_cnt,
542 mapping,
543 ARRAY_SIZE (mapping));
544
545 TEST_ASSERT (jerry_value_is_error (is_ok));
546 TEST_ASSERT (num0 == -2);
547 TEST_ASSERT (num1 == -2);
548 TEST_ASSERT (num2 == -1);
549 TEST_ASSERT (num3 == 2);
550 TEST_ASSERT (num4 == 1);
551 TEST_ASSERT (num5 == 2);
552 TEST_ASSERT (num6 == 127);
553 TEST_ASSERT (num7 == -128);
554 TEST_ASSERT (num8 == 127);
555 TEST_ASSERT (num9 == 123);
556
557 jerry_release_value (is_ok);
558 validator_int_count++;
559
560 return jerry_create_undefined ();
561 } /* test_validator_int2_handler */
562
563 static jerry_value_t
test_validator_int3_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)564 test_validator_int3_handler (const jerry_value_t func_obj_val, /**< function object */
565 const jerry_value_t this_val, /**< this value */
566 const jerry_value_t args_p[], /**< arguments list */
567 const jerry_length_t args_cnt) /**< arguments length */
568 {
569 JERRY_UNUSED (func_obj_val);
570 JERRY_UNUSED (this_val);
571
572 int8_t num0;
573
574 jerryx_arg_t mapping[] =
575 {
576 jerryx_arg_int8 (&num0, JERRYX_ARG_ROUND, JERRYX_ARG_CLAMP, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
577 };
578
579 jerry_value_t is_ok = jerryx_arg_transform_args (args_p,
580 args_cnt,
581 mapping,
582 ARRAY_SIZE (mapping));
583
584 TEST_ASSERT (jerry_value_is_error (is_ok));
585
586 jerry_release_value (is_ok);
587 validator_int_count++;
588
589 return jerry_create_undefined ();
590 } /* test_validator_int3_handler */
591
592 static jerry_value_t
test_validator_array1_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)593 test_validator_array1_handler (const jerry_value_t func_obj_val, /**< function object */
594 const jerry_value_t this_val, /**< this value */
595 const jerry_value_t args_p[], /**< arguments list */
596 const jerry_length_t args_cnt) /**< arguments length */
597 {
598 JERRY_UNUSED (func_obj_val);
599 JERRY_UNUSED (this_val);
600
601 double native1 = 0;
602 double native2 = 0;
603 double native3 = 0;
604
605 jerryx_arg_array_items_t arr_info;
606
607 jerryx_arg_t item_mapping[] =
608 {
609 jerryx_arg_number (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
610 jerryx_arg_number (&native2, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
611 jerryx_arg_number (&native3, JERRYX_ARG_COERCE, JERRYX_ARG_OPTIONAL)
612 };
613
614 arr_info.c_arg_p = item_mapping;
615 arr_info.c_arg_cnt = 3;
616
617 jerryx_arg_t mapping[] =
618 {
619 jerryx_arg_array (&arr_info, JERRYX_ARG_OPTIONAL),
620 };
621
622 jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, mapping, ARRAY_SIZE (mapping));
623
624 TEST_ASSERT (!jerry_value_is_error (is_ok));
625
626 if (validator_array_count == 0)
627 {
628 TEST_ASSERT (native1 == 1);
629 TEST_ASSERT (native2 == 2);
630 TEST_ASSERT (native3 == 0);
631 }
632
633 validator_array_count++;
634
635 return jerry_create_undefined ();
636 } /* test_validator_array1_handler */
637
638 static jerry_value_t
test_validator_array2_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)639 test_validator_array2_handler (const jerry_value_t func_obj_val, /**< function object */
640 const jerry_value_t this_val, /**< this value */
641 const jerry_value_t args_p[], /**< arguments list */
642 const jerry_length_t args_cnt) /**< arguments length */
643 {
644 JERRY_UNUSED (func_obj_val);
645 JERRY_UNUSED (this_val);
646 JERRY_UNUSED (args_cnt);
647
648 double native1 = 0;
649 bool native2 = false;
650
651 jerryx_arg_t item_mapping[] =
652 {
653 jerryx_arg_number (&native1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
654 jerryx_arg_boolean (&native2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED)
655 };
656
657 jerry_value_t is_ok = jerryx_arg_transform_array (args_p[0], item_mapping, ARRAY_SIZE (item_mapping));
658
659 TEST_ASSERT (jerry_value_is_error (is_ok));
660 TEST_ASSERT (native1 == 1);
661 TEST_ASSERT (!native2);
662
663 validator_array_count++;
664 jerry_release_value (is_ok);
665
666 return jerry_create_undefined ();
667 } /* test_validator_array2_handler */
668
669 /**
670 * This validator is designed to test the
671 * jerryx_arg_js_iterator_restore function. We'll introduce a union
672 * type to hold a bool or double and a transform function that will
673 * look for this type. Then, we'll call the handler with two
674 * parameters, one bool and one double and see if we correctly build
675 * the union types for each parameter. To check that the code protects
676 * against backing up too far, when the check for the double fails,
677 * we'll "restore" the stack three times; this shouldn't break
678 * anything.
679 */
680 /*
681 * This enumeration type specifies the kind of thing held in the union.
682 */
683 typedef enum
684 {
685 DOUBLE_VALUE,
686 BOOL_VALUE
687 } union_type_t;
688
689 /*
690 * This struct holds either a boolean or double in a union and has a
691 * second field that describes the type held in the union.
692 */
693 typedef struct
694 {
695 union_type_t type_of_value;
696 union
697 {
698 double double_field;
699 bool bool_field;
700 } value;
701 } double_or_bool_t;
702
703 /**
704 * This creates a jerryx_arg_t that can be used like any
705 * of the installed functions, like jerryx_arg_bool().
706 */
707 #define jerryx_arg_double_or_bool_t(value_ptr, coerce_or_not, optional_or_not, last_parameter) \
708 jerryx_arg_custom (value_ptr, \
709 (uintptr_t)&((uintptr_t []){(uintptr_t)coerce_or_not, \
710 (uintptr_t)optional_or_not, \
711 (uintptr_t)last_parameter}), \
712 jerry_arg_to_double_or_bool_t)
713 /*
714 * This function is the argument validator used in the above macro called
715 * jerryx_arg_double_or_bool. It calls jerryx_arg_js_iterator_restore()
716 * more times than it should to ensure that calling that function too
717 * often doesn't cause an error.
718 */
719 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)720 jerry_arg_to_double_or_bool_t (jerryx_arg_js_iterator_t *js_arg_iter_p,
721 const jerryx_arg_t *c_arg_p)
722 {
723 /* c_arg_p has two fields: dest, which is a pointer to the data that
724 * gets filled in, and extra_info, which contains the flags used to
725 * control coercion and optional-ness, respectively. For this test,
726 * we added an extra flag that tells us that we're working on the
727 * last parameter; when we know it's the last parameter, we'll "restore"
728 * the stack more times than there are actual stack values to ensure
729 * that the restore function doesn't produce an error. */
730 double_or_bool_t *destination = c_arg_p->dest;
731 uintptr_t *extra_info = (uintptr_t *) (c_arg_p->extra_info);
732 jerryx_arg_t conversion_function;
733 jerry_value_t conversion_result;
734 jerry_value_t restore_result;
735 bool last_parameter = (extra_info[2] == 1);
736
737 validator_restore_count++;
738
739 conversion_function = jerryx_arg_number ((double *) (&(destination->value.double_field)),
740 (jerryx_arg_coerce_t) extra_info[0],
741 JERRYX_ARG_OPTIONAL);
742 conversion_result = conversion_function.func (js_arg_iter_p, &conversion_function);
743 if (!jerry_value_is_error (conversion_result))
744 {
745 if (last_parameter)
746 {
747 /* The stack is only two parameters high, but we want to ensure that
748 * excessive calls will not result in aberrant behavior... */
749 jerryx_arg_js_iterator_restore (js_arg_iter_p);
750 jerryx_arg_js_iterator_restore (js_arg_iter_p);
751 jerryx_arg_js_iterator_restore (js_arg_iter_p);
752 restore_result = jerryx_arg_js_iterator_restore (js_arg_iter_p);
753 TEST_ASSERT (jerry_value_is_undefined (restore_result));
754 }
755
756 destination->type_of_value = DOUBLE_VALUE;
757 return conversion_result;
758 }
759
760 jerryx_arg_js_iterator_restore (js_arg_iter_p);
761
762 conversion_function = jerryx_arg_boolean ((bool *) (&(destination->value.bool_field)),
763 (jerryx_arg_coerce_t) extra_info[0],
764 (jerryx_arg_optional_t) extra_info[1]);
765
766 jerry_release_value (conversion_result);
767 conversion_result = conversion_function.func (js_arg_iter_p, &conversion_function);
768 if (!jerry_value_is_error (conversion_result))
769 {
770 if (last_parameter)
771 {
772 /* The stack is only two parameters high, but we want to ensure that
773 * excessive calls will not result in aberrant behavior... */
774 jerryx_arg_js_iterator_restore (js_arg_iter_p);
775 jerryx_arg_js_iterator_restore (js_arg_iter_p);
776 jerryx_arg_js_iterator_restore (js_arg_iter_p);
777 restore_result = jerryx_arg_js_iterator_restore (js_arg_iter_p);
778 TEST_ASSERT (jerry_value_is_undefined (restore_result));
779 }
780
781 destination->type_of_value = BOOL_VALUE;
782 return conversion_result;
783 }
784
785 /* Fall through indicates that whatever they gave us, it wasn't
786 * one of the types we were expecting... */
787 jerry_release_value (conversion_result);
788 return jerry_create_error (JERRY_ERROR_TYPE,
789 (const jerry_char_t *) "double_or_bool-type error.");
790 } /* jerry_arg_to_double_or_bool_t */
791
792 /**
793 * This validator expects two parameters, one a bool and one a double -- the
794 * order doesn't matter (so we'll call it twice with the orders reversed).
795 */
796 static jerry_value_t
test_validator_restore_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)797 test_validator_restore_handler (const jerry_value_t func_obj_val, /**< function object */
798 const jerry_value_t this_val, /**< this value */
799 const jerry_value_t args_p[], /**< arguments list */
800 const jerry_length_t args_cnt) /**< arguments length */
801 {
802 JERRY_UNUSED (func_obj_val);
803 JERRY_UNUSED (this_val);
804
805 double_or_bool_t arg1;
806 double_or_bool_t arg2;
807
808 jerryx_arg_t item_mapping[] =
809 {
810 jerryx_arg_double_or_bool_t (&arg1, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED, 0),
811 jerryx_arg_double_or_bool_t (&arg2, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED, 1)
812 };
813
814 jerry_value_t is_ok = jerryx_arg_transform_args (args_p, args_cnt, item_mapping, ARRAY_SIZE (item_mapping));
815
816 TEST_ASSERT (!jerry_value_is_error (is_ok));
817
818 /* We are going to call this with [false, 3.0] and [3.0, false] parameters... */
819 bool arg1_is_false = (arg1.type_of_value == BOOL_VALUE && arg1.value.bool_field == false);
820 bool arg1_is_three = (arg1.type_of_value == DOUBLE_VALUE && arg1.value.double_field == 3.0);
821 bool arg2_is_false = (arg2.type_of_value == BOOL_VALUE && arg2.value.bool_field == false);
822 bool arg2_is_three = (arg2.type_of_value == DOUBLE_VALUE && arg2.value.double_field == 3.0);
823 TEST_ASSERT ((arg1_is_false && arg2_is_three) || (arg1_is_three && arg2_is_false));
824
825 jerry_release_value (is_ok);
826
827 return jerry_create_undefined ();
828 } /* test_validator_restore_handler */
829
830 static void
test_utf8_string(void)831 test_utf8_string (void)
832 {
833 /* test string: 'str: {DESERET CAPITAL LETTER LONG I}' */
834 jerry_value_t str = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80");
835 char expect_utf8_buf[] = "\x73\x74\x72\x3a \xf0\x90\x90\x80";
836 size_t buf_len = sizeof (expect_utf8_buf) - 1;
837 JERRY_VLA (char, buf, buf_len + 1);
838
839 jerryx_arg_t mapping[] =
840 {
841 jerryx_arg_utf8_string (buf, (uint32_t) buf_len + 1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED),
842 };
843
844 jerry_value_t is_ok = jerryx_arg_transform_args (&str,
845 1,
846 mapping,
847 ARRAY_SIZE (mapping));
848
849 TEST_ASSERT (!jerry_value_is_error (is_ok));
850 TEST_ASSERT (!strcmp (buf, expect_utf8_buf));
851
852 jerry_release_value (str);
853 } /* test_utf8_string */
854
855 static jerry_value_t
create_object_a_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)856 create_object_a_handler (const jerry_value_t func_obj_val, /**< function object */
857 const jerry_value_t this_val, /**< this value */
858 const jerry_value_t args_p[], /**< arguments list */
859 const jerry_length_t args_cnt) /**< arguments length */
860 {
861 JERRY_UNUSED (func_obj_val);
862 JERRY_UNUSED (args_p);
863 JERRY_UNUSED (args_cnt);
864
865 TEST_ASSERT (jerry_value_is_object (this_val));
866
867 my_thing_a.x = 1;
868 jerry_set_object_native_pointer (this_val,
869 &my_thing_a,
870 &thing_a_info);
871
872 return jerry_create_boolean (true);
873 } /* create_object_a_handler */
874
875 static jerry_value_t
create_object_b_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)876 create_object_b_handler (const jerry_value_t func_obj_val, /**< function object */
877 const jerry_value_t this_val, /**< this value */
878 const jerry_value_t args_p[], /**< arguments list */
879 const jerry_length_t args_cnt) /**< arguments length */
880 {
881 JERRY_UNUSED (func_obj_val);
882 JERRY_UNUSED (args_p);
883 JERRY_UNUSED (args_cnt);
884
885 TEST_ASSERT (jerry_value_is_object (this_val));
886
887 my_thing_b.x = false;
888 jerry_set_object_native_pointer (this_val,
889 &my_thing_b,
890 &thing_b_info);
891
892 return jerry_create_boolean (true);
893 } /* create_object_b_handler */
894
895 /**
896 * Register a JavaScript function in the global object.
897 */
898 static void
register_js_function(const char * name_p,jerry_external_handler_t handler_p)899 register_js_function (const char *name_p, /**< name of the function */
900 jerry_external_handler_t handler_p) /**< function callback */
901 {
902 jerry_value_t global_obj_val = jerry_get_global_object ();
903
904 jerry_value_t function_val = jerry_create_external_function (handler_p);
905 jerry_value_t function_name_val = jerry_create_string ((const jerry_char_t *) name_p);
906 jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val);
907
908 jerry_release_value (function_name_val);
909 jerry_release_value (function_val);
910 jerry_release_value (global_obj_val);
911
912 jerry_release_value (result_val);
913 } /* register_js_function */
914
915 int
main(void)916 main (void)
917 {
918 jerry_init (JERRY_INIT_EMPTY);
919
920 test_utf8_string ();
921
922 register_js_function ("test_validator1", test_validator1_handler);
923 register_js_function ("test_validator2", test_validator2_handler);
924 register_js_function ("test_validator3", test_validator3_handler);
925 register_js_function ("test_validator_int1", test_validator_int1_handler);
926 register_js_function ("test_validator_int2", test_validator_int2_handler);
927 register_js_function ("test_validator_int3", test_validator_int3_handler);
928 register_js_function ("MyObjectA", create_object_a_handler);
929 register_js_function ("MyObjectB", create_object_b_handler);
930 register_js_function ("test_validator_prop1", test_validator_prop1_handler);
931 register_js_function ("test_validator_prop2", test_validator_prop2_handler);
932 register_js_function ("test_validator_prop3", test_validator_prop3_handler);
933 register_js_function ("test_validator_array1", test_validator_array1_handler);
934 register_js_function ("test_validator_array2", test_validator_array2_handler);
935 register_js_function ("test_validator_restore", test_validator_restore_handler);
936
937 jerry_value_t parsed_code_val = jerry_parse (NULL,
938 0,
939 test_source,
940 sizeof (test_source) - 1,
941 JERRY_PARSE_NO_OPTS);
942 TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
943
944 jerry_value_t res = jerry_run (parsed_code_val);
945 TEST_ASSERT (!jerry_value_is_error (res));
946 TEST_ASSERT (validator1_count == 5);
947 TEST_ASSERT (validator2_count == 3);
948 TEST_ASSERT (validator_prop_count == 4);
949 TEST_ASSERT (validator_int_count == 3);
950 TEST_ASSERT (validator_array_count == 3);
951 TEST_ASSERT (validator_restore_count == 4);
952
953 jerry_release_value (res);
954 jerry_release_value (parsed_code_val);
955
956 jerry_cleanup ();
957 } /* main */
958