style: 减少自动格式化换行
This commit is contained in:
@@ -37,10 +37,7 @@ fn eval_val(source: &str) -> (Vm, Result<JsValue, String>) {
|
||||
|
||||
fn to_str(vm: &Vm, val: JsValue) -> String {
|
||||
if val.is_string() {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
} else {
|
||||
format!("{}", val)
|
||||
}
|
||||
|
||||
@@ -24,11 +24,7 @@ fn bench_1m_property_reads() {
|
||||
}
|
||||
let elapsed = start.elapsed();
|
||||
let ns_per = elapsed.as_nanos() as f64 / N as f64;
|
||||
println!(
|
||||
"1M IC property reads: {:.2}ms ({:.0} ns/read)",
|
||||
elapsed.as_secs_f64() * 1000.0,
|
||||
ns_per
|
||||
);
|
||||
println!("1M IC property reads: {:.2}ms ({:.0} ns/read)", elapsed.as_secs_f64() * 1000.0, ns_per);
|
||||
if cfg!(debug_assertions) {
|
||||
println!(" (debug build -- skipping timing assertion)");
|
||||
} else {
|
||||
|
||||
@@ -5,11 +5,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(source: &str) -> Result<(Vm, JsValue), String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
let mut vm = Vm::new();
|
||||
let result = vm.run(&module)?;
|
||||
Ok((vm, result))
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
use oxide_vm::builtins::boolean::{
|
||||
boolean_constructor, boolean_prototype_to_string, boolean_prototype_value_of,
|
||||
};
|
||||
use oxide_vm::builtins::boolean::{boolean_constructor, boolean_prototype_to_string, boolean_prototype_value_of};
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn str_val(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// -- direct native fn tests --
|
||||
|
||||
@@ -3,19 +3,13 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<oxide_types::value::JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn str_val(vm: &Vm, val: oxide_types::value::JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// -- static methods --
|
||||
@@ -92,11 +86,7 @@ fn date_set_time() {
|
||||
#[test]
|
||||
fn date_set_full_year() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var d = new Date(2020, 0, 1); d.setFullYear(2025); d.getFullYear()",
|
||||
)
|
||||
.unwrap();
|
||||
let r = eval(&mut vm, "var d = new Date(2020, 0, 1); d.setFullYear(2025); d.getFullYear()").unwrap();
|
||||
assert_eq!(r.as_double(), 2025.0);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@ fn make_vm() -> Vm {
|
||||
fn eval(source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile: {}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
|
||||
let mut vm = make_vm();
|
||||
vm.run(&module)
|
||||
}
|
||||
@@ -140,22 +138,7 @@ fn reference_error_is_defined() {
|
||||
|
||||
#[test]
|
||||
fn error_subtype_constructors_produce_named_objects() {
|
||||
assert_eq!(
|
||||
format!("{}", eval("new Error('boom').name == 'Error'").unwrap()),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
eval("new TypeError('boom').name == 'TypeError'").unwrap()
|
||||
),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
eval("new SyntaxError('boom').name == 'SyntaxError'").unwrap()
|
||||
),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(format!("{}", eval("new Error('boom').name == 'Error'").unwrap()), "true");
|
||||
assert_eq!(format!("{}", eval("new TypeError('boom').name == 'TypeError'").unwrap()), "true");
|
||||
assert_eq!(format!("{}", eval("new SyntaxError('boom').name == 'SyntaxError'").unwrap()), "true");
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
@@ -38,11 +35,7 @@ fn function_to_string_includes_function() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Math.max.toString()").unwrap();
|
||||
assert!(result.is_string());
|
||||
let rendered = vm
|
||||
.kernel()
|
||||
.string_forge()
|
||||
.lookup(result.as_string_index())
|
||||
.unwrap_or_default();
|
||||
let rendered = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
|
||||
assert!(rendered.contains("function"), "got: {}", rendered);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(source: &str) -> Result<oxide_types::value::JsValue, String> {
|
||||
let allocator = Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
let mut vm = Vm::new();
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_types::value::JsValue;
|
||||
use oxide_vm::builtins::map::{
|
||||
map_clear, map_constructor as new_map, map_delete, map_get, map_has, map_set, map_size,
|
||||
};
|
||||
use oxide_vm::builtins::map::{map_clear, map_constructor as new_map, map_delete, map_get, map_has, map_set, map_size};
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn str_val(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// -- direct native fn tests --
|
||||
@@ -101,10 +93,6 @@ fn map_new_has() {
|
||||
#[test]
|
||||
fn map_new_delete() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var m = new Map(); m.set('x', 10); m.delete('x'); m.has('x')",
|
||||
)
|
||||
.unwrap();
|
||||
let r = eval(&mut vm, "var m = new Map(); m.set('x', 10); m.delete('x'); m.has('x')").unwrap();
|
||||
assert!(!r.as_bool());
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
@@ -79,11 +76,7 @@ fn number_constructor() {
|
||||
fn to_string_of_number() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "var n = 42; n.toString()").unwrap();
|
||||
let s = vm
|
||||
.kernel()
|
||||
.string_forge()
|
||||
.lookup(result.as_string_index())
|
||||
.unwrap_or_default();
|
||||
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
|
||||
assert_eq!(s, "42");
|
||||
}
|
||||
|
||||
@@ -91,11 +84,7 @@ fn to_string_of_number() {
|
||||
fn to_fixed_of_number() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "var n = 3.14159; n.toFixed(2)").unwrap();
|
||||
let s = vm
|
||||
.kernel()
|
||||
.string_forge()
|
||||
.lookup(result.as_string_index())
|
||||
.unwrap_or_default();
|
||||
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
|
||||
assert_eq!(s, "3.14");
|
||||
}
|
||||
|
||||
@@ -124,24 +113,13 @@ fn number_epsilon_is_positive() {
|
||||
fn number_to_exponential() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "var n = 123.456; n.toExponential(2)").unwrap();
|
||||
let s = vm
|
||||
.kernel()
|
||||
.string_forge()
|
||||
.lookup(result.as_string_index())
|
||||
.unwrap_or_default();
|
||||
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
|
||||
assert_eq!(s, "1.23e2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_static_constants_remain_bound() {
|
||||
let mut vm = Vm::new();
|
||||
assert_eq!(
|
||||
eval(&mut vm, "Number.MAX_SAFE_INTEGER")
|
||||
.unwrap()
|
||||
.as_double(),
|
||||
9007199254740991f64
|
||||
);
|
||||
assert!(eval(&mut vm, "Number.POSITIVE_INFINITY > 0")
|
||||
.unwrap()
|
||||
.as_bool());
|
||||
assert_eq!(eval(&mut vm, "Number.MAX_SAFE_INTEGER").unwrap().as_double(), 9007199254740991f64);
|
||||
assert!(eval(&mut vm, "Number.POSITIVE_INFINITY > 0").unwrap().as_bool());
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(source: &str) -> Result<(Vm, JsValue), String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
let mut vm = Vm::new();
|
||||
let result = vm.run(&module)?;
|
||||
Ok((vm, result))
|
||||
|
||||
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn to_str(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// --- RegExp constructor ---
|
||||
@@ -154,11 +148,7 @@ fn regexp_exec_global_last_index_advances() {
|
||||
#[test]
|
||||
fn regexp_exec_global_resets_on_exhaustion() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"var re = /a/g; re.exec('a'); re.exec('a') === null",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "var re = /a/g; re.exec('a'); re.exec('a') === null").unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_types::value::JsValue;
|
||||
use oxide_vm::builtins::set::{
|
||||
set_add, set_clear, set_constructor as new_set, set_delete, set_has, set_size,
|
||||
};
|
||||
use oxide_vm::builtins::set::{set_add, set_clear, set_constructor as new_set, set_delete, set_has, set_size};
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
@@ -119,10 +114,6 @@ fn set_new_has_missing() {
|
||||
#[test]
|
||||
fn set_new_delete() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = new Set(); s.add(1); s.add(2); s.delete(1); s.has(1)",
|
||||
)
|
||||
.unwrap();
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add(1); s.add(2); s.delete(1); s.has(1)").unwrap();
|
||||
assert!(!r.as_bool());
|
||||
}
|
||||
|
||||
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn to_str(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn to_str(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// --- Symbol constructor ---
|
||||
|
||||
@@ -38,26 +38,17 @@ fn eval_not_falsy() {
|
||||
|
||||
#[test]
|
||||
fn test_same_value_signed_zero() {
|
||||
assert!(!coercion::same_value(
|
||||
JsValue::float(0.0),
|
||||
JsValue::float(-0.0)
|
||||
));
|
||||
assert!(!coercion::same_value(JsValue::float(0.0), JsValue::float(-0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strict_equality_signed_zero() {
|
||||
assert!(coercion::strict_equality(
|
||||
JsValue::float(0.0),
|
||||
JsValue::float(-0.0)
|
||||
));
|
||||
assert!(coercion::strict_equality(JsValue::float(0.0), JsValue::float(-0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_same_value_nan() {
|
||||
assert!(coercion::same_value(
|
||||
JsValue::float(f64::NAN),
|
||||
JsValue::float(f64::NAN)
|
||||
));
|
||||
assert!(coercion::same_value(JsValue::float(f64::NAN), JsValue::float(f64::NAN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -73,36 +64,21 @@ fn test_same_value_int_float_equal() {
|
||||
|
||||
#[test]
|
||||
fn test_strict_equality_nan() {
|
||||
assert!(!coercion::strict_equality(
|
||||
JsValue::float(f64::NAN),
|
||||
JsValue::float(f64::NAN)
|
||||
));
|
||||
assert!(!coercion::strict_equality(JsValue::float(f64::NAN), JsValue::float(f64::NAN)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strict_equality_type_mismatch() {
|
||||
assert!(!coercion::strict_equality(
|
||||
JsValue::int(1),
|
||||
JsValue::bool(true)
|
||||
));
|
||||
assert!(!coercion::strict_equality(JsValue::int(1), JsValue::bool(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strict_equality_int_float_equal() {
|
||||
assert!(coercion::strict_equality(
|
||||
JsValue::int(1),
|
||||
JsValue::float(1.0)
|
||||
));
|
||||
assert!(!coercion::strict_equality(
|
||||
JsValue::int(1),
|
||||
JsValue::float(2.0)
|
||||
));
|
||||
assert!(coercion::strict_equality(JsValue::int(1), JsValue::float(1.0)));
|
||||
assert!(!coercion::strict_equality(JsValue::int(1), JsValue::float(2.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strict_equality_null_undefined() {
|
||||
assert!(!coercion::strict_equality(
|
||||
JsValue::null(),
|
||||
JsValue::undefined()
|
||||
));
|
||||
assert!(!coercion::strict_equality(JsValue::null(), JsValue::undefined()));
|
||||
}
|
||||
|
||||
@@ -61,18 +61,12 @@ fn eval_while_result_undefined() {
|
||||
|
||||
#[test]
|
||||
fn eval_for_basic() {
|
||||
assert_eq!(
|
||||
eval("var r = 0; for (i = 0; i < 3; i = i + 1) { r = r + i; } r"),
|
||||
"3"
|
||||
);
|
||||
assert_eq!(eval("var r = 0; for (i = 0; i < 3; i = i + 1) { r = r + i; } r"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_for_no_test() {
|
||||
assert_eq!(
|
||||
eval("var r = 0; for (i = 0; ; i = i + 1) { if (i >= 3) { break; } r = r + i; } r"),
|
||||
"3"
|
||||
);
|
||||
assert_eq!(eval("var r = 0; for (i = 0; ; i = i + 1) { if (i >= 3) { break; } r = r + i; } r"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -97,10 +91,7 @@ fn eval_ternary_nested() {
|
||||
|
||||
#[test]
|
||||
fn eval_break_in_while() {
|
||||
assert_eq!(
|
||||
eval("var i = 0; while (true) { i = i + 1; if (i >= 3) { break; } } i"),
|
||||
"3"
|
||||
);
|
||||
assert_eq!(eval("var i = 0; while (true) { i = i + 1; if (i >= 3) { break; } } i"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -155,10 +146,7 @@ fn eval_do_while_multi_iteration() {
|
||||
|
||||
#[test]
|
||||
fn eval_do_while_break() {
|
||||
assert_eq!(
|
||||
eval("var i = 0; do { i = i + 1; if (i >= 3) break; } while (true); i"),
|
||||
"3"
|
||||
);
|
||||
assert_eq!(eval("var i = 0; do { i = i + 1; if (i >= 3) break; } while (true); i"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -182,34 +170,22 @@ fn eval_for_in_empty_object() {
|
||||
#[test]
|
||||
fn eval_for_in_non_object_throws() {
|
||||
let result = eval("for (k in 42) {}");
|
||||
assert!(
|
||||
result.contains("TypeError"),
|
||||
"expected TypeError, got: {result}"
|
||||
);
|
||||
assert!(result.contains("TypeError"), "expected TypeError, got: {result}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_for_in_nested() {
|
||||
assert_eq!(
|
||||
eval("var r=0; for (k in {a:{x:1}}) { for (j in {y:2}) { r=r+1; } } r"),
|
||||
"2"
|
||||
);
|
||||
assert_eq!(eval("var r=0; for (k in {a:{x:1}}) { for (j in {y:2}) { r=r+1; } } r"), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_for_in_break() {
|
||||
assert_eq!(
|
||||
eval("var r=0; for (k in {a:1,b:2,c:3}) { if (k=='b') break; r=r+1; } r"),
|
||||
"1"
|
||||
);
|
||||
assert_eq!(eval("var r=0; for (k in {a:1,b:2,c:3}) { if (k=='b') break; r=r+1; } r"), "1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_for_in_continue() {
|
||||
assert_eq!(
|
||||
eval("var r=0; for (k in {a:1,b:2}) { if (k=='a') continue; r=r+1; } r"),
|
||||
"2"
|
||||
);
|
||||
assert_eq!(eval("var r=0; for (k in {a:1,b:2}) { if (k=='a') continue; r=r+1; } r"), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -220,10 +196,7 @@ fn eval_for_in_let_scoping() {
|
||||
|
||||
#[test]
|
||||
fn eval_switch_basic_match() {
|
||||
assert_eq!(
|
||||
eval("var x=0;switch(2){case 1:x=10;case 2:x=20;break;default:x=30;}x"),
|
||||
"20"
|
||||
);
|
||||
assert_eq!(eval("var x=0;switch(2){case 1:x=10;case 2:x=20;break;default:x=30;}x"), "20");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -243,18 +216,12 @@ fn eval_switch_no_match_no_default() {
|
||||
|
||||
#[test]
|
||||
fn eval_switch_break() {
|
||||
assert_eq!(
|
||||
eval("var x=0;switch(1){case 1:x=10;break;case 2:x=20;}x"),
|
||||
"10"
|
||||
);
|
||||
assert_eq!(eval("var x=0;switch(1){case 1:x=10;break;case 2:x=20;}x"), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_break_in_switch_in_loop() {
|
||||
assert_eq!(
|
||||
eval("var r=0;while(true){switch(1){case 1:r=1;break;}r=2;break;}r"),
|
||||
"2"
|
||||
);
|
||||
assert_eq!(eval("var r=0;while(true){switch(1){case 1:r=1;break;}r=2;break;}r"), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
@@ -61,11 +58,7 @@ fn fe_basic() {
|
||||
#[test]
|
||||
fn fe_with_params() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"var mul = function(x,y) { return x * y; }; mul(6, 7)",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "var mul = function(x,y) { return x * y; }; mul(6, 7)").unwrap();
|
||||
assert!((result.as_double() - 42.0).abs() < 0.0001);
|
||||
}
|
||||
|
||||
@@ -74,22 +67,14 @@ fn fe_with_params() {
|
||||
#[test]
|
||||
fn cross_func_call() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"function a() { return 1; } function b() { return a() + 2; } b()",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "function a() { return 1; } function b() { return a() + 2; } b()").unwrap();
|
||||
assert!((result.as_double() - 3.0).abs() < 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_funcs_called_from_global() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"function a() { return 1; } function b() { return 2; } a() + b()",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "function a() { return 1; } function b() { return 2; } a() + b()").unwrap();
|
||||
assert!(result.is_double(), "expected double, got: {:?}", result);
|
||||
assert!((result.as_double() - 3.0).abs() < 0.0001);
|
||||
}
|
||||
@@ -147,11 +132,7 @@ fn fd_calls_builtin_two_args() {
|
||||
#[test]
|
||||
fn fd_chain_call() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"function a() { return 10; } function b() { return a(); } b()",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "function a() { return 10; } function b() { return a(); } b()").unwrap();
|
||||
assert_eq!(result.as_int(), 10);
|
||||
}
|
||||
|
||||
@@ -177,11 +158,7 @@ fn fd_returns_new_array() {
|
||||
fn this_in_function_reads_value() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "function f() { return this; } f()").unwrap();
|
||||
assert!(
|
||||
result.is_object(),
|
||||
"expected object (function as this), got: {:?}",
|
||||
result
|
||||
);
|
||||
assert!(result.is_object(), "expected object (function as this), got: {:?}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -201,10 +178,6 @@ fn this_member_access() {
|
||||
#[test]
|
||||
fn this_in_constructor_sets_proto() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"function Ctor(m) { this.message = m; } Ctor.prototype = new Object(); 1",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "function Ctor(m) { this.message = m; } Ctor.prototype = new Object(); 1").unwrap();
|
||||
assert_eq!(result.as_int(), 1);
|
||||
}
|
||||
|
||||
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile error: {}", e))?;
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&module)
|
||||
}
|
||||
|
||||
fn string_value(vm: &Vm, val: JsValue) -> String {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
}
|
||||
|
||||
// -- JSON.parse --
|
||||
@@ -90,11 +84,7 @@ fn json_parse_null() {
|
||||
#[test]
|
||||
fn json_parse_nested() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"JSON.parse('{\"a\":1,\"b\":[1,2],\"c\":{\"d\":\"hello\"}}')",
|
||||
)
|
||||
.unwrap();
|
||||
let result = eval(&mut vm, "JSON.parse('{\"a\":1,\"b\":[1,2],\"c\":{\"d\":\"hello\"}}')").unwrap();
|
||||
assert!(result.is_object());
|
||||
}
|
||||
|
||||
@@ -200,11 +190,7 @@ fn json_parse_stringify_roundtrip() {
|
||||
#[test]
|
||||
fn json_roundtrip_array() {
|
||||
let mut vm = Vm::new();
|
||||
let _ = eval(
|
||||
&mut vm,
|
||||
"var arr = JSON.parse(JSON.stringify([1,2,3])); arr",
|
||||
)
|
||||
.unwrap();
|
||||
let _ = eval(&mut vm, "var arr = JSON.parse(JSON.stringify([1,2,3])); arr").unwrap();
|
||||
}
|
||||
|
||||
// -- Edge cases --
|
||||
|
||||
@@ -43,10 +43,7 @@ fn epoch_benchmark_1m_allocations() {
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
if cfg!(debug_assertions) {
|
||||
println!(
|
||||
"1M allocations took {}ms (debug build - skipping timing assertion)",
|
||||
elapsed.as_millis()
|
||||
);
|
||||
println!("1M allocations took {}ms (debug build - skipping timing assertion)", elapsed.as_millis());
|
||||
} else {
|
||||
assert!(
|
||||
elapsed.as_millis() < 200,
|
||||
|
||||
@@ -5,9 +5,7 @@ use oxide_vm::vm::Vm;
|
||||
fn eval(source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile: {}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
|
||||
let mut vm = Vm::new();
|
||||
vm.run(&module)
|
||||
}
|
||||
@@ -15,36 +13,21 @@ fn eval(source: &str) -> Result<JsValue, String> {
|
||||
macro_rules! assert_bool {
|
||||
($expr:expr, $expected:expr, $msg:expr) => {
|
||||
let r = $expr.unwrap();
|
||||
assert!(
|
||||
r.is_bool() && r.as_bool() == $expected,
|
||||
"{}: expected {}, got {:?}",
|
||||
$msg,
|
||||
$expected,
|
||||
r
|
||||
);
|
||||
assert!(r.is_bool() && r.as_bool() == $expected, "{}: expected {}, got {:?}", $msg, $expected, r);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_undefined {
|
||||
($expr:expr, $msg:expr) => {
|
||||
let r = $expr.unwrap();
|
||||
assert!(
|
||||
r.is_undefined(),
|
||||
"{}: expected undefined, got {:?}",
|
||||
$msg,
|
||||
r
|
||||
);
|
||||
assert!(r.is_undefined(), "{}: expected undefined, got {:?}", $msg, r);
|
||||
};
|
||||
}
|
||||
|
||||
// -- Proto chains: every (non-Object) constructor.prototype should inherit from Object.prototype --
|
||||
#[test]
|
||||
fn array_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Array.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Array proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Array.prototype) === Object.prototype"), true, "Array proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -57,20 +40,12 @@ fn function_proto_chain() {
|
||||
|
||||
#[test]
|
||||
fn string_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(String.prototype) === Object.prototype"),
|
||||
true,
|
||||
"String proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(String.prototype) === Object.prototype"), true, "String proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Number.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Number proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Number.prototype) === Object.prototype"), true, "Number proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -84,56 +59,32 @@ fn boolean_proto_chain() {
|
||||
|
||||
#[test]
|
||||
fn error_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Error.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Error proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Error.prototype) === Object.prototype"), true, "Error proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbol_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Symbol.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Symbol proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Symbol.prototype) === Object.prototype"), true, "Symbol proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Date.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Date proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Date.prototype) === Object.prototype"), true, "Date proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Set.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Set proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Set.prototype) === Object.prototype"), true, "Set proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(Map.prototype) === Object.prototype"),
|
||||
true,
|
||||
"Map proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(Map.prototype) === Object.prototype"), true, "Map proto");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regexp_proto_chain() {
|
||||
assert_bool!(
|
||||
eval("Object.getPrototypeOf(RegExp.prototype) === Object.prototype"),
|
||||
true,
|
||||
"RegExp proto"
|
||||
);
|
||||
assert_bool!(eval("Object.getPrototypeOf(RegExp.prototype) === Object.prototype"), true, "RegExp proto");
|
||||
}
|
||||
|
||||
// -- Object.prototype is the root, its __proto__ is null --
|
||||
@@ -147,20 +98,12 @@ fn object_proto_is_root() {
|
||||
#[test]
|
||||
fn array_instanceof_object() {
|
||||
assert_bool!(eval("[] instanceof Object"), true, "[] instanceof Object");
|
||||
assert_bool!(
|
||||
eval("new Array() instanceof Object"),
|
||||
true,
|
||||
"new Array instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Array() instanceof Object"), true, "new Array instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("(function() {}) instanceof Object"),
|
||||
true,
|
||||
"function instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("(function() {}) instanceof Object"), true, "function instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -179,110 +122,62 @@ fn boolean_not_instanceof_function() {
|
||||
|
||||
#[test]
|
||||
fn number_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Number(1) instanceof Object"),
|
||||
true,
|
||||
"new Number instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Number(1) instanceof Object"), true, "new Number instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boolean_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Boolean(true) instanceof Object"),
|
||||
true,
|
||||
"new Boolean instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Boolean(true) instanceof Object"), true, "new Boolean instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Error() instanceof Object"),
|
||||
true,
|
||||
"new Error instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Error() instanceof Object"), true, "new Error instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Date() instanceof Object"),
|
||||
true,
|
||||
"new Date instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Date() instanceof Object"), true, "new Date instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Set() instanceof Object"),
|
||||
true,
|
||||
"new Set instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Set() instanceof Object"), true, "new Set instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("new Map() instanceof Object"),
|
||||
true,
|
||||
"new Map instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new Map() instanceof Object"), true, "new Map instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regexp_instanceof_object() {
|
||||
assert_bool!(eval("/a/ instanceof Object"), true, "/a/ instanceof Object");
|
||||
assert_bool!(
|
||||
eval("new RegExp('a') instanceof Object"),
|
||||
true,
|
||||
"new RegExp instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("new RegExp('a') instanceof Object"), true, "new RegExp instanceof Object");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_instanceof_object() {
|
||||
assert_bool!(
|
||||
eval("({}) instanceof Object"),
|
||||
true,
|
||||
"({}) instanceof Object"
|
||||
);
|
||||
assert_bool!(eval("({}) instanceof Object"), true, "({}) instanceof Object");
|
||||
}
|
||||
|
||||
// -- instanceof for native types should NOT respond to their own false positives --
|
||||
#[test]
|
||||
fn number_not_instanceof_array() {
|
||||
assert_bool!(
|
||||
eval("new Number(1) instanceof Array"),
|
||||
false,
|
||||
"Number instanceof Array"
|
||||
);
|
||||
assert_bool!(eval("new Number(1) instanceof Array"), false, "Number instanceof Array");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_not_instanceof_regexp() {
|
||||
assert_bool!(
|
||||
eval("({}) instanceof RegExp"),
|
||||
false,
|
||||
"({}) instanceof RegExp"
|
||||
);
|
||||
assert_bool!(eval("({}) instanceof RegExp"), false, "({}) instanceof RegExp");
|
||||
}
|
||||
|
||||
// -- Primitives should NOT be instanceof their wrapper constructors (no autoboxing) --
|
||||
#[test]
|
||||
fn primitives_not_instanceof() {
|
||||
assert_bool!(eval("1 instanceof Number"), false, "1 instanceof Number");
|
||||
assert_bool!(
|
||||
eval("'hi' instanceof String"),
|
||||
false,
|
||||
"'hi' instanceof String"
|
||||
);
|
||||
assert_bool!(
|
||||
eval("true instanceof Boolean"),
|
||||
false,
|
||||
"true instanceof Boolean"
|
||||
);
|
||||
assert_bool!(eval("'hi' instanceof String"), false, "'hi' instanceof String");
|
||||
assert_bool!(eval("true instanceof Boolean"), false, "true instanceof Boolean");
|
||||
}
|
||||
|
||||
// -- VOID regression --
|
||||
|
||||
@@ -42,11 +42,7 @@ fn eval_with_kernel(source: &str, kernel: Arc<OxideKernel>) -> String {
|
||||
#[test]
|
||||
fn regression_to_boolean_empty_string() {
|
||||
assert_eq!(eval("!''"), "true", "NOT empty string should be true");
|
||||
assert_eq!(
|
||||
eval("if ('') { 1 } else { 2 }"),
|
||||
"2",
|
||||
"empty string should be falsy"
|
||||
);
|
||||
assert_eq!(eval("if ('') { 1 } else { 2 }"), "2", "empty string should be falsy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -71,19 +67,13 @@ fn regression_rerun_clears_ic_cache() {
|
||||
|
||||
#[test]
|
||||
fn regression_recursion_depth_limit() {
|
||||
assert_eq!(
|
||||
eval("function f(){f()} f()"),
|
||||
"vm error: RangeError: Maximum call stack size exceeded"
|
||||
);
|
||||
assert_eq!(eval("function f(){f()} f()"), "vm error: RangeError: Maximum call stack size exceeded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_throw_statement_errors() {
|
||||
let result = eval("throw 'error'");
|
||||
assert!(
|
||||
result.contains("uncaught"),
|
||||
"expected uncaught, got: {result}"
|
||||
);
|
||||
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
|
||||
assert!(
|
||||
result.contains("uncaught Error"),
|
||||
"expected string throw to default to Error, got: {result}"
|
||||
@@ -92,14 +82,8 @@ fn regression_throw_statement_errors() {
|
||||
|
||||
#[test]
|
||||
fn regression_throw_statement_preserves_type_error_kind() {
|
||||
assert_eq!(
|
||||
eval("try { throw new TypeError('boom') } catch (e) { e.name == 'TypeError' }"),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
eval("throw new TypeError('boom')"),
|
||||
"vm error: uncaught TypeError: {object}"
|
||||
);
|
||||
assert_eq!(eval("try { throw new TypeError('boom') } catch (e) { e.name == 'TypeError' }"), "true");
|
||||
assert_eq!(eval("throw new TypeError('boom')"), "vm error: uncaught TypeError: {object}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -108,10 +92,7 @@ fn regression_throw_statement_preserves_syntax_error_kind() {
|
||||
eval("try { throw new SyntaxError('boom') } catch (e) { e.name == 'SyntaxError' }"),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
eval("throw new SyntaxError('boom')"),
|
||||
"vm error: uncaught SyntaxError: {object}"
|
||||
);
|
||||
assert_eq!(eval("throw new SyntaxError('boom')"), "vm error: uncaught SyntaxError: {object}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -155,24 +136,12 @@ fn regression_new_expression_bytecode_constructor_error_is_catchable() {
|
||||
|
||||
#[test]
|
||||
fn regression_delete_static_property_throws_type_error() {
|
||||
assert_eq!(
|
||||
eval("try { var o={x:1}; delete o.x; 0 } catch (e) { e.name == 'TypeError' }"),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
eval("var o={x:1}; delete o.x"),
|
||||
"vm error: uncaught TypeError: {object}"
|
||||
);
|
||||
assert_eq!(eval("try { var o={x:1}; delete o.x; 0 } catch (e) { e.name == 'TypeError' }"), "true");
|
||||
assert_eq!(eval("var o={x:1}; delete o.x"), "vm error: uncaught TypeError: {object}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_delete_dynamic_property_throws_type_error() {
|
||||
assert_eq!(
|
||||
eval("try { var o={x:1}; delete o['x']; 0 } catch (e) { e.name == 'TypeError' }"),
|
||||
"true"
|
||||
);
|
||||
assert_eq!(
|
||||
eval("var o={x:1}; var k='x'; delete o[k]"),
|
||||
"vm error: uncaught TypeError: {object}"
|
||||
);
|
||||
assert_eq!(eval("try { var o={x:1}; delete o['x']; 0 } catch (e) { e.name == 'TypeError' }"), "true");
|
||||
assert_eq!(eval("var o={x:1}; var k='x'; delete o[k]"), "vm error: uncaught TypeError: {object}");
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ use oxide_vm::vm::Vm;
|
||||
fn eval(source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
|
||||
let module = Compiler::new()
|
||||
.compile(&program)
|
||||
.map_err(|e| format!("Compile: {}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
|
||||
let mut vm = Vm::new();
|
||||
vm.run(&module)
|
||||
}
|
||||
@@ -23,11 +21,7 @@ fn const_reassignment_throws() {
|
||||
let result = eval("const x = 1; x = 2");
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
err.contains("TypeError") || err.contains("constant"),
|
||||
"got: {}",
|
||||
err
|
||||
);
|
||||
assert!(err.contains("TypeError") || err.contains("constant"), "got: {}", err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -37,10 +37,7 @@ fn eval_val(source: &str) -> (Vm, Result<JsValue, String>) {
|
||||
|
||||
fn to_str(vm: &Vm, val: JsValue) -> String {
|
||||
if val.is_string() {
|
||||
vm.kernel()
|
||||
.string_forge()
|
||||
.lookup(val.as_string_index())
|
||||
.unwrap_or_default()
|
||||
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
|
||||
} else {
|
||||
format!("{}", val)
|
||||
}
|
||||
@@ -99,11 +96,7 @@ fn tagged_template_basic() {
|
||||
// This avoids bytecode function call complexity.
|
||||
let result = eval("Math.max`hello ${42} world`");
|
||||
// Math.max on the args should work - just verify it doesn't crash
|
||||
assert!(
|
||||
!result.starts_with("vm error:"),
|
||||
"Tagged template should not crash, got: {}",
|
||||
result
|
||||
);
|
||||
assert!(!result.starts_with("vm error:"), "Tagged template should not crash, got: {}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -111,8 +104,5 @@ fn tagged_template_compiles_no_error() {
|
||||
// Verify that tagged templates compile without error (even if the tag
|
||||
// function behavior isn't fully tested)
|
||||
let result = eval("function t(s,v){ return s[0]+v; } t`x${1}`");
|
||||
assert!(
|
||||
!result.starts_with("compile error:"),
|
||||
"Tagged template should compile"
|
||||
);
|
||||
assert!(!result.starts_with("compile error:"), "Tagged template should compile");
|
||||
}
|
||||
|
||||
@@ -121,9 +121,7 @@ fn as_js_object_ptr_non_object_returns_null() {
|
||||
assert!(JsValue::null().as_js_object_ptr().is_null());
|
||||
assert!(JsValue::undefined().as_js_object_ptr().is_null());
|
||||
let x = 42u8;
|
||||
assert!(!JsValue::object(&x as *const u8)
|
||||
.as_js_object_ptr()
|
||||
.is_null());
|
||||
assert!(!JsValue::object(&x as *const u8).as_js_object_ptr().is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -27,10 +27,7 @@ fn test_throw_caught_by_catch() {
|
||||
#[test]
|
||||
fn test_throw_without_catch() {
|
||||
let result = eval("throw 'err';");
|
||||
assert!(
|
||||
result.contains("uncaught"),
|
||||
"expected uncaught, got: {result}"
|
||||
);
|
||||
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -41,34 +38,22 @@ fn test_try_finally_normal_path() {
|
||||
#[test]
|
||||
fn test_try_finally_exception_path() {
|
||||
let result = eval("var x = 0; try { throw 1; } finally { x = 2; }");
|
||||
assert!(
|
||||
result.contains("uncaught"),
|
||||
"expected uncaught, got: {result}"
|
||||
);
|
||||
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_try_inner_catches() {
|
||||
assert_eq!(
|
||||
eval("try { try { throw 1; } catch(e) { e; } } catch(e) { 2; }"),
|
||||
"1"
|
||||
);
|
||||
assert_eq!(eval("try { try { throw 1; } catch(e) { e; } } catch(e) { 2; }"), "1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_try_outer_catches() {
|
||||
assert_eq!(
|
||||
eval("try { try { throw 1; } catch(e) { throw 2; } } catch(e) { e; }"),
|
||||
"2"
|
||||
);
|
||||
assert_eq!(eval("try { try { throw 1; } catch(e) { throw 2; } } catch(e) { e; }"), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_catch_finally() {
|
||||
assert_eq!(
|
||||
eval("var x = 0; try { x = 1; } catch(e) { x = 2; } finally { x = 3; } x;"),
|
||||
"3"
|
||||
);
|
||||
assert_eq!(eval("var x = 0; try { x = 1; } catch(e) { x = 2; } finally { x = 3; } x;"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -92,8 +77,5 @@ fn test_throw_err_type_error_is_object() {
|
||||
#[test]
|
||||
fn test_uncaught_type_error_message() {
|
||||
let result = eval("null.prop;");
|
||||
assert!(
|
||||
result.contains("TypeError"),
|
||||
"expected TypeError in message, got: {result}"
|
||||
);
|
||||
assert!(result.contains("TypeError"), "expected TypeError in message, got: {result}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user