Introduce new jerry-ext methods to ease property registration (#2715)

New methods
* jerryx_set_properties: Allows multiple property registration for via a single call
* jerryx_set_property_str: Allows property registration without the need to
    create the property name JS value. The property name can be directly passed
    as a `const char*` value and must be zero terminated.
* jerryx_get_property_str: Allows getting a property value on a given object.
    The property name can be directly passed as a `const char*` value.
* jerryx_has_property_str: Allows checking if a property exists on a given object.

JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
This commit is contained in:
Péter Gál
2019-07-25 20:37:44 +02:00
committed by Robert Fancsik
parent 3e12738037
commit c64ee882da
4 changed files with 925 additions and 0 deletions
+415
View File
@@ -1,3 +1,418 @@
# Common methods to handle properties
The `jerryscript-ext/handler.h` header defines a set of convenience methods
which makes the property access a bit straightforward.
## jerryx_set_property_str
**Summary**
Set a property on a target object with a given name.
*Note*:
- The property name must be a zero terminated UTF-8 string.
- There should be no '\0' (NULL) character in the name excluding the string terminator.
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
is no longer needed.
**Prototype**
```c
jerry_value_t
jerryx_set_property_str (const jerry_value_t target_object,
const char *name,
const jerry_value_t value);
```
- `target_object` - the object where the property should be set
- `name` - name of the property
- `value` - property value to be set
- return value
- JS true value, if success
- thrown error, if there was a problem setting the property
**Example**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
int
main (int argc, char **argv)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t global = jerry_get_global_object ();
jerry_value_t value = jerry_create_number (3.3);
jerry_value_t result = jerryx_set_property_str (global, "value", value);
if (jerry_value_is_error (result))
{
/* The error type/reason can be extracted via the `jerry_get_value_from_error` method */
printf ("Error during property configuration\r\n");
}
jerry_release_value (result);
jerry_release_value (value);
jerry_release_value (global);
jerry_cleanup();
return 0;
}
```
## jerryx_get_property_str
**Summary**
Get the value of a property from the specified object with the given name.
*Notes*:
- The property name must be a zero terminated UTF-8 string.
- There should be no '\0' (NULL) character in the name excluding the string terminator.
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
is no longer needed.
**Prototype**
```
jerry_value_t
jerryx_get_property_str (const jerry_value_t target_object,
const char *name);
```
- `target_object` - object on which the property name is accessed
- `name` - property name as an UTF-8 `char*`
- return value
- value of property, if success
- thrown error, if there was a problem accessing the property
**Example**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
int
main (int argc, char **argv)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t global = jerry_get_global_object ();
jerry_value_t math_object = jerryx_get_property_str (global, "Math");
/* use math_object */
jerry_release_value (math_object);
jerry_release_value (global);
jerry_cleanup();
return 0;
}
```
## jerryx_has_property_str
**Summary**
Check if a property exists on an object.
*Notes*:
- The operation performed is the same as what the `jerry_has_property` method.
- The property name must be a zero terminated UTF-8 string.
- There should be no '\0' (NULL) character in the name excluding the string terminator.
**Prototype**
```
bool
jerryx_has_property_str (const jerry_value_t target_object,
const char *name);
```
- `target_object` - object on which the property name is accessed
- `name` - property name as an UTF-8 `char*`
- return value
- true, if the given property name exsits on the object
- false, if there is no such property name or there was an error accessing the property
**Example**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
int
main (int argc, char **argv)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t global = jerry_get_global_object ();
bool have_math = jerryx_has_property_str (global, "Math");
jerry_release_value (global);
jerry_cleanup();
return have_math ? 0 : 1;
}
```
# Utility to register multiple properties in bulk
In some cases it is useful to register multiple properties for a given object
for this the following utility structures and methods are provided.
## jerryx_property_entry
**Summary**
Structure to define an array of properties with `name` and `value` fields which
can be registered to a target object.
The engine must be initialied before specifying the `jerry_value_t` in the struct.
**Prototype**
```c
typedef struct {
const char *name;
jerry_value_t value;
} jerryx_function_list_entry;
```
**See also**
- [jerryx_set_properties](#jerryx_set_properties)
## jerryx_register_result
**Summary**
Structure returned as the result of the [jerryx_set_properties](#jerryx_set_properties) operation.
The `result` field will either be a JavaScript undefined value or an error object.
In every case the `registered` field is used to indicated the number of
successfully registered methods.
This must be passed for the [jerryx_release_property_entry](#jerryx_release_property_entry) method
after the property registration.
If any error occured during the property registration the `result` field of the structure
must be manually released after processing the error value.
**Prototype**
```c
typedef struct {
jerry_value_t result;
uint32_t registered;
} jerryx_register_result;
```
**See also**
- [jerryx_set_properties](#jerryx_set_properties)
- [jerryx_release_property_entry](#jerryx_release_property_entry)
## jerryx_set_properties
**Summary**
Set multiple properties on a target object.
The properties are an array of (name, jerry_value_t) pairs and
this list must end with a (NULL, 0) entry.
Important notes:
* Each property value in the input array is released after a successful property registration.
* The method [jerryx_release_property_entry](#jerryx_release_property_entry) must be called if there is any failed registration
to release the values in the entries array.
It is safe to call this cleanup method in every case not just in case of failure.
* If the error value is reported via the result it must be freed manually.
**Prototype**
```c
jerryx_register_result
jerryx_set_properties (const jerry_value_t target_object,
const jerryx_property_entry entries[]);
```
- `target_object` - object on which the entries will be set.
- `entries` - array of (name, jerry_value_t) pairs.
- return a [jerryx_register_result](#jerryx_register_result).
- if everything is ok, the struct's `result` field is set to a JS undefined value.
- otherwise the `result` field is an error object indicating the problem.
- in every case the `registered` field contains the number of successfully registered properties.
**Example**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
static jerry_value_t
handler (const jerry_value_t function_obj,
const jerry_value_t this_val,
const jerry_value_t args_p[],
const jerry_length_t args_cnt)
{
printf ("native handler called!\n");
return jerry_create_boolean (true);
}
int
main (int argc, char **argv)
{
jerry_init (JERRY_INIT_EMPTY);
jerryx_property_entry methods[] =
{
{ "demo", jerry_create_external_function (handler) },
{ NULL, 0 },
};
jerry_value_t global = jerry_get_global_object ();
jerryx_register_result reg = jerryx_set_properties (global, methods);
/* if `reg.result` is undefined all methods are registered */
if (jerry_value_is_error (reg.result))
{
printf ("Only registered %d properties\r\n", reg.registered);
/* clean up not registered property values */
jerryx_release_property_entry (methods, reg);
/* clean up the error */
jerry_release_value (reg.result);
}
jerry_release_value (global);
jerry_cleanup();
return 0;
}
```
**Convenience macros**
To make property registration convenient, there are a set of macros to use
when setting a property entry:
* `JERRYX_PROPERTY_NUMBER(NAME, NUMBER)` - creates a number entry.
* `JERRYX_PROPERTY_STRING(NAME, STR)` - creates an UTF-8 string entry. This string must be zero terminated.
* `JERRYX_PROPERTY_STRING_SZ(NAME, STR, SIZE)` - creates an UTF-8 string entry using only `SIZE` bytes from the string.
* `JERRYX_PROPERTY_BOOLEAN(NAME, VALUE)` - creates a boolean entry.
* `JERRYX_PROPERTY_FUNCTION(NAME, NATIVE)` - creates a native C function entry.
* `JERRYX_PROPERTY_UNDEFINED(NAME)` - creates an undefined property entry.
* `JERRYX_PROPERTY_LIST_END()` - indicates the end of the property list.
**Example usage of Convenience macros**
[doctest]: # ()
```c
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
static jerry_value_t
handler (const jerry_value_t function_obj,
const jerry_value_t this_val,
const jerry_value_t args_p[],
const jerry_length_t args_cnt)
{
printf ("native handler called!\n");
return jerry_create_boolean (true);
}
int
main (int argc, char **argv)
{
jerry_init (JERRY_INIT_EMPTY);
/**
* Create a array of properties to be registered.
* This must be done after initializing the engine as creating `jerry_value_t`
* elements are invalid before `jerry_init`.
*/
jerryx_property_entry methods[] =
{
JERRYX_PROPERTY_FUNCTION ("demo", handler),
JERRYX_PROPERTY_NUMBER ("test_num", 2.3),
JERRYX_PROPERTY_UNDEFINED ("this_is_undefined"),
JERRYX_PROPERTY_LIST_END(),
};
jerry_value_t global = jerry_get_global_object ();
jerryx_register_result reg = jerryx_set_properties (global, methods);
/* if `reg.result` is undefined all methods are registered */
if (jerry_value_is_error (reg.result))
{
printf ("Only registered %d properties\r\n", reg.registered);
/* clean up not registered property values */
jerryx_release_property_entry (methods, reg);
/* clean up the error */
jerry_release_value (reg.result);
}
jerry_release_value (global);
jerry_cleanup();
return 0;
}
```
**See also**
- [jerryx_property_entry](#jerryx_property_entry)
- [jerryx_release_property_entry](#jerryx_release_property_entry)
- [jerryx_register_result](#jerryx_register_result)
## jerryx_release_property_entry
**Summary**
Release all `jerry_value_t` in a `jerryx_property_entry` array based on a previous [jerryx_set_properties](#jerryx_set_properties) call
and also the error value (if any) in the `jerryx_register_result` structure.
In case of a successful registration it is safe to call this method.
After the method call the `ęntries` array should not be used as all values are released.
**Prototype**
```
void
jerryx_release_property_entry (const jerryx_property_entry entries[],
const jerryx_register_result register_result);
```
- `entires` - array of [jerryx_property_entry](#jerryx_property_entry).
- `register_result` - result of a previous [jerryx_set_properties](#jerryx_set_properties) call.
**Example**
For example usage see [jerryx_set_properties](#jerryx_set_properties).
# Common external function handlers
## jerryx_handler_assert_fatal
+144
View File
@@ -40,3 +40,147 @@ jerryx_handler_register_global (const jerry_char_t *name_p, /**< name of the fun
return result_val;
} /* jerryx_handler_register_global */
/**
* Set multiple properties on a target object.
*
* The properties are an array of (name, property value) pairs and
* this list must end with a (NULL, 0) entry.
*
* Notes:
* - Each property value in the input array is released after a successful property registration.
* - The property name must be a zero terminated UTF-8 string.
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
* - The method `jerryx_release_property_entry` must be called if there is any failed registration
* to release the values in the entries array.
*
* @return `jerryx_register_result` struct - if everything is ok with the (undefined, property entry count) values.
* In case of error the (error object, registered property count) pair.
*/
jerryx_register_result
jerryx_set_properties (const jerry_value_t target_object, /**< target object */
const jerryx_property_entry entries[]) /**< array of method entries */
{
#define JERRYX_SET_PROPERTIES_RESULT(VALUE, IDX) ((jerryx_register_result) { VALUE, IDX })
uint32_t idx = 0;
for (; ((entries + idx) != NULL) && (entries[idx].name != NULL); idx++)
{
const jerryx_property_entry *entry = &entries[idx];
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) entry->name);
jerry_value_t result = jerry_set_property (target_object, prop_name, entry->value);
jerry_release_value (prop_name);
// By API definition:
// The jerry_set_property returns TRUE if there is no problem
// and error object if there is any problem.
// Thus there is no need to check if the boolean value is false or not.
if (!jerry_value_is_boolean (result))
{
return JERRYX_SET_PROPERTIES_RESULT (result, idx);
}
jerry_release_value (entry->value);
jerry_release_value (result);
}
return JERRYX_SET_PROPERTIES_RESULT (jerry_create_undefined (), idx);
#undef JERRYX_SET_PROPERTIES_RESULT
} /* jerryx_set_properties */
/**
* Release all jerry_value_t in a jerryx_property_entry array based on
* a previous jerryx_set_properties call.
*
* In case of a successful registration it is safe to call this method.
*/
void
jerryx_release_property_entry (const jerryx_property_entry entries[], /**< list of property entries */
const jerryx_register_result register_result) /**< previous result of registration */
{
for (uint32_t idx = register_result.registered;
((entries + idx) != NULL) && (entries[idx].name != NULL);
idx++)
{
jerry_release_value (entries[idx].value);
}
} /* jerryx_release_property_entry */
/**
* Set a property to a specified value with a given name.
*
* Notes:
* - The operation performed is the same as what the `jerry_set_property` method.
* - The property name must be a zero terminated UTF-8 string.
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
* - Returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return true value - if the operation was successful
* thrown error - otherwise
*/
jerry_value_t
jerryx_set_property_str (const jerry_value_t target_object, /**< target object */
const char *name, /**< property name */
const jerry_value_t value) /**< value to set */
{
jerry_value_t property_name_val = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
jerry_value_t result_val = jerry_set_property (target_object, property_name_val, value);
jerry_release_value (property_name_val);
return result_val;
} /* jerryx_set_property_str */
/**
* Get a property value of a specified object.
*
* Notes:
* - The operation performed is the same as what the `jerry_get_property` method.
* - The property name must be a zero terminated UTF-8 string.
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
* - Returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return jerry_value_t - the property value
*/
jerry_value_t
jerryx_get_property_str (const jerry_value_t target_object, /**< target object */
const char *name) /**< property name */
{
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
jerry_value_t result_val = jerry_get_property (target_object, prop_name);
jerry_release_value (prop_name);
return result_val;
} /* jerryx_get_property_str */
/**
* Check if a property exists on an object.
*
* Notes:
* - The operation performed is the same as what the `jerry_has_property` method.
* - The property name must be a zero terminated UTF-8 string.
* - There should be no '\0' (NULL) character in the name excluding the string terminator.
*
* @return true - if the property exists on the given object.
* false - if there is no such property or there was an error accessing the property.
*/
bool
jerryx_has_property_str (const jerry_value_t target_object, /**< target object */
const char *name) /**< property name */
{
bool has_property = false;
jerry_value_t prop_name = jerry_create_string_from_utf8 ((const jerry_char_t *) name);
jerry_value_t has_prop_val = jerry_has_property (target_object, prop_name);
if (!jerry_value_is_error (has_prop_val))
{
has_property = jerry_get_boolean_value (has_prop_val);
}
jerry_release_value (has_prop_val);
jerry_release_value (prop_name);
return has_property;
} /* jerryx_has_property_str */
@@ -45,6 +45,56 @@ jerry_value_t jerryx_handler_gc (const jerry_value_t func_obj_val, const jerry_v
jerry_value_t jerryx_handler_print (const jerry_value_t func_obj_val, const jerry_value_t this_p,
const jerry_value_t args_p[], const jerry_length_t args_cnt);
/**
* Struct used by the `jerryx_set_functions` method to
* register multiple methods for a given object.
*/
typedef struct
{
const char *name; /**< name of the property to add */
jerry_value_t value; /**< value of the property */
} jerryx_property_entry;
#define JERRYX_PROPERTY_NUMBER(NAME, NUMBER) (jerryx_property_entry) { NAME, jerry_create_number (NUMBER) }
#define JERRYX_PROPERTY_STRING(NAME, STR) \
(jerryx_property_entry) { NAME, jerry_create_string_from_utf8 ((const jerry_char_t *) STR) }
#define JERRYX_PROPERTY_STRING_SZ(NAME, STR, SIZE) \
(jerryx_property_entry) { NAME, jerry_create_string_sz_from_utf8 ((const jerry_char_t *) STR, SIZE) }
#define JERRYX_PROPERTY_BOOLEAN(NAME, VALUE) (jerryx_property_entry) { NAME, jerry_create_boolean (VALUE) }
#define JERRYX_PROPERTY_FUNCTION(NAME, FUNC) (jerryx_property_entry) { NAME, jerry_create_external_function (FUNC) }
#define JERRYX_PROPERTY_UNDEFINED(NAME) (jerryx_property_entry) { NAME, jerry_create_undefined() }
#define JERRYX_PROPERTY_LIST_END() (jerryx_property_entry) { NULL, 0 }
/**
* Stores the result of property register operation.
*/
typedef struct
{
jerry_value_t result; /**< result of property registraion (undefined or error object) */
uint32_t registered; /**< number of successfully registered methods */
} jerryx_register_result;
jerryx_register_result
jerryx_set_properties (const jerry_value_t target_object,
const jerryx_property_entry entries[]);
void
jerryx_release_property_entry (const jerryx_property_entry entries[],
const jerryx_register_result register_result);
jerry_value_t
jerryx_set_property_str (const jerry_value_t target_object,
const char *name,
const jerry_value_t value);
jerry_value_t
jerryx_get_property_str (const jerry_value_t target_object,
const char *name);
bool
jerryx_has_property_str (const jerry_value_t target_object,
const char *name);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+316
View File
@@ -0,0 +1,316 @@
/* 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.
*/
/**
* Unit test for jerry-ext/handler property registration
*/
#include "jerryscript.h"
#include "jerryscript-ext/handler.h"
#include "test-common.h"
#include <string.h>
static jerry_value_t
method_hello (const jerry_value_t jfunc, /**< function object */
const jerry_value_t jthis, /**< function this */
const jerry_value_t jargv[], /**< arguments */
const jerry_length_t jargc) /**< number of arguments */
{
(void) jfunc;
(void) jthis;
(void) jargv;
return jerry_create_number (jargc);
} /* method_hello */
/**
* Helper method to create a non-configurable property on an object
*/
static void
freeze_property (jerry_value_t target_obj, /**< target object */
const char *target_prop) /**< target property name */
{
// "freeze" property
jerry_property_descriptor_t prop_desc;
jerry_init_property_descriptor_fields (&prop_desc);
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = false;
jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) target_prop);
jerry_value_t return_value = jerry_define_own_property (target_obj, prop_name, &prop_desc);
TEST_ASSERT (jerry_value_is_boolean (return_value));
jerry_release_value (return_value);
jerry_release_value (prop_name);
jerry_free_property_descriptor_fields (&prop_desc);
} /* freeze_property */
/**
* Test registration of various property values.
*/
static void
test_simple_registration (void)
{
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t target_object = jerry_create_object ();
// Test simple registration
jerryx_property_entry methods[] =
{
JERRYX_PROPERTY_FUNCTION ("hello", method_hello),
JERRYX_PROPERTY_NUMBER ("my_number", 42.5),
JERRYX_PROPERTY_STRING ("my_str", "super_str"),
JERRYX_PROPERTY_STRING_SZ ("my_str_sz", "super_str", 6),
JERRYX_PROPERTY_BOOLEAN ("my_bool", true),
JERRYX_PROPERTY_BOOLEAN ("my_bool_false", false),
JERRYX_PROPERTY_UNDEFINED ("my_non_value"),
JERRYX_PROPERTY_LIST_END (),
};
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
TEST_ASSERT (register_result.registered == 7);
TEST_ASSERT (jerry_value_is_undefined (register_result.result));
jerryx_release_property_entry (methods, register_result);
jerry_release_value (register_result.result);
jerry_value_t global_obj = jerry_get_global_object ();
jerryx_set_property_str (global_obj, "test", target_object);
jerry_release_value (target_object);
jerry_release_value (global_obj);
{
const char *test_A = "test.my_number";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_number (result));
TEST_ASSERT (jerry_get_number_value (result) == 42.5);
jerry_release_value (result);
}
{
const char *test_A = "test.my_str_sz === 'super_'";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_boolean (result));
TEST_ASSERT (jerry_get_boolean_value (result) == true);
jerry_release_value (result);
}
{
const char *test_A = "test.my_str === 'super_str'";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_boolean (result));
TEST_ASSERT (jerry_get_boolean_value (result) == true);
jerry_release_value (result);
}
{
const char *test_A = "test.my_bool";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_boolean (result));
TEST_ASSERT (jerry_get_boolean_value (result) == true);
jerry_release_value (result);
}
{
const char *test_A = "test.my_bool_false";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_boolean (result));
TEST_ASSERT (jerry_get_boolean_value (result) == false);
jerry_release_value (result);
}
{
const char *test_A = "test.my_non_value";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_undefined (result));
jerry_release_value (result);
}
{
const char *test_A = "test.hello(33, 42, 2);";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_number (result));
TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 3u);
jerry_release_value (result);
}
{
const char *test_A = "test.hello();";
jerry_value_t result = jerry_eval ((const jerry_char_t *) test_A, strlen (test_A), 0);
TEST_ASSERT (jerry_value_is_number (result));
TEST_ASSERT ((uint32_t) jerry_get_number_value (result) == 0u);
jerry_release_value (result);
}
jerry_cleanup ();
} /* test_simple_registration */
/**
* Test registration error.
*
* Trying to register a property which is already a non-configurable property
* should result in an error.
*/
static void
test_error_setvalue (void)
{
jerry_init (JERRY_INIT_EMPTY);
const char *target_prop = "test_err";
jerry_value_t global_obj = jerry_get_global_object ();
freeze_property (global_obj, target_prop);
jerry_value_t new_object = jerry_create_object ();
jerry_value_t set_result = jerryx_set_property_str (global_obj, target_prop, new_object);
TEST_ASSERT (jerry_value_is_error (set_result));
jerry_release_value (set_result);
jerry_release_value (new_object);
jerry_release_value (global_obj);
jerry_cleanup ();
} /* test_error_setvalue */
/**
* Test registration error with jerryx_set_properties.
*
* Trying to register a property which is already a non-configurable property
* should result in an error.
*/
static void
test_error_single_function (void)
{
jerry_init (JERRY_INIT_EMPTY);
const char *target_prop = "test_err";
jerry_value_t target_object = jerry_create_object ();
freeze_property (target_object, target_prop);
jerryx_property_entry methods[] =
{
JERRYX_PROPERTY_FUNCTION (target_prop, method_hello), // This registration should fail
JERRYX_PROPERTY_LIST_END (),
};
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
TEST_ASSERT (register_result.registered == 0);
TEST_ASSERT (jerry_value_is_error (register_result.result));
jerryx_release_property_entry (methods, register_result);
jerry_release_value (register_result.result);
jerry_release_value (target_object);
jerry_cleanup ();
} /* test_error_single_function */
/**
* Test to see if jerryx_set_properties exits at the first error.
*/
static void
test_error_multiple_functions (void)
{
jerry_init (JERRY_INIT_EMPTY);
const char *prop_ok = "prop_ok";
const char *prop_err = "prop_err";
const char *prop_not = "prop_not";
jerry_value_t target_object = jerry_create_object ();
freeze_property (target_object, prop_err);
jerryx_property_entry methods[] =
{
JERRYX_PROPERTY_FUNCTION (prop_ok, method_hello), // This registration is ok
JERRYX_PROPERTY_FUNCTION (prop_err, method_hello), // This registration should fail
JERRYX_PROPERTY_FUNCTION (prop_not, method_hello), // This registration is not done
JERRYX_PROPERTY_LIST_END (),
};
jerryx_register_result register_result = jerryx_set_properties (target_object, methods);
TEST_ASSERT (register_result.registered == 1);
TEST_ASSERT (jerry_value_is_error (register_result.result));
jerryx_release_property_entry (methods, register_result);
jerry_release_value (register_result.result);
{
// Test if property "prop_ok" is correctly registered.
jerry_value_t prop_ok_val = jerry_create_string ((const jerry_char_t *) prop_ok);
jerry_value_t prop_ok_exists = jerry_has_own_property (target_object, prop_ok_val);
TEST_ASSERT (jerry_get_boolean_value (prop_ok_exists) == true);
jerry_release_value (prop_ok_exists);
// Try calling the method
jerry_value_t prop_ok_func = jerry_get_property (target_object, prop_ok_val);
TEST_ASSERT (jerry_value_is_function (prop_ok_func) == true);
jerry_value_t args[2] =
{
jerry_create_number (22),
jerry_create_number (-3),
};
jerry_size_t args_cnt = sizeof (args) / sizeof (jerry_value_t);
jerry_value_t func_result = jerry_call_function (prop_ok_func,
jerry_create_undefined (),
args,
args_cnt);
TEST_ASSERT (jerry_value_is_number (func_result) == true);
TEST_ASSERT ((uint32_t) jerry_get_number_value (func_result) == 2u);
jerry_release_value (func_result);
for (jerry_size_t idx = 0; idx < args_cnt; idx++)
{
jerry_release_value (args[idx]);
}
jerry_release_value (prop_ok_func);
jerry_release_value (prop_ok_val);
}
{
// The "prop_err" should exist - as it was "freezed" - but it should not be a function
jerry_value_t prop_err_val = jerry_create_string ((const jerry_char_t *) prop_err);
jerry_value_t prop_err_exists = jerry_has_own_property (target_object, prop_err_val);
TEST_ASSERT (jerry_get_boolean_value (prop_err_exists) == true);
jerry_release_value (prop_err_exists);
jerry_value_t prop_err_func = jerry_value_is_function (prop_err_val);
TEST_ASSERT (jerry_value_is_function (prop_err_func) == false);
jerry_release_value (prop_err_val);
}
{ // The "prop_not" is not available on the target object
jerry_value_t prop_not_val = jerry_create_string ((const jerry_char_t *) prop_not);
jerry_value_t prop_not_exists = jerry_has_own_property (target_object, prop_not_val);
TEST_ASSERT (jerry_get_boolean_value (prop_not_exists) == false);
jerry_release_value (prop_not_exists);
jerry_release_value (prop_not_val);
}
jerry_release_value (target_object);
jerry_cleanup ();
} /* test_error_multiple_functions */
int
main (void)
{
test_simple_registration ();
test_error_setvalue ();
test_error_single_function ();
test_error_multiple_functions ();
return 0;
} /* main */