From fd1f7eab9f83c87bf12a6b09e27afafac64443d6 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Thu, 17 Oct 2019 13:56:49 +0200 Subject: [PATCH] Add public API functions for internal property management (#3128) These 4 new API functions give possibility to perform [[Get]], [[Set]], [[Has]], [[Delete]] operations for properties which are not accessible from the JavaScript context only from the public API. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- docs/02.API-REFERENCE.md | 226 +++++++++++++++++++ jerry-core/api/jerry.c | 212 ++++++++++++++++++ jerry-core/include/jerryscript-core.h | 5 + jerry-core/lit/lit-magic-strings.h | 1 + tests/unit-core/test-internal-properties.c | 240 +++++++++++++++++++++ 5 files changed, 684 insertions(+) create mode 100644 tests/unit-core/test-internal-properties.c diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 61b021af6..dd36c512a 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -4683,6 +4683,63 @@ main (void) - [jerry_delete_property](#jerry_delete_property) +## jerry_has_internal_property + +**Summary** + +Checks whether the object has the given internal property. + +*Note*: + - Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it +is no longer needed. + +**Prototype** + +```c +bool +jerry_has_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - true, if the property exists + - false, otherwise + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + bool has_internal_js_prop = jerry_has_internal_property (global_object, prop_name); + + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + + ## jerry_delete_property **Summary** @@ -4772,6 +4829,50 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, - [jerry_get_property_by_index](#jerry_get_property_by_index) - [jerry_set_property_by_index](#jerry_set_property_by_index) +## jerry_delete_internal_property + +**Summary** + +Delete an internal property from an object. + +*Note*: Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + +**Prototype** + +```c +bool +jerry_delete_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - true, if property was deleted successfully + - false, otherwise + +**Example** + +```c +{ + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + bool delete_result = jerry_delete_internal_property (global_object, prop_name); + /* use "delete_result" */ + + jerry_release_value (prop_name); + jerry_release_value (global_object); +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + ## jerry_get_property @@ -4884,6 +4985,66 @@ jerry_get_property_by_index (const jerry_value_t obj_val, - [jerry_set_property](#jerry_set_property) - [jerry_set_property_by_index](#jerry_set_property_by_index) +## jerry_get_internal_property + +**Summary** + +Get value of an internal property to the specified object with the given name. + +*Note*: + - Properties which were not created with [jerry_set_internal_property](#jerry_set_internal_property) are excluded + during the operation. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) when it + is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_get_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val); +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- return value + - value of property, if the internal property exists + - undefined value, if the, if the internal does not property exists + - thrown error, otherwise + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + + jerry_value_t prop_value = jerry_get_internal_property (global_object, prop_name); + + /* use "prop_value" then release it. */ + + jerry_release_value (prop_value); + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_set_internal_property](#jerry_set_internal_property) + ## jerry_set_property @@ -5001,6 +5162,68 @@ jerry_set_property_by_index (const jerry_value_t obj_val, - [jerry_get_property_by_index](#jerry_get_property_by_index) +## jerry_set_internal_property + +**Summary** + +Set an internal property to the specified object with the given name. + +*Note*: + - The property cannot be accessed from the JavaScript context, only from the public API. + - It is different from [jerry_set_object_native_pointer](#jerry_set_object_native_pointer) in that any jerry API value + can be hidden from the JavaScript context, not only native pointers. + +**Prototype** + +```c +bool +jerry_set_internal_property (const jerry_value_t obj_val, + const jerry_value_t prop_name_val, + const jerry_value_t value_to_set) +``` + +- `obj_val` - object value +- `prop_name_val` - property name +- `value_to_set` - value to set +- return value + - true, if success + - thrown error, otherwise + +**Example** + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t global_object = jerry_get_global_object (); + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) "hidden_property"); + jerry_value_t value_to_set = jerry_create_number (5); + + bool set_result = jerry_set_internal_property (global_object, prop_name, value_to_set); + + /* check the result of internal property set call */ + + jerry_release_value (value_to_set); + jerry_release_value (prop_name); + jerry_release_value (global_object); + + return 0; +} +``` + +**See also** + +- [jerry_has_internal_property](#jerry_has_internal_property) +- [jerry_delete_internal_property](#jerry_delete_internal_property) +- [jerry_get_internal_property](#jerry_get_internal_property) + + ## jerry_init_property_descriptor_fields **Summary** @@ -5763,6 +5986,9 @@ You can get them by calling [jerry_get_object_native_pointer](#jerry_get_object_ the free callback will be invoked during the execution of `jerry_cleanup`. - The free callback **must not** invoke API functions. +*Note*: If possible do not store API values in native pointers, rather check + [jerry_set_internal_property](#jerry_set_internal_property). + **Prototype** ```c diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index bcdca6282..0aa0db7dc 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -1996,6 +1996,47 @@ jerry_has_own_property (const jerry_value_t obj_val, /**< object value */ return ecma_make_boolean_value (has_property); } /* jerry_has_own_property */ +/** + * Checks whether the object has the given internal property. + * + * @return true - if the internal property exists + * false - otherwise + */ +bool +jerry_has_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + return false; + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return false; + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + return property_p != NULL; +} /* jerry_has_internal_property */ + /** * Delete a property from an object. * @@ -2046,6 +2087,54 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, /**< object value * return ecma_is_value_true (ret_value); } /* jerry_delete_property_by_index */ +/** + * Delete an internal property from an object. + * + * @return true - if property was deleted successfully + * false - otherwise + */ +bool +jerry_delete_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + return true; + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return true; + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + if (property_p == NULL) + { + return true; + } + + ecma_delete_property (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p)); + + return true; +} /* jerry_delete_internal_property */ + /** * Get value of a property to the specified object with the given name. * @@ -2099,6 +2188,56 @@ jerry_get_property_by_index (const jerry_value_t obj_val, /**< object value */ return jerry_return (ret_value); } /* jerry_get_property_by_index */ +/** + * Get value of an internal property to the specified object with the given name. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return value of the internal property - if the internal property exists + * undefined value - if the internal does not property exists + * value marked with error flag - otherwise + */ +jerry_value_t +jerry_get_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val) /**< property name value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + + if (property_p == NULL) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + ecma_object_t *internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + property_p = ecma_find_named_property (internal_object_p, ecma_get_prop_name_from_value (prop_name_val)); + + if (property_p == NULL) + { + return jerry_return (ECMA_VALUE_UNDEFINED); + } + + return jerry_return (ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); +} /* jerry_get_internal_property */ + /** * Set a property to the specified object with the given name. * @@ -2160,6 +2299,79 @@ jerry_set_property_by_index (const jerry_value_t obj_val, /**< object value */ return jerry_return (ret_value); } /* jerry_set_property_by_index */ +/** + * Set an internal property to the specified object with the given name. + * + * Note: + * - the property cannot be accessed from the JavaScript context, only from the public API + * - returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return true value - if the operation was successful + * value marked with error flag - otherwise + */ +bool +jerry_set_internal_property (const jerry_value_t obj_val, /**< object value */ + const jerry_value_t prop_name_val, /**< property name value */ + const jerry_value_t value_to_set) /**< value to set */ +{ + jerry_assert_api_available (); + + if (ecma_is_value_error_reference (value_to_set) + || !ecma_is_value_object (obj_val) + || !ecma_is_value_prop_name (prop_name_val)) + { + return false; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + + ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); + + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + ecma_fast_array_convert_to_normal (obj_p); + } + + ecma_property_t *property_p = ecma_find_named_property (obj_p, internal_string_p); + ecma_object_t *internal_object_p; + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (obj_p, + internal_string_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + internal_object_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL); + value_p->value = ecma_make_object_value (internal_object_p); + ecma_deref_object (internal_object_p); + } + else + { + internal_object_p = ecma_get_object_from_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + } + + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (prop_name_val); + property_p = ecma_find_named_property (internal_object_p, prop_name_p); + + if (property_p == NULL) + { + ecma_property_value_t *value_p = ecma_create_named_data_property (internal_object_p, + prop_name_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + value_p->value = ecma_copy_value_if_not_object (value_to_set); + } + else + { + ecma_named_data_property_assign_value (internal_object_p, ECMA_PROPERTY_VALUE_PTR (property_p), value_to_set); + } + + return true; +} /* jerry_set_internal_property */ + /** * Initialize property descriptor. */ diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index ad2828d92..8feaed429 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -502,15 +502,20 @@ jerry_value_t jerry_create_undefined (void); */ jerry_value_t jerry_has_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_has_own_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); +bool jerry_has_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); bool jerry_delete_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); bool jerry_delete_property_by_index (const jerry_value_t obj_val, uint32_t index); +bool jerry_delete_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_get_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); +jerry_value_t jerry_get_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); jerry_value_t jerry_set_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, const jerry_value_t value_to_set); jerry_value_t jerry_set_property_by_index (const jerry_value_t obj_val, uint32_t index, const jerry_value_t value_to_set); +bool jerry_set_internal_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, + const jerry_value_t value_to_set); void jerry_init_property_descriptor_fields (jerry_property_descriptor_t *prop_desc_p); jerry_value_t jerry_define_own_property (const jerry_value_t obj_val, diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index faf636b40..509b99953 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -48,6 +48,7 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT, /**< [[RemainingElement]] property */ LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX, /**< [[%Iterator%NextIndex]] property */ LIT_INTERNAL_MAGIC_STRING_MAP_KEY, /**< Property key used when an object is a key in a map object */ + LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */ /* List of well known symbols */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */ diff --git a/tests/unit-core/test-internal-properties.c b/tests/unit-core/test-internal-properties.c new file mode 100644 index 000000000..c9a5ec9bb --- /dev/null +++ b/tests/unit-core/test-internal-properties.c @@ -0,0 +1,240 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jerryscript.h" +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" +#include "test-common.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t object = jerry_create_object (); + + jerry_value_t prop_name_1 = jerry_create_string ((const jerry_char_t *) "foo"); + jerry_value_t prop_name_2 = jerry_create_string ((const jerry_char_t *) "non_hidden_prop"); + jerry_value_t prop_name_3; + + if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_value_t prop_name_3_desc = jerry_create_string ((const jerry_char_t *) "bar"); + prop_name_3 = jerry_create_symbol (prop_name_3_desc); + jerry_release_value (prop_name_3_desc); + } + else + { + prop_name_3 = jerry_create_string ((const jerry_char_t *) "non_hidden_string_prop"); + } + + jerry_value_t internal_prop_name_1 = jerry_create_string ((const jerry_char_t *) "hidden_foo"); + jerry_value_t internal_prop_name_2 = jerry_create_string ((const jerry_char_t *) "hidden_prop"); + jerry_value_t internal_prop_name_3; + + if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) + { + jerry_value_t internal_prop_name_3_desc = jerry_create_string ((const jerry_char_t *) "bar"); + internal_prop_name_3 = jerry_create_symbol (internal_prop_name_3_desc); + jerry_release_value (internal_prop_name_3_desc); + } + else + { + internal_prop_name_3 = jerry_create_string ((const jerry_char_t *) "hidden_string_prop"); + } + + jerry_value_t prop_value_1 = jerry_create_number (5.5); + jerry_value_t prop_value_2 = jerry_create_number (6.5); + jerry_value_t prop_value_3 = jerry_create_number (7.5); + + jerry_value_t internal_prop_value_1 = jerry_create_number (8.5); + jerry_value_t internal_prop_value_2 = jerry_create_number (9.5); + jerry_value_t internal_prop_value_3 = jerry_create_number (10.5); + + /* Test the normal [[Set]] method */ + bool set_result_1 = jerry_set_property (object, prop_name_1, prop_value_1); + bool set_result_2 = jerry_set_property (object, prop_name_2, prop_value_2); + bool set_result_3 = jerry_set_property (object, prop_name_3, prop_value_3); + + TEST_ASSERT (set_result_1); + TEST_ASSERT (set_result_2); + TEST_ASSERT (set_result_3); + + /* Test the internal [[Set]] method */ + bool set_internal_result_1 = jerry_set_internal_property (object, internal_prop_name_1, internal_prop_value_1); + bool set_internal_result_2 = jerry_set_internal_property (object, internal_prop_name_2, internal_prop_value_2); + bool set_internal_result_3 = jerry_set_internal_property (object, internal_prop_name_3, internal_prop_value_3); + + TEST_ASSERT (set_internal_result_1); + TEST_ASSERT (set_internal_result_2); + TEST_ASSERT (set_internal_result_3); + + /* Test the normal [[Has]] method. */ + jerry_value_t has_result_1 = jerry_has_property (object, prop_name_1); + jerry_value_t has_result_2 = jerry_has_property (object, prop_name_2); + jerry_value_t has_result_3 = jerry_has_property (object, prop_name_3); + jerry_value_t has_result_4 = jerry_has_property (object, internal_prop_name_1); + jerry_value_t has_result_5 = jerry_has_property (object, internal_prop_name_2); + jerry_value_t has_result_6 = jerry_has_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_boolean (has_result_1) && jerry_get_boolean_value (has_result_1)); + TEST_ASSERT (jerry_value_is_boolean (has_result_2) && jerry_get_boolean_value (has_result_2)); + TEST_ASSERT (jerry_value_is_boolean (has_result_3) && jerry_get_boolean_value (has_result_3)); + TEST_ASSERT (jerry_value_is_boolean (has_result_4) && !jerry_get_boolean_value (has_result_4)); + TEST_ASSERT (jerry_value_is_boolean (has_result_5) && !jerry_get_boolean_value (has_result_5)); + TEST_ASSERT (jerry_value_is_boolean (has_result_6) && !jerry_get_boolean_value (has_result_6)); + + jerry_release_value (has_result_1); + jerry_release_value (has_result_2); + jerry_release_value (has_result_3); + jerry_release_value (has_result_4); + jerry_release_value (has_result_5); + jerry_release_value (has_result_6); + + /* Test the internal [[Has]] method. */ + bool has_internal_result_1 = jerry_has_internal_property (object, prop_name_1); + bool has_internal_result_2 = jerry_has_internal_property (object, prop_name_2); + bool has_internal_result_3 = jerry_has_internal_property (object, prop_name_3); + bool has_internal_result_4 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_internal_result_5 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_internal_result_6 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (!has_internal_result_1); + TEST_ASSERT (!has_internal_result_2); + TEST_ASSERT (!has_internal_result_3); + TEST_ASSERT (has_internal_result_4); + TEST_ASSERT (has_internal_result_5); + TEST_ASSERT (has_internal_result_6); + + /* Test the normal [[Get]] method. */ + jerry_value_t get_result_1 = jerry_get_property (object, prop_name_1); + jerry_value_t get_result_2 = jerry_get_property (object, prop_name_2); + jerry_value_t get_result_3 = jerry_get_property (object, prop_name_3); + jerry_value_t get_result_4 = jerry_get_property (object, internal_prop_name_1); + jerry_value_t get_result_5 = jerry_get_property (object, internal_prop_name_2); + jerry_value_t get_result_6 = jerry_get_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_number (get_result_1) && jerry_get_number_value (get_result_1) == 5.5); + TEST_ASSERT (jerry_value_is_number (get_result_2) && jerry_get_number_value (get_result_2) == 6.5); + TEST_ASSERT (jerry_value_is_number (get_result_3) && jerry_get_number_value (get_result_3) == 7.5); + TEST_ASSERT (jerry_value_is_undefined (get_result_4)); + TEST_ASSERT (jerry_value_is_undefined (get_result_5)); + TEST_ASSERT (jerry_value_is_undefined (get_result_6)); + + jerry_release_value (get_result_1); + jerry_release_value (get_result_2); + jerry_release_value (get_result_3); + jerry_release_value (get_result_4); + jerry_release_value (get_result_5); + jerry_release_value (get_result_6); + + /* Test the internal [[Get]] method. */ + jerry_value_t get_internal_result_1 = jerry_get_internal_property (object, prop_name_1); + jerry_value_t get_internal_result_2 = jerry_get_internal_property (object, prop_name_2); + jerry_value_t get_internal_result_3 = jerry_get_internal_property (object, prop_name_3); + jerry_value_t get_internal_result_4 = jerry_get_internal_property (object, internal_prop_name_1); + jerry_value_t get_internal_result_5 = jerry_get_internal_property (object, internal_prop_name_2); + jerry_value_t get_internal_result_6 = jerry_get_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_1)); + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_2)); + TEST_ASSERT (jerry_value_is_undefined (get_internal_result_3)); + TEST_ASSERT (jerry_value_is_number (get_internal_result_4) && jerry_get_number_value (get_internal_result_4) == 8.5); + TEST_ASSERT (jerry_value_is_number (get_internal_result_5) && jerry_get_number_value (get_internal_result_5) == 9.5); + TEST_ASSERT (jerry_value_is_number (get_internal_result_6) && jerry_get_number_value (get_internal_result_6) == 10.5); + + jerry_release_value (get_internal_result_1); + jerry_release_value (get_internal_result_2); + jerry_release_value (get_internal_result_3); + jerry_release_value (get_internal_result_4); + jerry_release_value (get_internal_result_5); + jerry_release_value (get_internal_result_6); + + /* Test the normal [[Delete]] method. */ + bool delete_result_1 = jerry_delete_property (object, prop_name_1); + bool delete_result_2 = jerry_delete_property (object, prop_name_2); + bool delete_result_3 = jerry_delete_property (object, prop_name_3); + bool delete_result_4 = jerry_delete_property (object, internal_prop_name_1); + bool delete_result_5 = jerry_delete_property (object, internal_prop_name_2); + bool delete_result_6 = jerry_delete_property (object, internal_prop_name_3); + + TEST_ASSERT (delete_result_1); + TEST_ASSERT (delete_result_2); + TEST_ASSERT (delete_result_3); + TEST_ASSERT (delete_result_4); + TEST_ASSERT (delete_result_5); + TEST_ASSERT (delete_result_6); + + jerry_value_t has_after_delete_result_1 = jerry_has_property (object, prop_name_1); + jerry_value_t has_after_delete_result_2 = jerry_has_property (object, prop_name_2); + jerry_value_t has_after_delete_result_3 = jerry_has_property (object, prop_name_3); + bool has_after_delete_result_4 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_after_delete_result_5 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_after_delete_result_6 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_1) + && !jerry_get_boolean_value (has_after_delete_result_1)); + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_2) + && !jerry_get_boolean_value (has_after_delete_result_2)); + TEST_ASSERT (jerry_value_is_boolean (has_after_delete_result_3) + && !jerry_get_boolean_value (has_after_delete_result_3)); + TEST_ASSERT (has_after_delete_result_4); + TEST_ASSERT (has_after_delete_result_5); + TEST_ASSERT (has_after_delete_result_6); + + jerry_release_value (has_after_delete_result_1); + jerry_release_value (has_after_delete_result_2); + jerry_release_value (has_after_delete_result_3); + + /* Test the internal [[Delete]] method. */ + bool delete_internal_result_4 = jerry_delete_internal_property (object, internal_prop_name_1); + bool delete_internal_result_5 = jerry_delete_internal_property (object, internal_prop_name_2); + bool delete_internal_result_6 = jerry_delete_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (delete_internal_result_4); + TEST_ASSERT (delete_internal_result_5); + TEST_ASSERT (delete_internal_result_6); + + bool has_after_internal_delete_result_1 = jerry_has_internal_property (object, internal_prop_name_1); + bool has_after_internal_delete_result_2 = jerry_has_internal_property (object, internal_prop_name_2); + bool has_after_internal_delete_result_3 = jerry_has_internal_property (object, internal_prop_name_3); + + TEST_ASSERT (!has_after_internal_delete_result_1); + TEST_ASSERT (!has_after_internal_delete_result_2); + TEST_ASSERT (!has_after_internal_delete_result_3); + + /* Cleanup */ + jerry_release_value (prop_value_3); + jerry_release_value (prop_value_2); + jerry_release_value (prop_value_1); + + jerry_release_value (prop_name_3); + jerry_release_value (prop_name_2); + jerry_release_value (prop_name_1); + + jerry_release_value (internal_prop_value_3); + jerry_release_value (internal_prop_value_2); + jerry_release_value (internal_prop_value_1); + + jerry_release_value (internal_prop_name_3); + jerry_release_value (internal_prop_name_2); + jerry_release_value (internal_prop_name_1); + + jerry_release_value (object); + + jerry_cleanup (); + + return 0; +} /* main */