• 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 "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