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 "jerryscript-port.h"
18 #include "jerryscript-port-default.h"
19 #include "test-common.h"
20
21 /**
22 * Register a JavaScript value in the global object.
23 */
24 static void
register_js_value(const char * name_p,jerry_value_t value)25 register_js_value (const char *name_p, /**< name of the function */
26 jerry_value_t value) /**< JS value */
27 {
28 jerry_value_t global_obj_val = jerry_get_global_object ();
29
30 jerry_value_t name_val = jerry_create_string ((const jerry_char_t *) name_p);
31 jerry_value_t result_val = jerry_set_property (global_obj_val, name_val, value);
32 TEST_ASSERT (jerry_value_is_boolean (result_val));
33
34 jerry_release_value (name_val);
35 jerry_release_value (global_obj_val);
36
37 jerry_release_value (result_val);
38 } /* register_js_value */
39
40 static jerry_value_t
assert_handler(const jerry_value_t func_obj_val,const jerry_value_t this_val,const jerry_value_t args_p[],const jerry_length_t args_cnt)41 assert_handler (const jerry_value_t func_obj_val, /**< function object */
42 const jerry_value_t this_val, /**< this arg */
43 const jerry_value_t args_p[], /**< function arguments */
44 const jerry_length_t args_cnt) /**< number of function arguments */
45 {
46 JERRY_UNUSED (func_obj_val);
47 JERRY_UNUSED (this_val);
48
49 if (args_cnt > 0
50 && jerry_value_is_boolean (args_p[0])
51 && jerry_get_boolean_value (args_p[0]))
52 {
53 return jerry_create_boolean (true);
54 }
55
56 if (args_cnt > 1
57 && jerry_value_is_string (args_p[1]))
58 {
59 jerry_length_t utf8_sz = jerry_get_string_size (args_p[1]);
60 JERRY_VLA (char, string_from_utf8, utf8_sz);
61 string_from_utf8[utf8_sz] = 0;
62
63 jerry_string_to_char_buffer (args_p[1], (jerry_char_t *) string_from_utf8, utf8_sz);
64
65 printf ("JS assert: %s\n", string_from_utf8);
66 }
67
68 TEST_ASSERT (false);
69 } /* assert_handler */
70
71 /**
72 * Test ArrayBuffer 'read' api call with various offset values.
73 */
74 static void
test_read_with_offset(uint8_t offset)75 test_read_with_offset (uint8_t offset) /**< offset for buffer read. */
76 {
77 const jerry_char_t eval_arraybuffer_src[] = TEST_STRING_LITERAL (
78 "var array = new Uint8Array (15);"
79 "for (var i = 0; i < array.length; i++) { array[i] = i * 2; };"
80 "array.buffer"
81 );
82 jerry_value_t arraybuffer = jerry_eval (eval_arraybuffer_src,
83 sizeof (eval_arraybuffer_src) - 1,
84 JERRY_PARSE_STRICT_MODE);
85
86 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
87 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
88 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == 15);
89
90 uint8_t buffer[20];
91 memset (buffer, 120, 20);
92
93 /* Try to copy more than the target buffer size. */
94 jerry_length_t copied = jerry_arraybuffer_read (arraybuffer, offset, buffer, 20);
95 TEST_ASSERT (copied == (jerry_length_t) (15 - offset));
96
97 for (uint8_t i = 0; i < copied; i++)
98 {
99 TEST_ASSERT (buffer[i] == (i + offset) * 2);
100 }
101 TEST_ASSERT (buffer[15 - offset] == 120);
102
103 jerry_release_value (arraybuffer);
104 } /* test_read_with_offset */
105
106 /**
107 * Test ArrayBuffer 'write' api call with various offset values.
108 */
test_write_with_offset(uint8_t offset)109 static void test_write_with_offset (uint8_t offset) /**< offset for buffer write. */
110 {
111 {
112 jerry_value_t offset_val = jerry_create_number (offset);
113 register_js_value ("offset", offset_val);
114 jerry_release_value (offset_val);
115 }
116
117 const jerry_char_t eval_arraybuffer_src[] = "var array = new Uint8Array (15); array.buffer";
118 jerry_value_t arraybuffer = jerry_eval (eval_arraybuffer_src,
119 sizeof (eval_arraybuffer_src) - 1,
120 JERRY_PARSE_STRICT_MODE);
121
122 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
123 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
124 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == 15);
125
126 uint8_t buffer[20];
127
128 for (uint8_t i = 0; i < 20; i++)
129 {
130 buffer[i] = (uint8_t) (i * 3);
131 }
132
133 /* Intentionally copy more than the allowed space. */
134 jerry_length_t copied = jerry_arraybuffer_write (arraybuffer, offset, buffer, 20);
135 TEST_ASSERT (copied == (jerry_length_t) (15 - offset));
136
137 const jerry_char_t eval_test_arraybuffer[] = TEST_STRING_LITERAL (
138 "for (var i = 0; i < offset; i++)"
139 "{"
140 " assert (array[i] == 0, 'offset check for: ' + i + ' was: ' + array[i] + ' should be: 0');"
141 "};"
142 "for (var i = offset; i < array.length; i++)"
143 "{"
144 " var expected = (i - offset) * 3;"
145 " assert (array[i] == expected, 'calc check for: ' + i + ' was: ' + array[i] + ' should be: ' + expected);"
146 "};"
147 "assert (array[15] === undefined, 'ArrayBuffer out of bounds index should return undefined value');"
148 );
149 jerry_value_t res = jerry_eval (eval_test_arraybuffer,
150 sizeof (eval_test_arraybuffer) - 1,
151 JERRY_PARSE_STRICT_MODE);
152 jerry_release_value (res);
153 jerry_release_value (arraybuffer);
154 } /* test_write_with_offset */
155
156 static bool callback_called = false;
157
test_free_cb(void * buffer)158 static void test_free_cb (void *buffer) /**< buffer to free (if needed) */
159 {
160 (void) buffer;
161 callback_called = true;
162 } /* test_free_cb */
163
164 int
main(void)165 main (void)
166 {
167 jerry_init (JERRY_INIT_EMPTY);
168
169 if (!jerry_is_feature_enabled (JERRY_FEATURE_TYPEDARRAY))
170 {
171 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "ArrayBuffer is disabled!\n");
172 jerry_cleanup ();
173 return 0;
174 }
175
176 jerry_value_t function_val = jerry_create_external_function (assert_handler);
177 register_js_value ("assert", function_val);
178 jerry_release_value (function_val);
179
180 /* Test array buffer queries */
181 {
182 const jerry_char_t eval_arraybuffer_src[] = "new ArrayBuffer (10)";
183 jerry_value_t eval_arraybuffer = jerry_eval (eval_arraybuffer_src,
184 sizeof (eval_arraybuffer_src) - 1,
185 JERRY_PARSE_STRICT_MODE);
186 TEST_ASSERT (!jerry_value_is_error (eval_arraybuffer));
187 TEST_ASSERT (jerry_value_is_arraybuffer (eval_arraybuffer));
188 TEST_ASSERT (jerry_get_arraybuffer_byte_length (eval_arraybuffer) == 10);
189 jerry_release_value (eval_arraybuffer);
190 }
191
192 /* Test array buffer creation */
193 {
194 const uint32_t length = 15;
195 jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
196 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
197 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
198 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
199 jerry_release_value (arraybuffer);
200 }
201
202 /* Test array buffer read operations */
203 for (uint8_t i = 0; i < 15; i++)
204 {
205 test_read_with_offset (i);
206 }
207
208 /* Test zero length ArrayBuffer read */
209 {
210 const uint32_t length = 0;
211 jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
212 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
213 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
214 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
215
216 uint8_t data[20];
217 memset (data, 11, 20);
218
219 jerry_length_t bytes_read = jerry_arraybuffer_read (arraybuffer, 0, data, 20);
220 TEST_ASSERT (bytes_read == 0);
221
222 for (int i = 0; i < 20; i++)
223 {
224 TEST_ASSERT (data[i] == 11);
225 }
226
227 jerry_release_value (arraybuffer);
228 }
229
230 /* Test array buffer write operations */
231 for (uint8_t i = 0; i < 15; i++)
232 {
233 test_write_with_offset (i);
234 }
235
236 /* Test zero length ArrayBuffer write */
237 {
238 const uint32_t length = 0;
239 jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
240 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
241 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
242 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
243
244 uint8_t data[20];
245 memset (data, 11, 20);
246
247 jerry_length_t bytes_written = jerry_arraybuffer_write (arraybuffer, 0, data, 20);
248 TEST_ASSERT (bytes_written == 0);
249
250 jerry_release_value (arraybuffer);
251 }
252
253 /* Test zero length external ArrayBuffer */
254 {
255 const uint32_t length = 0;
256 jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, NULL, NULL);
257 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
258 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
259 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
260
261 uint8_t data[20];
262 memset (data, 11, 20);
263
264 jerry_length_t bytes_written = jerry_arraybuffer_write (arraybuffer, 0, data, 20);
265 TEST_ASSERT (bytes_written == 0);
266
267 jerry_release_value (arraybuffer);
268 }
269
270 /* Test ArrayBuffer with buffer allocated externally */
271 {
272 const uint32_t buffer_size = 15;
273 const uint8_t base_value = 51;
274
275 JERRY_VLA (uint8_t, buffer_p, buffer_size);
276 memset (buffer_p, base_value, buffer_size);
277
278 jerry_value_t arrayb = jerry_create_arraybuffer_external (buffer_size, buffer_p, test_free_cb);
279 uint8_t new_value = 123;
280 jerry_length_t copied = jerry_arraybuffer_write (arrayb, 0, &new_value, 1);
281 TEST_ASSERT (copied == 1);
282 TEST_ASSERT (buffer_p[0] == new_value);
283 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arrayb) == buffer_size);
284
285 for (uint32_t i = 1; i < buffer_size; i++)
286 {
287 TEST_ASSERT (buffer_p[i] == base_value);
288 }
289
290 JERRY_VLA (uint8_t, test_buffer, buffer_size);
291 jerry_length_t read = jerry_arraybuffer_read (arrayb, 0, test_buffer, buffer_size);
292 TEST_ASSERT (read == buffer_size);
293 TEST_ASSERT (test_buffer[0] == new_value);
294
295 for (uint32_t i = 1; i < buffer_size; i++)
296 {
297 TEST_ASSERT (test_buffer[i] == base_value);
298 }
299
300 TEST_ASSERT (jerry_value_is_arraybuffer (arrayb));
301 jerry_release_value (arrayb);
302 }
303
304 /* Test ArrayBuffer external memory map/unmap */
305 {
306 const uint32_t buffer_size = 20;
307 /* cppcheck-suppress variableScope */
308 JERRY_VLA (uint8_t, buffer_p, buffer_size);
309 {
310 jerry_value_t input_buffer = jerry_create_arraybuffer_external (buffer_size, buffer_p, NULL);
311 register_js_value ("input_buffer", input_buffer);
312 jerry_release_value (input_buffer);
313 }
314
315 const jerry_char_t eval_arraybuffer_src[] = TEST_STRING_LITERAL (
316 "var array = new Uint8Array(input_buffer);"
317 "for (var i = 0; i < array.length; i++)"
318 "{"
319 " array[i] = i * 2;"
320 "};"
321 "array.buffer"
322 );
323 jerry_value_t buffer = jerry_eval (eval_arraybuffer_src,
324 sizeof (eval_arraybuffer_src) - 1,
325 JERRY_PARSE_STRICT_MODE);
326
327 TEST_ASSERT (!jerry_value_is_error (buffer));
328 TEST_ASSERT (jerry_value_is_arraybuffer (buffer));
329 TEST_ASSERT (jerry_get_arraybuffer_byte_length (buffer) == 20);
330
331 uint8_t *const data = jerry_get_arraybuffer_pointer (buffer);
332
333 /* test memory read */
334 for (int i = 0; i < 20; i++)
335 {
336 TEST_ASSERT (data[i] == (uint8_t) (i * 2));
337 }
338
339 /* "upload" new data */
340 double sum = 0;
341 for (int i = 0; i < 20; i++)
342 {
343 data[i] = (uint8_t) (i * 3);
344 sum += data[i];
345 }
346
347 const jerry_char_t eval_test_arraybuffer[] = TEST_STRING_LITERAL (
348 "var sum = 0;"
349 "for (var i = 0; i < array.length; i++)"
350 "{"
351 " var expected = i * 3;"
352 " assert(array[i] == expected, 'Array at index ' + i + ' was: ' + array[i] + ' should be: ' + expected);"
353 " sum += array[i]"
354 "};"
355 "sum"
356 );
357 jerry_value_t res = jerry_eval (eval_test_arraybuffer,
358 sizeof (eval_test_arraybuffer) - 1,
359 JERRY_PARSE_STRICT_MODE);
360 TEST_ASSERT (jerry_value_is_number (res));
361 TEST_ASSERT (jerry_get_number_value (res) == sum);
362 jerry_release_value (res);
363
364 jerry_release_value (buffer);
365 }
366
367 /* Test ArrayBuffer detach */
368 {
369 const uint32_t length = 1;
370 jerry_value_t arraybuffer = jerry_create_arraybuffer (length);
371 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
372 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
373 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
374
375 jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer);
376 TEST_ASSERT (!jerry_value_is_error (is_detachable));
377 TEST_ASSERT (!jerry_get_boolean_value (is_detachable));
378
379 jerry_value_t res = jerry_detach_arraybuffer (arraybuffer);
380 TEST_ASSERT (jerry_value_is_error (res));
381
382 jerry_release_value (res);
383 jerry_release_value (arraybuffer);
384 }
385
386 /* Test external ArrayBuffer detach */
387 {
388 uint8_t buf[1];
389 const uint32_t length = 1;
390 jerry_value_t arraybuffer = jerry_create_arraybuffer_external (length, buf, NULL);
391 TEST_ASSERT (!jerry_value_is_error (arraybuffer));
392 TEST_ASSERT (jerry_value_is_arraybuffer (arraybuffer));
393 TEST_ASSERT (jerry_get_arraybuffer_byte_length (arraybuffer) == length);
394
395 jerry_value_t is_detachable = jerry_is_arraybuffer_detachable (arraybuffer);
396 TEST_ASSERT (!jerry_value_is_error (is_detachable));
397 TEST_ASSERT (jerry_get_boolean_value (is_detachable));
398 jerry_release_value (is_detachable);
399
400 jerry_value_t res = jerry_detach_arraybuffer (arraybuffer);
401 TEST_ASSERT (!jerry_value_is_error (res));
402
403 is_detachable = jerry_is_arraybuffer_detachable (arraybuffer);
404 TEST_ASSERT (!jerry_value_is_error (is_detachable));
405 TEST_ASSERT (!jerry_get_boolean_value (is_detachable));
406 jerry_release_value (is_detachable);
407
408 jerry_release_value (res);
409 jerry_release_value (arraybuffer);
410 }
411
412 jerry_cleanup ();
413
414 TEST_ASSERT (callback_called == true);
415
416 return 0;
417 } /* main */
418