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 26static jerry_value_t 27method_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 */ 41static void 42freeze_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 */ 63static void 64test_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 */ 168static void 169test_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 */ 194static void 195test_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 */ 224static void 225test_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 307int 308main (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