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
25static 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
68static const jerry_object_native_info_t thing_a_info =
69{
70  .free_cb = NULL
71};
72
73static const jerry_object_native_info_t thing_b_info =
74{
75  .free_cb = NULL
76};
77
78typedef struct
79{
80  int x;
81} my_type_a_t;
82
83typedef struct
84{
85  bool x;
86} my_type_b_t;
87
88static my_type_a_t my_thing_a;
89static my_type_b_t my_thing_b;
90
91static int validator1_count = 0;
92static int validator2_count = 0;
93static int validator3_count = 0;
94static int validator_int_count = 0;
95static int validator_prop_count = 0;
96static int validator_array_count = 0;
97static 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 */
108static jerry_value_t
109test_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 */
180static jerry_value_t
181my_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 */
212static jerry_value_t
213test_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 */
258static jerry_value_t
259test_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 */
325static jerry_value_t
326test_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 */
368static jerry_value_t
369test_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
418static jerry_value_t
419test_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 */
458static jerry_value_t
459test_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
513static jerry_value_t
514test_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
563static jerry_value_t
564test_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
592static jerry_value_t
593test_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
638static jerry_value_t
639test_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*/
683typedef 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*/
693typedef 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*/
719static jerry_value_t
720jerry_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*/
796static jerry_value_t
797test_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
830static void
831test_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
855static jerry_value_t
856create_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
875static jerry_value_t
876create_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 */
898static void
899register_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
915int
916main (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