• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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