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 <string.h>
17
18 #include "jerryscript.h"
19 #include "test-common.h"
20 #include "jerryscript-ext/module.h"
21
22 /* Load a module. */
23 const char eval_string1[] = "require ('my_custom_module');";
24
25 /* Load a module using a different resolver. */
26 const char eval_string2[] = "require ('differently-handled-module');";
27
28 /* Load a broken module using the built-in resolver. */
29 const char eval_string3[] =
30 "(function() {"
31 " var theError;"
32 " try {"
33 " require ('my_broken_module');"
34 " } catch (anError) {"
35 " theError = anError;"
36 " }"
37 " return (((theError.message === 'Module on_resolve () must not be NULL') &&"
38 " (theError.moduleName === 'my_broken_module') &&"
39 " (theError instanceof TypeError)) ? 1 : 0);"
40 "}) ();";
41
42 /* Load a non-existent module. */
43 const char eval_string4[] =
44 "(function() {"
45 " var theError;"
46 " try {"
47 " require ('some_missing_module_xyzzy');"
48 " } catch (anError) {"
49 " theError = anError;"
50 " }"
51 " return (((theError.message === 'Module not found') &&"
52 " (theError.moduleName === 'some_missing_module_xyzzy')) ? 1 : 0);"
53 "}) ();";
54
55 /* Make sure the result of a module load is cached. */
56 const char eval_string5[] =
57 "(function() {"
58 " var x = require('cache-check');"
59 " var y = require('cache-check');"
60 " return x === y ? 1 : 0;"
61 "}) ();";
62
63 /* Make sure the result of a module load is removed from the cache. */
64 const char eval_string6[] =
65 "(function() {"
66 " var x = require('cache-check');"
67 " clear_require_cache('cache-check');"
68 " var y = require('cache-check');"
69 " return x !== y ? 1 : 0;"
70 "}) ();";
71
72 /* Make sure the entire cache is cleared. */
73 const char eval_string7[] =
74 "(function() {"
75 " var x = require('cache-check');"
76 " clear_require_cache(undefined);"
77 " var y = require('cache-check');"
78 " return x !== y ? 1 : 0;"
79 "}) ();";
80
81 /*
82 * Define a resolver for a module named "differently-handled-module" to check that custom resolvers work.
83 */
84 static bool
resolve_differently_handled_module(const jerry_value_t name,jerry_value_t * result)85 resolve_differently_handled_module (const jerry_value_t name,
86 jerry_value_t *result)
87 {
88 jerry_size_t name_size = jerry_get_utf8_string_size (name);
89 JERRY_VLA (jerry_char_t, name_string, name_size);
90 jerry_string_to_utf8_char_buffer (name, name_string, name_size);
91
92 if (!strncmp ((char *) name_string, "differently-handled-module", name_size))
93 {
94 (*result) = jerry_create_number (29);
95 return true;
96 }
97 return false;
98 } /* resolve_differently_handled_module */
99
100 static jerryx_module_resolver_t differently_handled_module_resolver =
101 {
102 NULL,
103 resolve_differently_handled_module
104 };
105
106 /*
107 * Define module "cache-check" via its own resolver as an empty object. Since objects are accessible only via references
108 * we can strictly compare the object returned on subsequent attempts at loading "cache-check" with the object returned
109 * on the first attempt and establish that the two are in fact the same object - which in turn shows that caching works.
110 */
111 static bool
cache_check(const jerry_value_t name,jerry_value_t * result)112 cache_check (const jerry_value_t name,
113 jerry_value_t *result)
114 {
115 jerry_size_t name_size = jerry_get_utf8_string_size (name);
116 JERRY_VLA (jerry_char_t, name_string, name_size);
117 jerry_string_to_utf8_char_buffer (name, name_string, name_size);
118
119 if (!strncmp ((char *) name_string, "cache-check", name_size))
120 {
121 (*result) = jerry_create_object ();
122 return true;
123 }
124 return false;
125 } /* cache_check */
126
127 static jerryx_module_resolver_t cache_check_resolver =
128 {
129 NULL,
130 cache_check
131 };
132
133 static const jerryx_module_resolver_t *resolvers[3] =
134 {
135 &jerryx_module_native_resolver,
136 &differently_handled_module_resolver,
137 &cache_check_resolver
138 };
139
140 static jerry_value_t
handle_clear_require_cache(const jerry_value_t js_function,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_count)141 handle_clear_require_cache (const jerry_value_t js_function,
142 const jerry_value_t this_val,
143 const jerry_value_t args_p[],
144 const jerry_length_t args_count)
145 {
146 (void) js_function;
147 (void) this_val;
148 (void) args_count;
149
150 TEST_ASSERT (args_count == 1);
151 jerryx_module_clear_cache (args_p[0], resolvers, 3);
152
153 return 0;
154 } /* handle_clear_require_cache */
155
156 static jerry_value_t
handle_require(const jerry_value_t js_function,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_count)157 handle_require (const jerry_value_t js_function,
158 const jerry_value_t this_val,
159 const jerry_value_t args_p[],
160 const jerry_length_t args_count)
161 {
162 (void) js_function;
163 (void) this_val;
164 (void) args_count;
165
166 jerry_value_t return_value = 0;
167
168 TEST_ASSERT (args_count == 1);
169 return_value = jerryx_module_resolve (args_p[0], resolvers, 3);
170
171 return return_value;
172 } /* handle_require */
173
174 static void
assert_number(jerry_value_t js_value,double expected_result)175 assert_number (jerry_value_t js_value, double expected_result)
176 {
177 TEST_ASSERT (!jerry_value_is_error (js_value));
178 TEST_ASSERT (jerry_get_number_value (js_value) == expected_result);
179 } /* assert_number */
180
181 static void
eval_one(const char * the_string,double expected_result)182 eval_one (const char *the_string, double expected_result)
183 {
184 jerry_value_t js_eval_result = jerry_eval ((const jerry_char_t *) the_string,
185 strlen (the_string),
186 JERRY_PARSE_STRICT_MODE);
187 assert_number (js_eval_result, expected_result);
188 jerry_release_value (js_eval_result);
189 } /* eval_one */
190
191 #ifndef ENABLE_INIT_FINI
192 extern void my_broken_module_register (void);
193 extern void my_custom_module_register (void);
194 #endif /* !ENABLE_INIT_FINI */
195
196 int
main(int argc,char ** argv)197 main (int argc, char **argv)
198 {
199 (void) argc;
200 (void) argv;
201 jerry_value_t js_global = 0, js_function = 0, js_property_name = 0;
202 jerry_value_t res;
203
204 #ifndef ENABLE_INIT_FINI
205 my_broken_module_register ();
206 my_custom_module_register ();
207 #endif /* !ENABLE_INIT_FINI */
208
209 jerry_init (JERRY_INIT_EMPTY);
210
211 js_global = jerry_get_global_object ();
212
213 js_function = jerry_create_external_function (handle_require);
214 js_property_name = jerry_create_string ((const jerry_char_t *) "require");
215 res = jerry_set_property (js_global, js_property_name, js_function);
216 TEST_ASSERT (!jerry_value_is_error (res));
217 TEST_ASSERT (jerry_value_is_boolean (res) && jerry_get_boolean_value (res));
218 jerry_release_value (res);
219 jerry_release_value (js_property_name);
220 jerry_release_value (js_function);
221
222 js_function = jerry_create_external_function (handle_clear_require_cache);
223 js_property_name = jerry_create_string ((const jerry_char_t *) "clear_require_cache");
224 res = jerry_set_property (js_global, js_property_name, js_function);
225 TEST_ASSERT (!jerry_value_is_error (res));
226 TEST_ASSERT (jerry_value_is_boolean (res) && jerry_get_boolean_value (res));
227 jerry_release_value (res);
228 jerry_release_value (js_property_name);
229 jerry_release_value (js_function);
230
231 jerry_release_value (js_global);
232
233 eval_one (eval_string1, 42);
234 eval_one (eval_string2, 29);
235 eval_one (eval_string3, 1);
236 eval_one (eval_string4, 1);
237 eval_one (eval_string5, 1);
238 eval_one (eval_string6, 1);
239 eval_one (eval_string7, 1);
240
241 jerry_cleanup ();
242 } /* main */
243