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 #include "jerryscript.h"
17 #include "test-common.h"
18
19 static bool
count_objects(jerry_value_t object,void * user_arg)20 count_objects (jerry_value_t object, void *user_arg)
21 {
22 (void) object;
23 TEST_ASSERT (user_arg != NULL);
24
25 int *counter = (int *) user_arg;
26
27 (*counter)++;
28 return true;
29 } /* count_objects */
30
31 static void
test_container(void)32 test_container (void)
33 {
34 jerry_value_t global = jerry_get_global_object ();
35 jerry_value_t map_str = jerry_create_string ((const jerry_char_t *) "Map");
36 jerry_value_t map_result = jerry_get_property (global, map_str);
37 jerry_type_t type = jerry_value_get_type (map_result);
38
39 jerry_release_value (map_result);
40 jerry_release_value (map_str);
41 jerry_release_value (global);
42
43 /* If there is no Map function this is not an es2015 profile build, skip this test case. */
44 if (type != JERRY_TYPE_FUNCTION)
45 {
46 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Container based test is disabled!\n");
47 return;
48 }
49
50 {
51 /* Create a "DEMO" array which will be used for the Map below. */
52 const char array_str[] = "var DEMO = [[1, 2], [3, 4]]; DEMO";
53 jerry_value_t array = jerry_eval ((const jerry_char_t *) array_str, sizeof (array_str) - 1, 0);
54 TEST_ASSERT (jerry_value_is_object (array));
55 TEST_ASSERT (!jerry_value_is_error (array));
56 jerry_release_value (array);
57 }
58
59 const char eval_str[] = "new Map (DEMO)";
60 {
61 /* Make sure that the Map and it's prototype object/function is initialized. */
62 jerry_value_t result = jerry_eval ((const jerry_char_t *) eval_str, sizeof (eval_str) - 1, 0);
63 TEST_ASSERT (jerry_value_is_object (result));
64 TEST_ASSERT (!jerry_value_is_error (result));
65 jerry_release_value (result);
66 }
67
68 /* Do a bit of cleaning to clear up old objects. */
69 jerry_gc (JERRY_GC_PRESSURE_LOW);
70
71 /* Get the number of iterable objects. */
72 int start_count = 0;
73 jerry_objects_foreach (count_objects, &start_count);
74
75 /* Create another map. */
76 jerry_value_t result = jerry_eval ((const jerry_char_t *) eval_str, sizeof (eval_str) - 1, 0);
77
78 /* Remove any old/unused objects. */
79 jerry_gc (JERRY_GC_PRESSURE_LOW);
80
81 /* Get the current number of objects. */
82 int end_count = 0;
83 jerry_objects_foreach (count_objects, &end_count);
84
85 /* As only one Map was created the number of available iterable objects should be incremented only by one. */
86 TEST_ASSERT (end_count > start_count);
87 TEST_ASSERT ((end_count - start_count) == 1);
88
89 jerry_release_value (result);
90 } /* test_container */
91
92 static void
test_internal_prop(void)93 test_internal_prop (void)
94 {
95 /* Make sure that the object is initialized in the engine. */
96 {
97 jerry_value_t object = jerry_create_object ();
98 jerry_release_value (object);
99 }
100
101 /* Get the number of iterable objects. */
102 int before_object_count = 0;
103 jerry_objects_foreach (count_objects, &before_object_count);
104
105 jerry_value_t object = jerry_create_object ();
106
107 /* After creating the object, the number of objects is incremented by one. */
108 int after_object_count = 0;
109 {
110 jerry_objects_foreach (count_objects, &after_object_count);
111
112 TEST_ASSERT (after_object_count > before_object_count);
113 TEST_ASSERT ((after_object_count - before_object_count) == 1);
114 }
115
116 jerry_value_t internal_prop_name = jerry_create_string ((const jerry_char_t *) "hidden_foo");
117 jerry_value_t internal_prop_object = jerry_create_object ();
118 bool internal_result = jerry_set_internal_property (object, internal_prop_name, internal_prop_object);
119 TEST_ASSERT (internal_result == true);
120 jerry_release_value (internal_prop_name);
121 jerry_release_value (internal_prop_object);
122
123 /* After adding an internal property object, the number of object is incremented by one. */
124 {
125 int after_internal_count = 0;
126 jerry_objects_foreach (count_objects, &after_internal_count);
127
128 TEST_ASSERT (after_internal_count > after_object_count);
129 TEST_ASSERT ((after_internal_count - after_object_count) == 1);
130 }
131
132 jerry_release_value (object);
133 } /* test_internal_prop */
134
135 static int test_data = 1;
136
free_test_data(void * data_p)137 static void free_test_data (void *data_p)
138 {
139 TEST_ASSERT ((int *) data_p == &test_data);
140 } /* free_test_data */
141
142 static const jerry_object_native_info_t test_info =
143 {
144 .free_cb = free_test_data
145 };
146
147 static const jerry_char_t strict_equal_source[] = "var x = function(a, b) {return a === b;}; x";
148
149 static bool
find_test_object_by_data(const jerry_value_t candidate,void * object_data_p,void * context_p)150 find_test_object_by_data (const jerry_value_t candidate,
151 void *object_data_p,
152 void *context_p)
153 {
154 if (object_data_p == &test_data)
155 {
156 *((jerry_value_t *) context_p) = jerry_acquire_value (candidate);
157 return false;
158 }
159 return true;
160 } /* find_test_object_by_data */
161
162 static bool
find_test_object_by_property(const jerry_value_t candidate,void * context_p)163 find_test_object_by_property (const jerry_value_t candidate,
164 void *context_p)
165 {
166 jerry_value_t *args_p = (jerry_value_t *) context_p;
167 jerry_value_t result = jerry_has_property (candidate, args_p[0]);
168
169 bool has_property = (!jerry_value_is_error (result) && jerry_get_boolean_value (result));
170
171 /* If the object has the desired property, store a new reference to it in args_p[1]. */
172 if (has_property)
173 {
174 args_p[1] = jerry_acquire_value (candidate);
175 }
176
177 jerry_release_value (result);
178
179 /* Stop iterating if we've found our object. */
180 return !has_property;
181 } /* find_test_object_by_property */
182
183 int
main(void)184 main (void)
185 {
186 jerry_init (JERRY_INIT_EMPTY);
187
188 /* Render strict-equal as a function. */
189 jerry_value_t parse_result = jerry_parse (NULL,
190 0,
191 strict_equal_source,
192 sizeof (strict_equal_source) - 1,
193 JERRY_PARSE_STRICT_MODE);
194 TEST_ASSERT (!jerry_value_is_error (parse_result));
195 jerry_value_t strict_equal = jerry_run (parse_result);
196 TEST_ASSERT (!jerry_value_is_error (strict_equal));
197 jerry_release_value (parse_result);
198
199 /* Create an object and associate some native data with it. */
200 jerry_value_t object = jerry_create_object ();
201 jerry_set_object_native_pointer (object, &test_data, &test_info);
202
203 /* Retrieve the object by its native pointer. */
204
205 jerry_value_t found_object;
206 TEST_ASSERT (jerry_objects_foreach_by_native_info (&test_info, find_test_object_by_data, &found_object));
207 jerry_value_t args[2] = {object, found_object};
208
209 /* Assert that the correct object was retrieved. */
210 jerry_value_t undefined = jerry_create_undefined ();
211 jerry_value_t strict_equal_result = jerry_call_function (strict_equal, undefined, args, 2);
212 TEST_ASSERT (jerry_value_is_boolean (strict_equal_result) && jerry_get_boolean_value (strict_equal_result));
213 jerry_release_value (strict_equal_result);
214 jerry_release_value (found_object);
215 jerry_release_value (object);
216
217 /* Collect garbage. */
218 jerry_gc (JERRY_GC_PRESSURE_LOW);
219
220 /* Attempt to retrieve the object by its native pointer again. */
221 TEST_ASSERT (!jerry_objects_foreach_by_native_info (&test_info, find_test_object_by_data, &found_object));
222
223 /* Create an object and set a property on it. */
224 object = jerry_create_object ();
225 jerry_value_t property_name = jerry_create_string ((jerry_char_t *) "xyzzy");
226 jerry_value_t property_value = jerry_create_number (42);
227 jerry_release_value (jerry_set_property (object, property_name, property_value));
228 jerry_release_value (property_value);
229
230 /* Retrieve the object by the presence of its property, placing it at args[1]. */
231 args[0] = property_name;
232 TEST_ASSERT (jerry_objects_foreach (find_test_object_by_property, args));
233
234 /* Assert that the right object was retrieved and release both the original reference to it and the retrieved one. */
235 args[0] = object;
236 strict_equal_result = jerry_call_function (strict_equal, undefined, args, 2);
237 TEST_ASSERT (jerry_value_is_boolean (strict_equal_result) && jerry_get_boolean_value (strict_equal_result));
238 jerry_release_value (strict_equal_result);
239 jerry_release_value (args[0]);
240 jerry_release_value (args[1]);
241
242 /* Collect garbage. */
243 jerry_gc (JERRY_GC_PRESSURE_LOW);
244
245 /* Attempt to retrieve the object by the presence of its property again. */
246 args[0] = property_name;
247 TEST_ASSERT (!jerry_objects_foreach (find_test_object_by_property, args));
248
249 jerry_release_value (property_name);
250 jerry_release_value (undefined);
251 jerry_release_value (strict_equal);
252
253 test_container ();
254 test_internal_prop ();
255
256 jerry_cleanup ();
257
258 return 0;
259 } /* main */
260