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/handler property registration
18 */
19
20 #include "jerryscript.h"
21 #include "jerryscript-ext/handler.h"
22 #include "test-common.h"
23
24 #include <string.h>
25
26 static jerry_value_t
method_hello(const jerry_value_t jfunc,const jerry_value_t jthis,const jerry_value_t jargv[],const jerry_length_t jargc)27 method_hello (const jerry_value_t jfunc, /**< function object */
28 const jerry_value_t jthis, /**< function this */
29 const jerry_value_t jargv[], /**< arguments */
30 const jerry_length_t jargc) /**< number of arguments */
31 {
32 (void) jfunc;
33 (void) jthis;
34 (void) jargv;
35 return jerry_create_number (jargc);
36 } /* method_hello */
37
38 /**
39 * Helper method to create a non-configurable property on an object
40 */
41 static void
freeze_property(jerry_value_t target_obj,const char * target_prop)42 freeze_property (jerry_value_t target_obj, /**< target object */
43 const char *target_prop) /**< target property name */
44 {
45 // "freeze" property
46 jerry_property_descriptor_t prop_desc;
47 jerry_init_property_descriptor_fields (&prop_desc);
48 prop_desc.is_configurable_defined = true;
49 prop_desc.is_configurable = false;
50
51 jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) target_prop);
52 jerry_value_t return_value = jerry_define_own_property (target_obj, prop_name, &prop_desc);
53 TEST_ASSERT (jerry_value_is_boolean (return_value));
54 jerry_release_value (return_value);
55 jerry_release_value (prop_name);
56
57 jerry_free_property_descriptor_fields (&prop_desc);
58 } /* freeze_property */
59
60 /**
61 * Test registration of various property values.
62 */
63 static void
test_simple_registration(void)64 test_simple_registration (void)
65 {
66 jerry_init (JERRY_INIT_EMPTY);
67
68 jerry_value_t target_object = jerry_create_object ();
69
70 // Test simple registration
71 jerryx_property_entry methods[] =
72 {
73 JERRYX_PROPERTY_FUNCTION ("hello", method_hello),
74 JERRYX_PROPERTY_NUMBER ("my_number", 42.5),
75 JERRYX_PROPERTY_STRING ("my_str", "super_str"),
76 JERRYX_PROPERTY_STRING_SZ ("my_str_sz", "super_str", 6),
77 JERRYX_PROPERTY_BOOLEAN ("my_bool", true),
78 JERRYX_PROPERTY_BOOLEAN ("my_bool_false", false),
79 JERRYX_PROPERTY_UNDEFINED ("my_non_value"),
80 JERRYX_PROPERTY_LIST_END (),
81 };
82
83 jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
84
85 TEST_ASSERT (register_result.registered == 7);
86 TEST_ASSERT (jerry_value_is_undefined (register_result.result));
87
88 jerryx_release_property_entry (methods, register_result);
89 jerry_release_value (register_result.result);
90
91 jerry_value_t global_obj = jerry_get_global_object ();
92 jerryx_set_property_str (global_obj, "test", target_object);
93 jerry_release_value (target_object);
94 jerry_release_value (global_obj);
95
96 {
97 const char *test_A = "test.my_number";
98 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
99 TEST_ASSERT (jerry_value_is_number (result));
100 TEST_ASSERT (jerry_get_number_value (result) == 42.5);
101 jerry_release_value (result);
102 }
103
104 {
105 const char *test_A = "test.my_str_sz === 'super_'";
106 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
107 TEST_ASSERT (jerry_value_is_boolean (result));
108 TEST_ASSERT (jerry_get_boolean_value (result) == true);
109 jerry_release_value (result);
110 }
111
112 {
113 const char *test_A = "test.my_str === 'super_str'";
114 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
115 TEST_ASSERT (jerry_value_is_boolean (result));
116 TEST_ASSERT (jerry_get_boolean_value (result) == true);
117 jerry_release_value (result);
118 }
119
120 {
121 const char *test_A = "test.my_bool";
122 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
123 TEST_ASSERT (jerry_value_is_boolean (result));
124 TEST_ASSERT (jerry_get_boolean_value (result) == true);
125 jerry_release_value (result);
126 }
127
128 {
129 const char *test_A = "test.my_bool_false";
130 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
131 TEST_ASSERT (jerry_value_is_boolean (result));
132 TEST_ASSERT (jerry_get_boolean_value (result) == false);
133 jerry_release_value (result);
134 }
135
136 {
137 const char *test_A = "test.my_non_value";
138 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
139 TEST_ASSERT (jerry_value_is_undefined (result));
140 jerry_release_value (result);
141 }
142
143 {
144 const char *test_A = "test.hello(33, 42, 2);";
145 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
146 TEST_ASSERT (jerry_value_is_number (result));
147 TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 3u);
148 jerry_release_value (result);
149 }
150
151 {
152 const char *test_A = "test.hello();";
153 jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
154 TEST_ASSERT (jerry_value_is_number (result));
155 TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 0u);
156 jerry_release_value (result);
157 }
158
159 jerry_cleanup ();
160 } /* test_simple_registration */
161
162 /**
163 * Test registration error.
164 *
165 * Trying to register a property which is already a non-configurable property
166 * should result in an error.
167 */
168 static void
test_error_setvalue(void)169 test_error_setvalue (void)
170 {
171 jerry_init (JERRY_INIT_EMPTY);
172
173 const char *target_prop = "test_err";
174 jerry_value_t global_obj = jerry_get_global_object ();
175 freeze_property (global_obj, target_prop);
176
177 jerry_value_t new_object = jerry_create_object ();
178 jerry_value_t set_result = jerryx_set_property_str (global_obj, target_prop, new_object);
179 TEST_ASSERT (jerry_value_is_error (set_result));
180
181 jerry_release_value (set_result);
182 jerry_release_value (new_object);
183 jerry_release_value (global_obj);
184
185 jerry_cleanup ();
186 } /* test_error_setvalue */
187
188 /**
189 * Test registration error with jerryx_set_properties.
190 *
191 * Trying to register a property which is already a non-configurable property
192 * should result in an error.
193 */
194 static void
test_error_single_function(void)195 test_error_single_function (void)
196 {
197 jerry_init (JERRY_INIT_EMPTY);
198
199 const char *target_prop = "test_err";
200 jerry_value_t target_object = jerry_create_object ();
201 freeze_property (target_object, target_prop);
202
203 jerryx_property_entry methods[] =
204 {
205 JERRYX_PROPERTY_FUNCTION (target_prop, method_hello), // This registration should fail
206 JERRYX_PROPERTY_LIST_END (),
207 };
208
209 jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
210
211 TEST_ASSERT (register_result.registered == 0);
212 TEST_ASSERT (jerry_value_is_error (register_result.result));
213 jerryx_release_property_entry (methods, register_result);
214 jerry_release_value (register_result.result);
215
216 jerry_release_value (target_object);
217
218 jerry_cleanup ();
219 } /* test_error_single_function */
220
221 /**
222 * Test to see if jerryx_set_properties exits at the first error.
223 */
224 static void
test_error_multiple_functions(void)225 test_error_multiple_functions (void)
226 {
227 jerry_init (JERRY_INIT_EMPTY);
228
229 const char *prop_ok = "prop_ok";
230 const char *prop_err = "prop_err";
231 const char *prop_not = "prop_not";
232 jerry_value_t target_object = jerry_create_object ();
233 freeze_property (target_object, prop_err);
234
235 jerryx_property_entry methods[] =
236 {
237 JERRYX_PROPERTY_FUNCTION (prop_ok, method_hello), // This registration is ok
238 JERRYX_PROPERTY_FUNCTION (prop_err, method_hello), // This registration should fail
239 JERRYX_PROPERTY_FUNCTION (prop_not, method_hello), // This registration is not done
240 JERRYX_PROPERTY_LIST_END (),
241 };
242
243 jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
244
245 TEST_ASSERT (register_result.registered == 1);
246 TEST_ASSERT (jerry_value_is_error (register_result.result));
247
248 jerryx_release_property_entry (methods, register_result);
249 jerry_release_value (register_result.result);
250
251 {
252 // Test if property "prop_ok" is correctly registered.
253 jerry_value_t prop_ok_val = jerry_create_string ((const jerry_char_t *) prop_ok);
254 jerry_value_t prop_ok_exists = jerry_has_own_property (target_object, prop_ok_val);
255 TEST_ASSERT (jerry_get_boolean_value (prop_ok_exists) == true);
256 jerry_release_value (prop_ok_exists);
257
258 // Try calling the method
259 jerry_value_t prop_ok_func = jerry_get_property (target_object, prop_ok_val);
260 TEST_ASSERT (jerry_value_is_function (prop_ok_func) == true);
261 jerry_value_t args[2] =
262 {
263 jerry_create_number (22),
264 jerry_create_number (-3),
265 };
266 jerry_size_t args_cnt = sizeof (args) / sizeof (jerry_value_t);
267 jerry_value_t func_result = jerry_call_function (prop_ok_func,
268 jerry_create_undefined (),
269 args,
270 args_cnt);
271 TEST_ASSERT (jerry_value_is_number (func_result) == true);
272 TEST_ASSERT ((uint32_t) jerry_get_number_value (func_result) == 2u);
273 jerry_release_value (func_result);
274 for (jerry_size_t idx = 0; idx < args_cnt; idx++)
275 {
276 jerry_release_value (args[idx]);
277 }
278 jerry_release_value (prop_ok_func);
279 jerry_release_value (prop_ok_val);
280 }
281
282 {
283 // The "prop_err" should exist - as it was "freezed" - but it should not be a function
284 jerry_value_t prop_err_val = jerry_create_string ((const jerry_char_t *) prop_err);
285 jerry_value_t prop_err_exists = jerry_has_own_property (target_object, prop_err_val);
286 TEST_ASSERT (jerry_get_boolean_value (prop_err_exists) == true);
287 jerry_release_value (prop_err_exists);
288
289 jerry_value_t prop_err_func = jerry_value_is_function (prop_err_val);
290 TEST_ASSERT (jerry_value_is_function (prop_err_func) == false);
291 jerry_release_value (prop_err_val);
292 }
293
294 { // The "prop_not" is not available on the target object
295 jerry_value_t prop_not_val = jerry_create_string ((const jerry_char_t *) prop_not);
296 jerry_value_t prop_not_exists = jerry_has_own_property (target_object, prop_not_val);
297 TEST_ASSERT (jerry_get_boolean_value (prop_not_exists) == false);
298 jerry_release_value (prop_not_exists);
299 jerry_release_value (prop_not_val);
300 }
301
302 jerry_release_value (target_object);
303
304 jerry_cleanup ();
305 } /* test_error_multiple_functions */
306
307 int
main(void)308 main (void)
309 {
310 test_simple_registration ();
311 test_error_setvalue ();
312 test_error_single_function ();
313 test_error_multiple_functions ();
314 return 0;
315 } /* main */
316