2019-12-04 00:57:06 -05:00
|
|
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
2019-12-19 23:36:29 -05:00
|
|
|
|
2019-12-04 00:57:06 -05:00
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
|
|
|
|
|
|
|
use rusty_v8 as v8;
|
2019-12-24 18:31:36 -05:00
|
|
|
use rusty_v8::{new_null, FunctionCallbackInfo, InIsolate, Local, ToLocal};
|
2019-12-26 10:45:55 -05:00
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
2019-12-04 00:57:06 -05:00
|
|
|
use std::sync::Mutex;
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref INIT_LOCK: Mutex<u32> = Mutex::new(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TestGuard {}
|
|
|
|
|
|
|
|
impl Drop for TestGuard {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// TODO shutdown process cleanly.
|
|
|
|
/*
|
|
|
|
*g -= 1;
|
|
|
|
if *g == 0 {
|
|
|
|
unsafe { v8::V8::dispose() };
|
|
|
|
v8::V8::shutdown_platform();
|
|
|
|
}
|
|
|
|
drop(g);
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-05 17:03:18 -05:00
|
|
|
fn setup() -> TestGuard {
|
2019-12-04 00:57:06 -05:00
|
|
|
let mut g = INIT_LOCK.lock().unwrap();
|
|
|
|
*g += 1;
|
|
|
|
if *g == 1 {
|
|
|
|
v8::V8::initialize_platform(v8::platform::new_default_platform());
|
|
|
|
v8::V8::initialize();
|
|
|
|
}
|
|
|
|
drop(g);
|
|
|
|
TestGuard {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn handle_scope_nested() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope1 = hs.enter();
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(scope1);
|
|
|
|
let _scope2 = hs.enter();
|
|
|
|
}
|
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-04 00:57:06 -05:00
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[allow(clippy::float_cmp)]
|
|
|
|
fn handle_scope_numbers() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope1 = hs.enter();
|
2019-12-21 00:08:00 -05:00
|
|
|
let l1 = v8::Integer::new(scope1, -123);
|
|
|
|
let l2 = v8::Integer::new_from_unsigned(scope1, 456);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(scope1);
|
|
|
|
let scope2 = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let l3 = v8::Number::new(scope2, 78.9);
|
2019-12-04 00:57:06 -05:00
|
|
|
assert_eq!(l1.value(), -123);
|
|
|
|
assert_eq!(l2.value(), 456);
|
|
|
|
assert_eq!(l3.value(), 78.9);
|
|
|
|
assert_eq!(v8::Number::value(&l1), -123f64);
|
|
|
|
assert_eq!(v8::Number::value(&l2), 456f64);
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-04 00:57:06 -05:00
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-21 12:17:03 -05:00
|
|
|
#[test]
|
|
|
|
fn global_handles() {
|
|
|
|
let _g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-21 12:17:03 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
|
|
|
let mut g1 = v8::Global::<v8::String>::new();
|
|
|
|
let mut g2 = v8::Global::<v8::Integer>::new();
|
|
|
|
let mut g3 = v8::Global::<v8::Integer>::new();
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut _g4 = v8::Global::<v8::Integer>::new();
|
2019-12-21 12:17:03 -05:00
|
|
|
let g5 = v8::Global::<v8::Script>::new();
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-21 12:17:03 -05:00
|
|
|
let l1 = v8::String::new(scope, "bla").unwrap();
|
|
|
|
let l2 = v8::Integer::new(scope, 123);
|
|
|
|
g1.set(scope, l1);
|
|
|
|
g2.set(scope, l2);
|
|
|
|
g3.set(scope, &g2);
|
2019-12-24 18:31:36 -05:00
|
|
|
_g4 = v8::Global::new_from(scope, l2);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-21 12:17:03 -05:00
|
|
|
assert!(!g1.is_empty());
|
|
|
|
assert_eq!(g1.get(scope).unwrap().to_rust_string_lossy(scope), "bla");
|
|
|
|
assert!(!g2.is_empty());
|
|
|
|
assert_eq!(g2.get(scope).unwrap().value(), 123);
|
|
|
|
assert!(!g3.is_empty());
|
|
|
|
assert_eq!(g3.get(scope).unwrap().value(), 123);
|
2019-12-24 18:31:36 -05:00
|
|
|
assert!(!_g4.is_empty());
|
|
|
|
assert_eq!(_g4.get(scope).unwrap().value(), 123);
|
2019-12-21 12:17:03 -05:00
|
|
|
assert!(g5.is_empty());
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-21 12:17:03 -05:00
|
|
|
g1.reset(&mut locker);
|
|
|
|
assert!(g1.is_empty());
|
|
|
|
g2.reset(&mut locker);
|
|
|
|
assert!(g2.is_empty());
|
|
|
|
g3.reset(&mut locker);
|
|
|
|
assert!(g3.is_empty());
|
2019-12-24 18:31:36 -05:00
|
|
|
_g4.reset(&mut locker);
|
|
|
|
assert!(_g4.is_empty());
|
2019-12-21 12:17:03 -05:00
|
|
|
assert!(g5.is_empty());
|
|
|
|
}
|
|
|
|
|
2019-12-04 02:03:17 -05:00
|
|
|
#[test]
|
|
|
|
fn test_string() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-04 02:03:17 -05:00
|
|
|
let reference = "Hello 🦕 world!";
|
2019-12-20 20:59:56 -05:00
|
|
|
let local = v8::String::new(scope, reference).unwrap();
|
2019-12-05 12:28:20 -05:00
|
|
|
assert_eq!(15, local.length());
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(17, local.utf8_length(scope));
|
|
|
|
assert_eq!(reference, local.to_rust_string_lossy(scope));
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-04 02:03:17 -05:00
|
|
|
}
|
|
|
|
|
2019-12-22 09:05:39 -05:00
|
|
|
#[test]
|
|
|
|
#[allow(clippy::float_cmp)]
|
|
|
|
fn escapable_handle_scope() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-22 09:05:39 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
|
|
|
isolate.enter();
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope1 = hs.enter();
|
2019-12-22 10:43:59 -05:00
|
|
|
// After dropping EscapableHandleScope, we should be able to
|
2019-12-22 09:05:39 -05:00
|
|
|
// read escaped values.
|
|
|
|
let number_val = {
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut hs = v8::EscapableHandleScope::new(scope1);
|
|
|
|
let escapable_scope = hs.enter();
|
2019-12-22 10:43:59 -05:00
|
|
|
let number: Local<v8::Value> =
|
2019-12-24 18:31:36 -05:00
|
|
|
cast(v8::Number::new(escapable_scope, 78.9));
|
2019-12-22 09:05:39 -05:00
|
|
|
escapable_scope.escape(number)
|
|
|
|
};
|
|
|
|
let number: Local<v8::Number> = cast(number_val);
|
|
|
|
assert_eq!(number.value(), 78.9);
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
let string = {
|
|
|
|
let mut hs = v8::EscapableHandleScope::new(scope1);
|
|
|
|
let escapable_scope = hs.enter();
|
|
|
|
let string = v8::String::new(escapable_scope, "Hello 🦕 world!").unwrap();
|
|
|
|
escapable_scope.escape(string)
|
2019-12-22 09:05:39 -05:00
|
|
|
};
|
|
|
|
assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(scope1));
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
let string = {
|
|
|
|
let mut hs = v8::EscapableHandleScope::new(scope1);
|
|
|
|
let escapable_scope = hs.enter();
|
2019-12-22 09:05:39 -05:00
|
|
|
let nested_str_val = {
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut hs = v8::EscapableHandleScope::new(escapable_scope);
|
|
|
|
let nested_escapable_scope = hs.enter();
|
2019-12-22 10:43:59 -05:00
|
|
|
let string =
|
2019-12-24 18:31:36 -05:00
|
|
|
v8::String::new(nested_escapable_scope, "Hello 🦕 world!").unwrap();
|
|
|
|
nested_escapable_scope.escape(string)
|
2019-12-22 09:05:39 -05:00
|
|
|
};
|
|
|
|
escapable_scope.escape(nested_str_val)
|
|
|
|
};
|
|
|
|
assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(scope1));
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-22 09:05:39 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-21 08:50:59 -05:00
|
|
|
#[test]
|
|
|
|
fn array_buffer() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-21 08:50:59 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-21 08:50:59 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let ab = v8::ArrayBuffer::new(scope, 42);
|
|
|
|
assert_eq!(42, ab.byte_length());
|
|
|
|
|
2019-12-21 11:05:51 -05:00
|
|
|
let bs = v8::ArrayBuffer::new_backing_store(scope, 84);
|
|
|
|
assert_eq!(84, bs.byte_length());
|
|
|
|
assert_eq!(false, bs.is_shared());
|
|
|
|
|
2019-12-21 08:50:59 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-21 08:50:59 -05:00
|
|
|
drop(locker);
|
|
|
|
}
|
|
|
|
|
2019-12-25 21:32:22 -05:00
|
|
|
#[test]
|
|
|
|
fn array_buffer_with_shared_backing_store() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
|
|
|
|
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let ab1 = v8::ArrayBuffer::new(scope, 42);
|
|
|
|
assert_eq!(42, ab1.byte_length());
|
|
|
|
|
|
|
|
let bs1 = ab1.get_backing_store();
|
|
|
|
assert_eq!(ab1.byte_length(), bs1.byte_length());
|
|
|
|
assert_eq!(2, v8::SharedRef::use_count(&bs1));
|
|
|
|
|
|
|
|
let bs2 = ab1.get_backing_store();
|
|
|
|
assert_eq!(ab1.byte_length(), bs2.byte_length());
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs1));
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs2));
|
|
|
|
|
|
|
|
let mut bs3 = ab1.get_backing_store();
|
|
|
|
assert_eq!(ab1.byte_length(), bs3.byte_length());
|
|
|
|
assert_eq!(4, v8::SharedRef::use_count(&bs1));
|
|
|
|
assert_eq!(4, v8::SharedRef::use_count(&bs2));
|
|
|
|
assert_eq!(4, v8::SharedRef::use_count(&bs3));
|
|
|
|
|
|
|
|
drop(bs2);
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs1));
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs3));
|
|
|
|
|
|
|
|
drop(bs1);
|
|
|
|
assert_eq!(2, v8::SharedRef::use_count(&bs3));
|
|
|
|
|
|
|
|
let ab2 = v8::ArrayBuffer::new_with_backing_store(scope, &mut bs3);
|
|
|
|
assert_eq!(ab1.byte_length(), ab2.byte_length());
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs3));
|
|
|
|
|
|
|
|
let bs4 = ab2.get_backing_store();
|
|
|
|
assert_eq!(ab2.byte_length(), bs4.byte_length());
|
|
|
|
assert_eq!(4, v8::SharedRef::use_count(&bs4));
|
|
|
|
assert_eq!(4, v8::SharedRef::use_count(&bs3));
|
|
|
|
|
|
|
|
drop(bs3);
|
|
|
|
assert_eq!(3, v8::SharedRef::use_count(&bs4));
|
|
|
|
|
|
|
|
context.exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
fn v8_str<'sc>(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl v8::ToLocal<'sc>,
|
2019-12-20 10:01:45 -05:00
|
|
|
s: &str,
|
|
|
|
) -> v8::Local<'sc, v8::String> {
|
2019-12-24 18:31:36 -05:00
|
|
|
v8::String::new(scope, s).unwrap()
|
2019-12-23 18:09:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn eval<'sc>(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl v8::InIsolate,
|
2019-12-23 18:09:03 -05:00
|
|
|
context: Local<v8::Context>,
|
|
|
|
code: &'static str,
|
|
|
|
) -> Option<Local<'sc, v8::Value>> {
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut hs = v8::EscapableHandleScope::new(scope);
|
|
|
|
let scope = hs.enter();
|
2019-12-23 18:09:03 -05:00
|
|
|
let source = v8_str(scope, code);
|
|
|
|
let mut script =
|
|
|
|
v8::Script::compile(&mut *scope, context, source, None).unwrap();
|
2019-12-24 18:31:36 -05:00
|
|
|
let r = script.run(scope, context);
|
|
|
|
r.map(|v| scope.escape(v))
|
2019-12-19 23:36:29 -05:00
|
|
|
}
|
|
|
|
|
2019-12-20 18:28:08 -05:00
|
|
|
#[test]
|
|
|
|
fn try_catch() {
|
|
|
|
let _g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-20 18:28:08 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 18:28:08 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
{
|
|
|
|
// Error thrown - should be caught.
|
|
|
|
let mut try_catch = v8::TryCatch::new(scope);
|
|
|
|
let tc = try_catch.enter();
|
|
|
|
let result = eval(scope, context, "throw new Error('foo')");
|
|
|
|
assert!(result.is_none());
|
|
|
|
assert!(tc.has_caught());
|
|
|
|
assert!(tc.exception().is_some());
|
|
|
|
assert!(tc.stack_trace(scope, context).is_some());
|
|
|
|
assert!(tc.message().is_some());
|
|
|
|
assert_eq!(
|
|
|
|
tc.message().unwrap().get(scope).to_rust_string_lossy(scope),
|
|
|
|
"Uncaught Error: foo"
|
|
|
|
);
|
|
|
|
};
|
|
|
|
{
|
|
|
|
// No error thrown.
|
|
|
|
let mut try_catch = v8::TryCatch::new(scope);
|
|
|
|
let tc = try_catch.enter();
|
|
|
|
let result = eval(scope, context, "1 + 1");
|
|
|
|
assert!(result.is_some());
|
|
|
|
assert!(!tc.has_caught());
|
|
|
|
assert!(tc.exception().is_none());
|
|
|
|
assert!(tc.stack_trace(scope, context).is_none());
|
|
|
|
assert!(tc.message().is_none());
|
|
|
|
assert!(tc.rethrow().is_none());
|
|
|
|
};
|
|
|
|
{
|
|
|
|
// Rethrow and reset.
|
|
|
|
let mut try_catch_1 = v8::TryCatch::new(scope);
|
|
|
|
let tc1 = try_catch_1.enter();
|
|
|
|
{
|
|
|
|
let mut try_catch_2 = v8::TryCatch::new(scope);
|
|
|
|
let tc2 = try_catch_2.enter();
|
|
|
|
eval(scope, context, "throw 'bar'");
|
|
|
|
assert!(tc2.has_caught());
|
|
|
|
assert!(tc2.rethrow().is_some());
|
|
|
|
tc2.reset();
|
|
|
|
assert!(!tc2.has_caught());
|
|
|
|
}
|
|
|
|
assert!(tc1.has_caught());
|
|
|
|
};
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-23 08:16:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn throw_exception() {
|
|
|
|
let _g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-23 08:16:01 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-23 08:16:01 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
{
|
|
|
|
let mut try_catch = v8::TryCatch::new(scope);
|
|
|
|
let tc = try_catch.enter();
|
|
|
|
isolate.throw_exception(v8_str(scope, "boom").into());
|
|
|
|
assert!(tc.has_caught());
|
|
|
|
assert!(tc
|
|
|
|
.exception()
|
|
|
|
.unwrap()
|
|
|
|
.strict_equals(v8_str(scope, "boom").into()));
|
|
|
|
};
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-20 18:28:08 -05:00
|
|
|
}
|
|
|
|
|
2019-12-04 00:57:06 -05:00
|
|
|
#[test]
|
2019-12-24 16:40:41 -05:00
|
|
|
fn add_message_listener() {
|
2019-12-04 00:57:06 -05:00
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-18 17:17:38 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 32);
|
2019-12-19 21:34:07 -05:00
|
|
|
|
|
|
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
extern "C" fn check_message_0(
|
2019-12-19 23:36:29 -05:00
|
|
|
message: Local<v8::Message>,
|
|
|
|
_exception: Local<v8::Value>,
|
2019-12-19 21:34:07 -05:00
|
|
|
) {
|
|
|
|
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut cbs = v8::CallbackScope::new(message);
|
|
|
|
let scope = cbs.enter();
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(scope);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let message_str = message.get(scope);
|
|
|
|
assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo");
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 21:34:07 -05:00
|
|
|
}
|
|
|
|
isolate.add_message_listener(check_message_0);
|
|
|
|
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
2019-12-19 21:34:07 -05:00
|
|
|
context.enter();
|
2019-12-20 20:59:56 -05:00
|
|
|
let source = v8::String::new(s, "throw 'foo'").unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut script = v8::Script::compile(s, context, source, None).unwrap();
|
|
|
|
assert!(script.run(s, context).is_none());
|
2019-12-19 21:34:07 -05:00
|
|
|
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 21:34:07 -05:00
|
|
|
drop(locker);
|
2019-12-04 00:57:06 -05:00
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-24 16:40:41 -05:00
|
|
|
fn unexpected_module_resolve_callback(
|
|
|
|
_context: v8::Local<v8::Context>,
|
|
|
|
_specifier: v8::Local<v8::String>,
|
|
|
|
_referrer: v8::Local<v8::Module>,
|
|
|
|
) -> *mut v8::Module {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn set_host_initialize_import_meta_object_callback() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-24 16:40:41 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
|
|
|
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
extern "C" fn callback(
|
2019-12-24 18:31:36 -05:00
|
|
|
context: Local<v8::Context>,
|
2019-12-24 16:40:41 -05:00
|
|
|
_module: Local<v8::Module>,
|
|
|
|
meta: Local<v8::Object>,
|
|
|
|
) {
|
|
|
|
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut cbs = v8::CallbackScope::new(context);
|
|
|
|
let mut hs = v8::HandleScope::new(cbs.enter());
|
|
|
|
let scope = hs.enter();
|
|
|
|
let key = v8::String::new(scope, "foo").unwrap();
|
|
|
|
let value = v8::String::new(scope, "bar").unwrap();
|
2019-12-24 16:40:41 -05:00
|
|
|
meta.create_data_property(context, cast(key), value.into());
|
|
|
|
}
|
|
|
|
isolate.set_host_initialize_import_meta_object_callback(callback);
|
|
|
|
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-24 16:40:41 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
|
|
|
context.enter();
|
|
|
|
let source = mock_source(s, "google.com", "import.meta;");
|
|
|
|
let mut module =
|
|
|
|
v8::script_compiler::compile_module(&isolate, source).unwrap();
|
|
|
|
let result =
|
|
|
|
module.instantiate_module(context, unexpected_module_resolve_callback);
|
|
|
|
assert!(result.is_some());
|
2019-12-24 18:31:36 -05:00
|
|
|
let meta = module.evaluate(s, context).unwrap();
|
2019-12-24 16:40:41 -05:00
|
|
|
assert!(meta.is_object());
|
|
|
|
let meta: Local<v8::Object> = cast(meta);
|
2019-12-24 18:31:36 -05:00
|
|
|
let key = v8::String::new(s, "foo").unwrap();
|
|
|
|
let expected = v8::String::new(s, "bar").unwrap();
|
|
|
|
let actual = meta.get(s, context, key.into()).unwrap();
|
2019-12-24 16:40:41 -05:00
|
|
|
assert!(expected.strict_equals(actual));
|
|
|
|
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-24 16:40:41 -05:00
|
|
|
drop(locker);
|
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-04 08:12:27 -05:00
|
|
|
#[test]
|
|
|
|
fn script_compile_and_run() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
2019-12-04 08:12:27 -05:00
|
|
|
context.enter();
|
2019-12-20 20:59:56 -05:00
|
|
|
let source = v8::String::new(s, "'Hello ' + 13 + 'th planet'").unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut script = v8::Script::compile(s, context, source, None).unwrap();
|
|
|
|
source.to_rust_string_lossy(s);
|
|
|
|
let result = script.run(s, context).unwrap();
|
2019-12-04 08:12:27 -05:00
|
|
|
// TODO: safer casts.
|
|
|
|
let result: v8::Local<v8::String> =
|
|
|
|
unsafe { std::mem::transmute_copy(&result) };
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(result.to_rust_string_lossy(s), "Hello 13th planet");
|
2019-12-05 12:55:46 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-04 08:12:27 -05:00
|
|
|
}
|
|
|
|
|
2019-12-18 05:46:36 -05:00
|
|
|
#[test]
|
|
|
|
fn script_origin() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-18 05:46:36 -05:00
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
2019-12-18 05:46:36 -05:00
|
|
|
context.enter();
|
|
|
|
|
2019-12-20 20:59:56 -05:00
|
|
|
let resource_name = v8::String::new(s, "foo.js").unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let resource_line_offset = v8::Integer::new(s, 4);
|
|
|
|
let resource_column_offset = v8::Integer::new(s, 5);
|
|
|
|
let resource_is_shared_cross_origin = v8::new_true(s);
|
|
|
|
let script_id = v8::Integer::new(s, 123);
|
2019-12-20 20:59:56 -05:00
|
|
|
let source_map_url = v8::String::new(s, "source_map_url").unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let resource_is_opaque = v8::new_true(s);
|
|
|
|
let is_wasm = v8::new_false(s);
|
|
|
|
let is_module = v8::new_false(s);
|
2019-12-18 05:46:36 -05:00
|
|
|
|
|
|
|
let script_origin = v8::ScriptOrigin::new(
|
|
|
|
resource_name.into(),
|
|
|
|
resource_line_offset,
|
|
|
|
resource_column_offset,
|
|
|
|
resource_is_shared_cross_origin,
|
|
|
|
script_id,
|
|
|
|
source_map_url.into(),
|
|
|
|
resource_is_opaque,
|
|
|
|
is_wasm,
|
|
|
|
is_module,
|
|
|
|
);
|
|
|
|
|
2019-12-20 20:59:56 -05:00
|
|
|
let source = v8::String::new(s, "1+2").unwrap();
|
2019-12-18 05:46:36 -05:00
|
|
|
let mut script =
|
2019-12-20 10:01:45 -05:00
|
|
|
v8::Script::compile(s, context, source, Some(&script_origin)).unwrap();
|
|
|
|
source.to_rust_string_lossy(s);
|
|
|
|
let _result = script.run(s, context).unwrap();
|
2019-12-18 05:46:36 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-18 05:46:36 -05:00
|
|
|
}
|
|
|
|
|
2019-12-04 00:57:06 -05:00
|
|
|
#[test]
|
|
|
|
fn get_version() {
|
|
|
|
assert!(v8::V8::get_version().len() > 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn set_flags_from_command_line() {
|
|
|
|
let r = v8::V8::set_flags_from_command_line(vec![
|
|
|
|
"binaryname".to_string(),
|
|
|
|
"--log-colour".to_string(),
|
|
|
|
"--should-be-ignored".to_string(),
|
|
|
|
]);
|
|
|
|
assert_eq!(
|
|
|
|
r,
|
|
|
|
vec!["binaryname".to_string(), "--should-be-ignored".to_string()]
|
|
|
|
);
|
|
|
|
}
|
2019-12-04 10:31:54 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn inspector_string_view() {
|
|
|
|
let chars = b"Hello world!";
|
|
|
|
let view = v8::inspector::StringView::from(&chars[..]);
|
|
|
|
|
|
|
|
assert_eq!(chars.len(), view.into_iter().len());
|
|
|
|
assert_eq!(chars.len(), view.len());
|
|
|
|
for (c1, c2) in chars.iter().copied().map(u16::from).zip(&view) {
|
|
|
|
assert_eq!(c1, c2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn inspector_string_buffer() {
|
|
|
|
let chars = b"Hello Venus!";
|
|
|
|
let mut buf = {
|
|
|
|
let src_view = v8::inspector::StringView::from(&chars[..]);
|
|
|
|
v8::inspector::StringBuffer::create(&src_view)
|
|
|
|
};
|
|
|
|
let view = buf.as_mut().unwrap().string();
|
|
|
|
|
|
|
|
assert_eq!(chars.len(), view.into_iter().len());
|
|
|
|
assert_eq!(chars.len(), view.len());
|
|
|
|
for (c1, c2) in chars.iter().copied().map(u16::from).zip(view) {
|
|
|
|
assert_eq!(c1, c2);
|
|
|
|
}
|
|
|
|
}
|
2019-12-05 17:03:18 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_primitives() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let null = v8::new_null(scope);
|
2019-12-06 09:36:34 -05:00
|
|
|
assert!(!null.is_undefined());
|
|
|
|
assert!(null.is_null());
|
|
|
|
assert!(null.is_null_or_undefined());
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
let undefined = v8::new_undefined(scope);
|
2019-12-06 09:36:34 -05:00
|
|
|
assert!(undefined.is_undefined());
|
|
|
|
assert!(!undefined.is_null());
|
|
|
|
assert!(undefined.is_null_or_undefined());
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
let true_ = v8::new_true(scope);
|
2019-12-06 09:36:34 -05:00
|
|
|
assert!(!true_.is_undefined());
|
|
|
|
assert!(!true_.is_null());
|
|
|
|
assert!(!true_.is_null_or_undefined());
|
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
let false_ = v8::new_false(scope);
|
2019-12-06 09:36:34 -05:00
|
|
|
assert!(!false_.is_undefined());
|
|
|
|
assert!(!false_.is_null());
|
|
|
|
assert!(!false_.is_null_or_undefined());
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-05 17:03:18 -05:00
|
|
|
}
|
2019-12-08 20:26:58 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn exception() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-08 20:26:58 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-08 20:26:58 -05:00
|
|
|
isolate.enter();
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-08 20:26:58 -05:00
|
|
|
context.enter();
|
|
|
|
let reference = "This is a test error";
|
2019-12-20 20:59:56 -05:00
|
|
|
let local = v8::String::new(scope, reference).unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
v8::range_error(scope, local);
|
|
|
|
v8::reference_error(scope, local);
|
|
|
|
v8::syntax_error(scope, local);
|
|
|
|
v8::type_error(scope, local);
|
|
|
|
let exception = v8::error(scope, local);
|
|
|
|
let msg = v8::create_message(scope, exception);
|
|
|
|
let msg_string = msg.get(scope);
|
|
|
|
let rust_msg_string = msg_string.to_rust_string_lossy(scope);
|
2019-12-09 19:14:07 -05:00
|
|
|
assert_eq!(
|
|
|
|
"Uncaught Error: This is a test error".to_string(),
|
|
|
|
rust_msg_string
|
|
|
|
);
|
2019-12-20 10:01:45 -05:00
|
|
|
assert!(v8::get_stack_trace(scope, exception).is_none());
|
2019-12-08 20:26:58 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-08 20:26:58 -05:00
|
|
|
isolate.exit();
|
|
|
|
}
|
2019-12-09 17:11:31 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn json() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
2019-12-09 17:11:31 -05:00
|
|
|
context.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let json_string = v8_str(s, "{\"a\": 1, \"b\": 2}");
|
2019-12-20 08:47:20 -05:00
|
|
|
let maybe_value = v8::json::parse(context, json_string);
|
2019-12-09 17:11:31 -05:00
|
|
|
assert!(maybe_value.is_some());
|
|
|
|
let value = maybe_value.unwrap();
|
2019-12-20 08:47:20 -05:00
|
|
|
let maybe_stringified = v8::json::stringify(context, value);
|
2019-12-09 17:11:31 -05:00
|
|
|
assert!(maybe_stringified.is_some());
|
|
|
|
let stringified = maybe_stringified.unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let rust_str = stringified.to_rust_string_lossy(s);
|
2019-12-09 17:11:31 -05:00
|
|
|
assert_eq!("{\"a\":1,\"b\":2}".to_string(), rust_str);
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-09 17:11:31 -05:00
|
|
|
}
|
2019-12-09 19:14:07 -05:00
|
|
|
|
|
|
|
// TODO Safer casts https://github.com/denoland/rusty_v8/issues/51
|
|
|
|
fn cast<U, T>(local: v8::Local<T>) -> v8::Local<U> {
|
|
|
|
let cast_local: v8::Local<U> = unsafe { std::mem::transmute_copy(&local) };
|
|
|
|
cast_local
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn object() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-09 19:14:07 -05:00
|
|
|
context.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let null: v8::Local<v8::Value> = new_null(scope).into();
|
2019-12-20 20:59:56 -05:00
|
|
|
let s1 = v8::String::new(scope, "a").unwrap();
|
|
|
|
let s2 = v8::String::new(scope, "b").unwrap();
|
2019-12-09 19:14:07 -05:00
|
|
|
let name1: Local<v8::Name> = cast(s1);
|
|
|
|
let name2: Local<v8::Name> = cast(s2);
|
|
|
|
let names = vec![name1, name2];
|
2019-12-20 10:01:45 -05:00
|
|
|
let v1: v8::Local<v8::Value> = v8::Number::new(scope, 1.0).into();
|
|
|
|
let v2: v8::Local<v8::Value> = v8::Number::new(scope, 2.0).into();
|
2019-12-09 19:14:07 -05:00
|
|
|
let values = vec![v1, v2];
|
2019-12-20 10:01:45 -05:00
|
|
|
let object = v8::Object::new(scope, null, names, values, 2);
|
2019-12-09 19:14:07 -05:00
|
|
|
assert!(!object.is_null_or_undefined());
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-09 19:14:07 -05:00
|
|
|
}
|
2019-12-10 22:43:22 -05:00
|
|
|
|
2019-12-24 16:10:40 -05:00
|
|
|
#[test]
|
|
|
|
fn create_data_property() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-24 16:10:40 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-24 16:10:40 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
eval(scope, context, "var a = {};");
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
let key = v8_str(scope, "a");
|
2019-12-24 16:10:40 -05:00
|
|
|
let obj = context
|
2019-12-24 18:31:36 -05:00
|
|
|
.global(scope)
|
|
|
|
.get(scope, context, key.into())
|
2019-12-24 16:10:40 -05:00
|
|
|
.unwrap();
|
|
|
|
assert!(obj.is_object());
|
|
|
|
let obj: Local<v8::Object> = cast(obj);
|
|
|
|
let key = v8_str(scope, "foo");
|
|
|
|
let value = v8_str(scope, "bar");
|
|
|
|
assert_eq!(
|
|
|
|
obj.create_data_property(context, cast(key), cast(value)),
|
|
|
|
v8::MaybeBool::JustTrue
|
|
|
|
);
|
2019-12-24 18:31:36 -05:00
|
|
|
let actual = obj.get(scope, context, cast(key)).unwrap();
|
2019-12-24 16:10:40 -05:00
|
|
|
assert!(value.strict_equals(actual));
|
|
|
|
|
2019-12-26 14:38:16 -05:00
|
|
|
let key2 = v8_str(scope, "foo2");
|
|
|
|
assert_eq!(
|
|
|
|
obj.set(context, cast(key2), cast(value)),
|
|
|
|
v8::MaybeBool::JustTrue
|
|
|
|
);
|
|
|
|
let actual = obj.get(scope, context, cast(key2)).unwrap();
|
|
|
|
assert!(value.strict_equals(actual));
|
|
|
|
|
2019-12-24 16:10:40 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-24 16:10:40 -05:00
|
|
|
drop(locker);
|
|
|
|
}
|
|
|
|
|
2019-12-13 20:18:30 -05:00
|
|
|
#[test]
|
|
|
|
fn promise_resolved() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
context.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let maybe_resolver = v8::PromiseResolver::new(scope, context);
|
2019-12-13 20:18:30 -05:00
|
|
|
assert!(maybe_resolver.is_some());
|
|
|
|
let mut resolver = maybe_resolver.unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut promise = resolver.get_promise(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
assert!(!promise.has_handler());
|
|
|
|
assert_eq!(promise.state(), v8::PromiseState::Pending);
|
2019-12-20 20:59:56 -05:00
|
|
|
let str = v8::String::new(scope, "test").unwrap();
|
2019-12-13 20:18:30 -05:00
|
|
|
let value: Local<v8::Value> = cast(str);
|
|
|
|
resolver.resolve(context, value);
|
|
|
|
assert_eq!(promise.state(), v8::PromiseState::Fulfilled);
|
2019-12-20 10:01:45 -05:00
|
|
|
let result = promise.result(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
let result_str: v8::Local<v8::String> = cast(result);
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
|
2019-12-13 20:18:30 -05:00
|
|
|
// Resolve again with different value, since promise is already in `Fulfilled` state
|
|
|
|
// it should be ignored.
|
2019-12-20 20:59:56 -05:00
|
|
|
let str = v8::String::new(scope, "test2").unwrap();
|
2019-12-13 20:18:30 -05:00
|
|
|
let value: Local<v8::Value> = cast(str);
|
|
|
|
resolver.resolve(context, value);
|
2019-12-20 10:01:45 -05:00
|
|
|
let result = promise.result(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
let result_str: v8::Local<v8::String> = cast(result);
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
|
2019-12-13 20:18:30 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-13 20:18:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn promise_rejected() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
context.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let maybe_resolver = v8::PromiseResolver::new(scope, context);
|
2019-12-13 20:18:30 -05:00
|
|
|
assert!(maybe_resolver.is_some());
|
|
|
|
let mut resolver = maybe_resolver.unwrap();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut promise = resolver.get_promise(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
assert!(!promise.has_handler());
|
|
|
|
assert_eq!(promise.state(), v8::PromiseState::Pending);
|
2019-12-20 20:59:56 -05:00
|
|
|
let str = v8::String::new(scope, "test").unwrap();
|
2019-12-13 20:18:30 -05:00
|
|
|
let value: Local<v8::Value> = cast(str);
|
|
|
|
let rejected = resolver.reject(context, value);
|
2019-12-18 09:05:33 -05:00
|
|
|
assert!(rejected.unwrap());
|
2019-12-13 20:18:30 -05:00
|
|
|
assert_eq!(promise.state(), v8::PromiseState::Rejected);
|
2019-12-20 10:01:45 -05:00
|
|
|
let result = promise.result(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
let result_str: v8::Local<v8::String> = cast(result);
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
|
2019-12-13 20:18:30 -05:00
|
|
|
// Reject again with different value, since promise is already in `Rejected` state
|
|
|
|
// it should be ignored.
|
2019-12-20 20:59:56 -05:00
|
|
|
let str = v8::String::new(scope, "test2").unwrap();
|
2019-12-13 20:18:30 -05:00
|
|
|
let value: Local<v8::Value> = cast(str);
|
|
|
|
resolver.reject(context, value);
|
2019-12-20 10:01:45 -05:00
|
|
|
let result = promise.result(scope);
|
2019-12-13 20:18:30 -05:00
|
|
|
let result_str: v8::Local<v8::String> = cast(result);
|
2019-12-20 10:01:45 -05:00
|
|
|
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
|
2019-12-13 20:18:30 -05:00
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-13 20:18:30 -05:00
|
|
|
}
|
|
|
|
|
2019-12-10 22:43:22 -05:00
|
|
|
#[test]
|
|
|
|
fn function() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 19:15:52 -05:00
|
|
|
let isolate = v8::Isolate::new(params);
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-26 10:45:55 -05:00
|
|
|
|
|
|
|
extern "C" fn fn_callback(info: &FunctionCallbackInfo) {
|
|
|
|
assert_eq!(info.length(), 0);
|
|
|
|
{
|
|
|
|
let rv = &mut info.get_return_value();
|
|
|
|
#[allow(mutable_transmutes)]
|
|
|
|
#[allow(clippy::transmute_ptr_to_ptr)]
|
|
|
|
let info: &mut FunctionCallbackInfo =
|
|
|
|
unsafe { std::mem::transmute(info) };
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(info);
|
|
|
|
let scope = hs.enter();
|
|
|
|
let s = v8::String::new(scope, "Hello callback!").unwrap();
|
|
|
|
let value: Local<v8::Value> = s.into();
|
|
|
|
let rv_value = rv.get(scope);
|
|
|
|
assert!(rv_value.is_undefined());
|
|
|
|
rv.set(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-10 22:43:22 -05:00
|
|
|
context.enter();
|
2019-12-24 18:31:36 -05:00
|
|
|
let global = context.global(scope);
|
2019-12-13 21:40:54 -05:00
|
|
|
let recv: Local<v8::Value> = global.into();
|
2019-12-10 22:43:22 -05:00
|
|
|
// create function using template
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut fn_template = v8::FunctionTemplate::new(scope, fn_callback);
|
2019-12-10 22:43:22 -05:00
|
|
|
let mut function = fn_template
|
2019-12-20 10:01:45 -05:00
|
|
|
.get_function(scope, context)
|
2019-12-10 22:43:22 -05:00
|
|
|
.expect("Unable to create function");
|
2019-12-20 10:01:45 -05:00
|
|
|
let _value =
|
|
|
|
v8::Function::call(&mut *function, scope, context, recv, 0, vec![]);
|
2019-12-10 22:43:22 -05:00
|
|
|
// create function without a template
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut function = v8::Function::new(scope, context, fn_callback)
|
2019-12-19 08:13:33 -05:00
|
|
|
.expect("Unable to create function");
|
2019-12-10 22:43:22 -05:00
|
|
|
let maybe_value =
|
2019-12-20 10:01:45 -05:00
|
|
|
v8::Function::call(&mut *function, scope, context, recv, 0, vec![]);
|
2019-12-10 22:43:22 -05:00
|
|
|
let value = maybe_value.unwrap();
|
|
|
|
let value_str: v8::Local<v8::String> = cast(value);
|
2019-12-20 10:01:45 -05:00
|
|
|
let rust_str = value_str.to_rust_string_lossy(scope);
|
2019-12-10 22:43:22 -05:00
|
|
|
assert_eq!(rust_str, "Hello callback!".to_string());
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-10 22:43:22 -05:00
|
|
|
}
|
2019-12-19 08:13:33 -05:00
|
|
|
|
|
|
|
extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) {
|
|
|
|
let event = msg.get_event();
|
|
|
|
assert_eq!(event, v8::PromiseRejectEvent::PromiseRejectWithNoHandler);
|
|
|
|
let mut promise = msg.get_promise();
|
|
|
|
assert_eq!(promise.state(), v8::PromiseState::Rejected);
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut promise_obj: v8::Local<v8::Object> = cast(promise);
|
2019-12-19 08:13:33 -05:00
|
|
|
let isolate = promise_obj.get_isolate();
|
|
|
|
let value = msg.get_value();
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-19 08:13:33 -05:00
|
|
|
let value_str: v8::Local<v8::String> = cast(value);
|
2019-12-20 10:01:45 -05:00
|
|
|
let rust_str = value_str.to_rust_string_lossy(scope);
|
2019-12-19 08:13:33 -05:00
|
|
|
assert_eq!(rust_str, "promise rejected".to_string());
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-19 08:13:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn set_promise_reject_callback() {
|
|
|
|
setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-19 08:13:33 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.set_promise_reject_callback(promise_reject_callback);
|
|
|
|
isolate.enter();
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-19 08:13:33 -05:00
|
|
|
context.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut resolver = v8::PromiseResolver::new(scope, context).unwrap();
|
2019-12-20 20:59:56 -05:00
|
|
|
let str_ = v8::String::new(scope, "promise rejected").unwrap();
|
2019-12-19 08:13:33 -05:00
|
|
|
let value: Local<v8::Value> = cast(str_);
|
|
|
|
resolver.reject(context, value);
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-19 16:58:39 -05:00
|
|
|
drop(locker);
|
2019-12-19 08:13:33 -05:00
|
|
|
isolate.exit();
|
|
|
|
}
|
2019-12-20 14:54:20 -05:00
|
|
|
|
2019-12-20 10:01:45 -05:00
|
|
|
fn mock_script_origin<'sc>(
|
2019-12-24 18:31:36 -05:00
|
|
|
scope: &mut impl v8::ToLocal<'sc>,
|
2019-12-23 18:09:03 -05:00
|
|
|
resource_name_: &str,
|
2019-12-20 10:01:45 -05:00
|
|
|
) -> v8::ScriptOrigin<'sc> {
|
2019-12-24 18:31:36 -05:00
|
|
|
let resource_name = v8_str(scope, resource_name_);
|
|
|
|
let resource_line_offset = v8::Integer::new(scope, 0);
|
|
|
|
let resource_column_offset = v8::Integer::new(scope, 0);
|
|
|
|
let resource_is_shared_cross_origin = v8::new_true(scope);
|
|
|
|
let script_id = v8::Integer::new(scope, 123);
|
|
|
|
let source_map_url = v8_str(scope, "source_map_url");
|
|
|
|
let resource_is_opaque = v8::new_true(scope);
|
|
|
|
let is_wasm = v8::new_false(scope);
|
|
|
|
let is_module = v8::new_true(scope);
|
2019-12-20 14:54:20 -05:00
|
|
|
v8::ScriptOrigin::new(
|
|
|
|
resource_name.into(),
|
|
|
|
resource_line_offset,
|
|
|
|
resource_column_offset,
|
|
|
|
resource_is_shared_cross_origin,
|
|
|
|
script_id,
|
|
|
|
source_map_url.into(),
|
|
|
|
resource_is_opaque,
|
|
|
|
is_wasm,
|
|
|
|
is_module,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
fn mock_source<'sc>(
|
|
|
|
scope: &mut impl ToLocal<'sc>,
|
2019-12-24 16:40:41 -05:00
|
|
|
resource_name: &str,
|
|
|
|
source: &str,
|
|
|
|
) -> v8::script_compiler::Source {
|
2019-12-24 18:31:36 -05:00
|
|
|
let source_str = v8_str(scope, source);
|
|
|
|
let script_origin = mock_script_origin(scope, resource_name);
|
|
|
|
v8::script_compiler::Source::new(source_str, &script_origin)
|
2019-12-24 16:40:41 -05:00
|
|
|
}
|
|
|
|
|
2019-12-20 14:54:20 -05:00
|
|
|
#[test]
|
|
|
|
fn script_compiler_source() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-20 14:54:20 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.set_promise_reject_callback(promise_reject_callback);
|
|
|
|
isolate.enter();
|
2019-12-21 00:08:00 -05:00
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-20 10:01:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
2019-12-20 14:54:20 -05:00
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let source = "1+2";
|
2019-12-23 18:09:03 -05:00
|
|
|
let script_origin = mock_script_origin(scope, "foo.js");
|
2019-12-20 10:01:45 -05:00
|
|
|
let source =
|
|
|
|
v8::script_compiler::Source::new(v8_str(scope, source), &script_origin);
|
2019-12-20 14:54:20 -05:00
|
|
|
|
2019-12-23 20:23:55 -05:00
|
|
|
let result = v8::script_compiler::compile_module(&isolate, source);
|
2019-12-20 14:54:20 -05:00
|
|
|
assert!(result.is_some());
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-20 14:54:20 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-21 06:38:26 -05:00
|
|
|
|
2019-12-23 07:12:52 -05:00
|
|
|
#[test]
|
|
|
|
fn module_instantiation_failures1() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-23 07:12:52 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-23 07:12:52 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let source_text = v8_str(
|
|
|
|
scope,
|
|
|
|
"import './foo.js';\n\
|
|
|
|
export {} from './bar.js';",
|
|
|
|
);
|
2019-12-23 18:09:03 -05:00
|
|
|
let origin = mock_script_origin(scope, "foo.js");
|
2019-12-23 07:12:52 -05:00
|
|
|
let source = v8::script_compiler::Source::new(source_text, &origin);
|
|
|
|
|
2019-12-23 20:23:55 -05:00
|
|
|
let mut module =
|
|
|
|
v8::script_compiler::compile_module(&isolate, source).unwrap();
|
2019-12-23 07:12:52 -05:00
|
|
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
|
|
|
assert_eq!(2, module.get_module_requests_length());
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
"./foo.js",
|
|
|
|
module.get_module_request(0).to_rust_string_lossy(scope)
|
|
|
|
);
|
|
|
|
let loc = module.get_module_request_location(0);
|
|
|
|
assert_eq!(0, loc.get_line_number());
|
|
|
|
assert_eq!(7, loc.get_column_number());
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
"./bar.js",
|
|
|
|
module.get_module_request(1).to_rust_string_lossy(scope)
|
|
|
|
);
|
|
|
|
let loc = module.get_module_request_location(1);
|
|
|
|
assert_eq!(1, loc.get_line_number());
|
|
|
|
assert_eq!(15, loc.get_column_number());
|
|
|
|
|
2019-12-23 18:09:03 -05:00
|
|
|
// Instantiation should fail.
|
|
|
|
{
|
|
|
|
let mut try_catch = v8::TryCatch::new(scope);
|
|
|
|
let tc = try_catch.enter();
|
|
|
|
fn resolve_callback(
|
2019-12-24 18:31:36 -05:00
|
|
|
context: v8::Local<v8::Context>,
|
2019-12-23 18:09:03 -05:00
|
|
|
_specifier: v8::Local<v8::String>,
|
|
|
|
_referrer: v8::Local<v8::Module>,
|
2019-12-23 20:23:55 -05:00
|
|
|
) -> *mut v8::Module {
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut cbs = v8::CallbackScope::new(context);
|
|
|
|
let mut hs = v8::HandleScope::new(cbs.enter());
|
|
|
|
let scope = hs.enter();
|
|
|
|
let e = v8_str(scope, "boom");
|
|
|
|
scope.isolate().throw_exception(e.into());
|
2019-12-23 20:23:55 -05:00
|
|
|
std::ptr::null_mut()
|
2019-12-23 18:09:03 -05:00
|
|
|
}
|
|
|
|
let result = module.instantiate_module(context, resolve_callback);
|
|
|
|
assert!(result.is_none());
|
|
|
|
assert!(tc.has_caught());
|
|
|
|
assert!(tc
|
|
|
|
.exception()
|
|
|
|
.unwrap()
|
|
|
|
.strict_equals(v8_str(scope, "boom").into()));
|
|
|
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
|
|
|
}
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-23 18:09:03 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-23 20:23:55 -05:00
|
|
|
fn compile_specifier_as_module_resolve_callback(
|
2019-12-24 18:31:36 -05:00
|
|
|
context: v8::Local<v8::Context>,
|
2019-12-23 20:23:55 -05:00
|
|
|
specifier: v8::Local<v8::String>,
|
|
|
|
_referrer: v8::Local<v8::Module>,
|
|
|
|
) -> *mut v8::Module {
|
2019-12-24 18:31:36 -05:00
|
|
|
let mut cbs = v8::CallbackScope::new(context);
|
|
|
|
let mut hs = v8::EscapableHandleScope::new(cbs.enter());
|
|
|
|
let scope = hs.enter();
|
|
|
|
let origin = mock_script_origin(scope, "module.js");
|
2019-12-23 20:23:55 -05:00
|
|
|
let source = v8::script_compiler::Source::new(specifier, &origin);
|
2019-12-24 18:31:36 -05:00
|
|
|
let module =
|
|
|
|
v8::script_compiler::compile_module(scope.isolate(), source).unwrap();
|
|
|
|
&mut *cast(scope.escape(module))
|
2019-12-23 20:23:55 -05:00
|
|
|
}
|
|
|
|
|
2019-12-23 18:09:03 -05:00
|
|
|
#[test]
|
|
|
|
fn module_evaluation() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-23 18:09:03 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-23 18:09:03 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let source_text = v8_str(
|
|
|
|
scope,
|
|
|
|
"import 'Object.expando = 5';\n\
|
|
|
|
import 'Object.expando *= 2';",
|
|
|
|
);
|
|
|
|
let origin = mock_script_origin(scope, "foo.js");
|
|
|
|
let source = v8::script_compiler::Source::new(source_text, &origin);
|
|
|
|
|
2019-12-23 20:23:55 -05:00
|
|
|
let mut module =
|
|
|
|
v8::script_compiler::compile_module(&isolate, source).unwrap();
|
2019-12-23 18:09:03 -05:00
|
|
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
|
|
|
|
2019-12-23 20:23:55 -05:00
|
|
|
let result = module.instantiate_module(
|
|
|
|
context,
|
|
|
|
compile_specifier_as_module_resolve_callback,
|
|
|
|
);
|
2019-12-23 18:09:03 -05:00
|
|
|
assert!(result.unwrap());
|
|
|
|
assert_eq!(v8::ModuleStatus::Instantiated, module.get_status());
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
let result = module.evaluate(scope, context);
|
2019-12-23 18:09:03 -05:00
|
|
|
assert!(result.is_some());
|
|
|
|
assert_eq!(v8::ModuleStatus::Evaluated, module.get_status());
|
|
|
|
|
|
|
|
let result = eval(scope, context, "Object.expando").unwrap();
|
|
|
|
assert!(result.is_number());
|
|
|
|
let expected = v8::Number::new(scope, 10.);
|
|
|
|
assert!(result.strict_equals(expected.into()));
|
2019-12-23 07:12:52 -05:00
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-23 07:12:52 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
|
|
|
|
2019-12-21 06:38:26 -05:00
|
|
|
#[test]
|
|
|
|
fn primitive_array() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-21 06:38:26 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-21 06:38:26 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let length = 3;
|
|
|
|
let array = v8::PrimitiveArray::new(scope, length);
|
|
|
|
assert_eq!(length, array.length());
|
|
|
|
|
|
|
|
for i in 0..length {
|
|
|
|
let item = array.get(scope, i);
|
|
|
|
assert!(item.is_undefined());
|
|
|
|
}
|
|
|
|
|
|
|
|
let string = v8_str(scope, "test");
|
|
|
|
array.set(scope, 1, cast(string));
|
|
|
|
assert!(array.get(scope, 0).is_undefined());
|
|
|
|
assert!(array.get(scope, 1).is_string());
|
|
|
|
|
|
|
|
let num = v8::Number::new(scope, 0.42);
|
|
|
|
array.set(scope, 2, cast(num));
|
|
|
|
assert!(array.get(scope, 0).is_undefined());
|
|
|
|
assert!(array.get(scope, 1).is_string());
|
|
|
|
assert!(array.get(scope, 2).is_number());
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-21 06:38:26 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-22 10:22:44 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn ui() {
|
|
|
|
// This environment variable tells build.rs that we're running trybuild tests,
|
|
|
|
// so it won't rebuild V8.
|
|
|
|
std::env::set_var("DENO_TRYBUILD", "1");
|
|
|
|
|
|
|
|
let t = trybuild::TestCases::new();
|
|
|
|
t.compile_fail("tests/compile_fail/*.rs");
|
|
|
|
}
|
2019-12-23 07:32:45 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn equality() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-23 07:32:45 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-23 07:32:45 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
assert!(v8_str(scope, "a").strict_equals(v8_str(scope, "a").into()));
|
|
|
|
assert!(!v8_str(scope, "a").strict_equals(v8_str(scope, "b").into()));
|
|
|
|
|
|
|
|
assert!(v8_str(scope, "a").same_value(v8_str(scope, "a").into()));
|
|
|
|
assert!(!v8_str(scope, "a").same_value(v8_str(scope, "b").into()));
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-23 07:32:45 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-24 05:50:30 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn array_buffer_view() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-24 05:50:30 -05:00
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
2019-12-24 05:50:30 -05:00
|
|
|
let mut context = v8::Context::new(s);
|
|
|
|
context.enter();
|
|
|
|
let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap();
|
|
|
|
let mut script = v8::Script::compile(s, context, source, None).unwrap();
|
|
|
|
source.to_rust_string_lossy(s);
|
|
|
|
let result = script.run(s, context).unwrap();
|
|
|
|
// TODO: safer casts.
|
|
|
|
let result: v8::Local<v8::array_buffer_view::ArrayBufferView> =
|
2019-12-25 20:37:25 -05:00
|
|
|
cast(result);
|
2019-12-24 05:50:30 -05:00
|
|
|
assert_eq!(result.byte_length(), 4);
|
|
|
|
assert_eq!(result.byte_offset(), 0);
|
|
|
|
let mut dest = [0; 4];
|
|
|
|
let copy_bytes = result.copy_contents(&mut dest);
|
|
|
|
assert_eq!(copy_bytes, 4);
|
|
|
|
assert_eq!(dest, [23, 23, 23, 23]);
|
|
|
|
let maybe_ab = result.buffer();
|
|
|
|
assert!(maybe_ab.is_some());
|
|
|
|
let ab = maybe_ab.unwrap();
|
|
|
|
assert_eq!(ab.byte_length(), 4);
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-24 05:50:30 -05:00
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-24 08:03:32 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn snapshot_creator() {
|
|
|
|
let g = setup();
|
|
|
|
// First we create the snapshot, there is a single global variable 'a' set to
|
|
|
|
// the value 3.
|
|
|
|
let mut startup_data = {
|
|
|
|
let mut snapshot_creator = v8::SnapshotCreator::default();
|
|
|
|
let isolate = snapshot_creator.get_isolate();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-24 08:03:32 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let source = v8::String::new(scope, "a = 1 + 2").unwrap();
|
|
|
|
let mut script =
|
|
|
|
v8::Script::compile(scope, context, source, None).unwrap();
|
|
|
|
script.run(scope, context).unwrap();
|
|
|
|
|
|
|
|
snapshot_creator.set_default_context(context);
|
|
|
|
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-24 08:03:32 -05:00
|
|
|
|
2019-12-25 08:14:55 -05:00
|
|
|
snapshot_creator
|
|
|
|
.create_blob(v8::FunctionCodeHandling::Clear)
|
|
|
|
.unwrap()
|
2019-12-24 08:03:32 -05:00
|
|
|
};
|
2019-12-25 08:14:55 -05:00
|
|
|
assert!(startup_data.len() > 0);
|
2019-12-24 08:03:32 -05:00
|
|
|
// Now we try to load up the snapshot and check that 'a' has the correct
|
|
|
|
// value.
|
|
|
|
{
|
|
|
|
let mut params = v8::Isolate::create_params();
|
2019-12-25 10:56:27 -05:00
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
2019-12-24 08:03:32 -05:00
|
|
|
params.set_snapshot_blob(&mut startup_data);
|
|
|
|
let isolate = v8::Isolate::new(params);
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let scope = hs.enter();
|
2019-12-24 08:03:32 -05:00
|
|
|
let mut context = v8::Context::new(scope);
|
|
|
|
context.enter();
|
|
|
|
let source = v8::String::new(scope, "a === 3").unwrap();
|
|
|
|
let mut script =
|
|
|
|
v8::Script::compile(scope, context, source, None).unwrap();
|
|
|
|
let result = script.run(scope, context).unwrap();
|
|
|
|
let true_val: Local<v8::Value> = cast(v8::new_true(scope));
|
|
|
|
assert!(result.same_value(true_val));
|
|
|
|
context.exit();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
2019-12-25 10:56:27 -05:00
|
|
|
// TODO(ry) WARNING! startup_data needs to be kept alive as long the isolate
|
|
|
|
// using it. See note in CreateParams::set_snapshot_blob
|
|
|
|
drop(startup_data);
|
2019-12-24 08:03:32 -05:00
|
|
|
}
|
2019-12-25 10:56:27 -05:00
|
|
|
|
2019-12-24 08:03:32 -05:00
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-25 20:37:25 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn uint8_array() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
|
|
|
let mut context = v8::Context::new(s);
|
|
|
|
context.enter();
|
|
|
|
let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap();
|
|
|
|
let mut script = v8::Script::compile(s, context, source, None).unwrap();
|
|
|
|
source.to_rust_string_lossy(s);
|
|
|
|
let result = script.run(s, context).unwrap();
|
|
|
|
// TODO: safer casts.
|
|
|
|
let result: v8::Local<v8::array_buffer_view::ArrayBufferView> =
|
|
|
|
cast(result);
|
|
|
|
assert_eq!(result.byte_length(), 4);
|
|
|
|
assert_eq!(result.byte_offset(), 0);
|
|
|
|
let mut dest = [0; 4];
|
|
|
|
let copy_bytes = result.copy_contents(&mut dest);
|
|
|
|
assert_eq!(copy_bytes, 4);
|
|
|
|
assert_eq!(dest, [23, 23, 23, 23]);
|
|
|
|
let maybe_ab = result.buffer();
|
|
|
|
assert!(maybe_ab.is_some());
|
|
|
|
let ab = maybe_ab.unwrap();
|
|
|
|
let uint8_array = v8::Uint8Array::new(ab, 0, 0);
|
|
|
|
assert!(uint8_array.is_some());
|
|
|
|
context.exit();
|
|
|
|
}
|
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|
2019-12-26 10:45:55 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dynamic_import() {
|
|
|
|
let g = setup();
|
|
|
|
let mut params = v8::Isolate::create_params();
|
|
|
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
|
|
|
let mut isolate = v8::Isolate::new(params);
|
|
|
|
|
|
|
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
extern "C" fn dynamic_import_cb(
|
|
|
|
context: v8::Local<v8::Context>,
|
|
|
|
_referrer: v8::Local<v8::ScriptOrModule>,
|
|
|
|
specifier: v8::Local<v8::String>,
|
|
|
|
) -> *mut v8::Promise {
|
|
|
|
let mut cbs = v8::CallbackScope::new(context);
|
|
|
|
let mut hs = v8::HandleScope::new(cbs.enter());
|
|
|
|
let scope = hs.enter();
|
|
|
|
assert!(specifier.strict_equals(v8_str(scope, "bar.js").into()));
|
|
|
|
let e = v8_str(scope, "boom");
|
|
|
|
scope.isolate().throw_exception(e.into());
|
|
|
|
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
|
|
|
|
std::ptr::null_mut()
|
|
|
|
}
|
|
|
|
isolate.set_host_import_module_dynamically_callback(dynamic_import_cb);
|
|
|
|
|
|
|
|
isolate.enter();
|
|
|
|
let mut locker = v8::Locker::new(&isolate);
|
|
|
|
{
|
|
|
|
let mut hs = v8::HandleScope::new(&mut locker);
|
|
|
|
let s = hs.enter();
|
|
|
|
let mut context = v8::Context::new(s);
|
|
|
|
context.enter();
|
|
|
|
|
|
|
|
let result = eval(
|
|
|
|
s,
|
|
|
|
context,
|
|
|
|
"(async function () {\n\
|
|
|
|
let x = await import('bar.js');\n\
|
|
|
|
})();",
|
|
|
|
);
|
|
|
|
assert!(result.is_some());
|
|
|
|
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
|
|
|
|
|
|
|
|
context.exit();
|
|
|
|
}
|
|
|
|
drop(locker);
|
|
|
|
isolate.exit();
|
|
|
|
drop(g);
|
|
|
|
}
|