Browse Source

tests: add check_output test helper (#1458)

Co-authored-by: jedel1043 <jedel0124@gmail.com>
pull/1498/head
Bartek Iwańczuk 3 years ago committed by GitHub
parent
commit
1b380c69af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      boa/src/builtins/symbol/tests.rs
  2. 144
      boa/src/exec/tests.rs
  3. 44
      boa/src/lib.rs
  4. 157
      boa/src/syntax/ast/node/iteration/tests.rs
  5. 110
      boa/src/value/tests.rs

13
boa/src/builtins/symbol/tests.rs

@ -1,4 +1,4 @@
use crate::{forward, forward_val, Context};
use crate::{check_output, forward, forward_val, Context, TestAction};
#[test]
fn call_symbol_and_check_return_type() {
@ -24,7 +24,6 @@ fn print_symbol_expect_description() {
#[test]
fn symbol_access() {
let mut context = Context::new();
let init = r#"
var x = {};
var sym1 = Symbol("Hello");
@ -32,8 +31,10 @@ fn symbol_access() {
x[sym1] = 10;
x[sym2] = 20;
"#;
forward_val(&mut context, init).unwrap();
assert_eq!(forward(&mut context, "x[sym1]"), "10");
assert_eq!(forward(&mut context, "x[sym2]"), "20");
assert_eq!(forward(&mut context, "x['Symbol(Hello)']"), "undefined");
check_output(&[
TestAction::Execute(init),
TestAction::TestEq("x[sym1]", "10"),
TestAction::TestEq("x[sym2]", "20"),
TestAction::TestEq("x['Symbol(Hello)']", "undefined"),
]);
}

144
boa/src/exec/tests.rs

@ -1,4 +1,6 @@
use crate::{builtins::Number, exec, forward, forward_val, Context, JsValue};
use crate::{
builtins::Number, check_output, exec, forward, forward_val, Context, JsValue, TestAction,
};
#[test]
fn function_declaration_returns_undefined() {
@ -118,8 +120,6 @@ fn object_field_set() {
#[test]
fn spread_with_arguments() {
let mut context = Context::new();
let scenario = r#"
const a = [1, "test", 3, 4];
function foo(...a) {
@ -128,31 +128,27 @@ fn spread_with_arguments() {
var result = foo(...a);
"#;
forward(&mut context, scenario);
let one = forward(&mut context, "result[0]");
assert_eq!(one, String::from("1"));
let two = forward(&mut context, "result[1]");
assert_eq!(two, String::from("\"test\""));
let three = forward(&mut context, "result[2]");
assert_eq!(three, String::from("3"));
let four = forward(&mut context, "result[3]");
assert_eq!(four, String::from("4"));
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result[0]", "1"),
TestAction::TestEq("result[1]", "\"test\""),
TestAction::TestEq("result[2]", "3"),
TestAction::TestEq("result[3]", "4"),
]);
}
#[test]
fn array_rest_with_arguments() {
let mut context = Context::new();
let scenario = r#"
var b = [4, 5, 6]
var a = [1, 2, 3, ...b];
"#;
forward(&mut context, scenario);
let one = forward(&mut context, "a");
assert_eq!(one, String::from("[ 1, 2, 3, 4, 5, 6 ]"));
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("a", "[ 1, 2, 3, 4, 5, 6 ]"),
]);
}
#[test]
@ -722,8 +718,6 @@ mod in_operator {
#[test]
fn should_type_error_when_rhs_not_object() {
let mut context = Context::new();
let scenario = r#"
var x = false;
try {
@ -733,14 +727,14 @@ mod in_operator {
}
"#;
forward(&mut context, scenario);
assert_eq!(forward(&mut context, "x"), "true");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("x", "true"),
]);
}
#[test]
fn should_set_this_value() {
let mut context = Context::new();
let scenario = r#"
function Foo() {
this.a = "a";
@ -749,22 +743,24 @@ mod in_operator {
var bar = new Foo();
"#;
forward(&mut context, scenario);
assert_eq!(forward(&mut context, "bar.a"), "\"a\"");
assert_eq!(forward(&mut context, "bar.b"), "\"b\"");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("bar.a", "\"a\""),
TestAction::TestEq("bar.b", "\"b\""),
]);
}
#[test]
fn should_type_error_when_new_is_not_constructor() {
let mut context = Context::new();
let scenario = r#"
const a = "";
new a();
"#;
let result = forward(&mut context, scenario);
assert_eq!(result, "Uncaught \"TypeError\": \"a is not a constructor\"");
check_output(&[TestAction::TestEq(
&scenario,
"Uncaught \"TypeError\": \"a is not a constructor\"",
)]);
}
#[test]
@ -1223,45 +1219,38 @@ fn number_object_access_benchmark() {
#[test]
fn not_a_function() {
let mut context = Context::new();
let init = r#"
let a = {};
let b = true;
"#;
forward(&mut context, init);
let scenario = r#"
let scenario1 = r#"
try {
a();
} catch(e) {
e.toString()
}
"#;
assert_eq!(
forward(&mut context, scenario),
"\"TypeError: not a function\""
);
let scenario = r#"
let scenario2 = r#"
try {
a.a();
} catch(e) {
e.toString()
}
"#;
assert_eq!(
forward(&mut context, scenario),
"\"TypeError: not a function\""
);
let scenario = r#"
let scenario3 = r#"
try {
b();
} catch(e) {
e.toString()
}
"#;
assert_eq!(
forward(&mut context, scenario),
"\"TypeError: not a function\""
);
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(scenario1, "\"TypeError: not a function\""),
TestAction::TestEq(scenario2, "\"TypeError: not a function\""),
TestAction::TestEq(scenario3, "\"TypeError: not a function\""),
]);
}
#[test]
@ -1339,12 +1328,12 @@ fn multicharacter_bitwise_assignment_to_non_assignable() {
#[test]
fn assign_to_array_decl() {
let mut context = Context::new();
assert!(forward(&mut context, "[1] = [2]").starts_with("Uncaught \"SyntaxError\": "));
assert!(forward(&mut context, "[3, 5] = [7, 8]").starts_with("Uncaught \"SyntaxError\": "));
assert!(forward(&mut context, "[6, 8] = [2]").starts_with("Uncaught \"SyntaxError\": "));
assert!(forward(&mut context, "[6] = [2, 9]").starts_with("Uncaught \"SyntaxError\": "));
check_output(&[
TestAction::TestStartsWith("[1] = [2]", "Uncaught \"SyntaxError\": "),
TestAction::TestStartsWith("[3, 5] = [7, 8]", "Uncaught \"SyntaxError\": "),
TestAction::TestStartsWith("[6, 8] = [2]", "Uncaught \"SyntaxError\": "),
TestAction::TestStartsWith("[6] = [2, 9]", "Uncaught \"SyntaxError\": "),
]);
}
#[test]
@ -1407,11 +1396,10 @@ fn test_strict_mode_octal() {
var n = 023;
"#;
let mut context = Context::new();
let string = dbg!(forward(&mut context, scenario));
assert!(string.starts_with("Uncaught \"SyntaxError\": "));
check_output(&[TestAction::TestStartsWith(
scenario,
"Uncaught \"SyntaxError\": ",
)]);
}
#[test]
@ -1428,11 +1416,10 @@ fn test_strict_mode_with() {
}
"#;
let mut context = Context::new();
let string = dbg!(forward(&mut context, scenario));
assert!(string.starts_with("Uncaught \"SyntaxError\": "));
check_output(&[TestAction::TestStartsWith(
scenario,
"Uncaught \"SyntaxError\": ",
)]);
}
#[test]
@ -1446,11 +1433,10 @@ fn test_strict_mode_delete() {
delete x;
"#;
let mut context = Context::new();
let string = dbg!(forward(&mut context, scenario));
assert!(string.starts_with("Uncaught \"SyntaxError\": "));
check_output(&[TestAction::TestStartsWith(
scenario,
"Uncaught \"SyntaxError\": ",
)]);
}
#[test]
@ -1494,11 +1480,10 @@ fn test_strict_mode_func_decl_in_block() {
if (a < b) { function f() {} }
"#;
let mut context = Context::new();
let string = dbg!(forward(&mut context, scenario));
assert!(string.starts_with("Uncaught \"SyntaxError\": "));
check_output(&[TestAction::TestStartsWith(
scenario,
"Uncaught \"SyntaxError\": ",
)]);
}
#[test]
@ -1511,11 +1496,10 @@ fn test_strict_mode_dup_func_parameters() {
function f(a, b, b) {}
"#;
let mut context = Context::new();
let string = dbg!(forward(&mut context, scenario));
assert!(string.starts_with("Uncaught \"SyntaxError\": "));
check_output(&[TestAction::TestStartsWith(
scenario,
"Uncaught \"SyntaxError\": ",
)]);
}
#[test]

44
boa/src/lib.rs

@ -159,3 +159,47 @@ pub(crate) fn exec<T: AsRef<[u8]>>(src: T) -> String {
Err(error) => error.display().to_string(),
}
}
#[cfg(test)]
pub(crate) enum TestAction {
Execute(&'static str),
TestEq(&'static str, &'static str),
TestStartsWith(&'static str, &'static str),
}
/// Create a clean Context, call "forward" for each action, and optionally
/// assert equality of the returned value or if returned value starts with
/// expected string.
#[cfg(test)]
#[track_caller]
pub(crate) fn check_output(actions: &[TestAction]) {
let mut context = Context::new();
let mut i = 1;
for action in actions {
match action {
TestAction::Execute(src) => {
forward(&mut context, src);
}
TestAction::TestEq(case, expected) => {
assert_eq!(
&forward(&mut context, case),
expected,
"Test case {} ('{}')",
i,
case
);
i += 1;
}
TestAction::TestStartsWith(case, expected) => {
assert!(
&forward(&mut context, case).starts_with(expected),
"Test case {} ('{}')",
i,
case
);
i += 1;
}
}
}
}

157
boa/src/syntax/ast/node/iteration/tests.rs

@ -1,4 +1,4 @@
use crate::{exec, forward, Context};
use crate::{check_output, exec, TestAction};
#[test]
fn while_loop_late_break() {
@ -194,87 +194,84 @@ fn do_while_loop_continue() {
#[test]
fn for_of_loop_declaration() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (i of [1, 2, 3]) {
result = i;
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "3");
assert_eq!(&forward(&mut context, "i"), "3");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "3"),
TestAction::TestEq("i", "3"),
]);
}
#[test]
fn for_of_loop_var() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (var i of [1, 2, 3]) {
result = i;
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "3");
assert_eq!(&forward(&mut context, "i"), "3");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "3"),
TestAction::TestEq("i", "3"),
]);
}
#[test]
fn for_of_loop_let() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (let i of [1, 2, 3]) {
result = i;
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "3");
assert_eq!(
&forward(
&mut context,
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "3"),
TestAction::TestEq(
r#"
try {
i
} catch(e) {
e.toString()
}
"#
"#,
"\"ReferenceError: i is not defined\"",
),
"\"ReferenceError: i is not defined\""
);
]);
}
#[test]
fn for_of_loop_const() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (let i of [1, 2, 3]) {
result = i;
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "3");
assert_eq!(
&forward(
&mut context,
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "3"),
TestAction::TestEq(
r#"
try {
i
} catch(e) {
e.toString()
}
"#
"#,
"\"ReferenceError: i is not defined\"",
),
"\"ReferenceError: i is not defined\""
);
]);
}
#[test]
fn for_of_loop_break() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (var i of [1, 2, 3]) {
@ -283,14 +280,15 @@ fn for_of_loop_break() {
result = i
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "1");
assert_eq!(&forward(&mut context, "i"), "2");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "1"),
TestAction::TestEq("i", "2"),
]);
}
#[test]
fn for_of_loop_continue() {
let mut context = Context::new();
let scenario = r#"
var result = 0;
for (var i of [1, 2, 3]) {
@ -299,14 +297,15 @@ fn for_of_loop_continue() {
result = i
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "result"), "2");
assert_eq!(&forward(&mut context, "i"), "3");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("result", "2"),
TestAction::TestEq("i", "3"),
]);
}
#[test]
fn for_of_loop_return() {
let mut context = Context::new();
let scenario = r#"
function foo() {
for (i of [1, 2, 3]) {
@ -315,8 +314,10 @@ fn for_of_loop_return() {
}
}
"#;
context.eval(scenario).unwrap();
assert_eq!(&forward(&mut context, "foo()"), "2");
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("foo()", "2"),
]);
}
#[test]
@ -356,8 +357,6 @@ fn for_loop_continue_label() {
#[test]
fn for_in_declaration() {
let mut context = Context::new();
let init = r#"
let result = [];
let obj = { a: "a", b: 2};
@ -366,21 +365,17 @@ fn for_in_declaration() {
result = result.concat([i]);
}
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(
&mut context,
"result.length === 2 && result.includes('a') && result.includes('b')"
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(
"result.length === 2 && result.includes('a') && result.includes('b')",
"true",
),
"true"
);
]);
}
#[test]
fn for_in_var_object() {
let mut context = Context::new();
let init = r#"
let result = [];
let obj = { a: "a", b: 2};
@ -388,21 +383,17 @@ fn for_in_var_object() {
result = result.concat([i]);
}
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(
&mut context,
"result.length === 2 && result.includes('a') && result.includes('b')"
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(
"result.length === 2 && result.includes('a') && result.includes('b')",
"true",
),
"true"
);
]);
}
#[test]
fn for_in_var_array() {
let mut context = Context::new();
let init = r#"
let result = [];
let arr = ["a", "b"];
@ -410,21 +401,17 @@ fn for_in_var_array() {
result = result.concat([i]);
}
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(
&mut context,
"result.length === 2 && result.includes('0') && result.includes('1')"
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(
"result.length === 2 && result.includes('0') && result.includes('1')",
"true",
),
"true"
);
]);
}
#[test]
fn for_in_let_object() {
let mut context = Context::new();
let init = r#"
let result = [];
let obj = { a: "a", b: 2};
@ -432,21 +419,17 @@ fn for_in_let_object() {
result = result.concat([i]);
}
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(
&mut context,
"result.length === 2 && result.includes('a') && result.includes('b')"
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(
"result.length === 2 && result.includes('a') && result.includes('b')",
"true",
),
"true"
);
]);
}
#[test]
fn for_in_const_array() {
let mut context = Context::new();
let init = r#"
let result = [];
let arr = ["a", "b"];
@ -454,15 +437,13 @@ fn for_in_const_array() {
result = result.concat([i]);
}
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(
&mut context,
"result.length === 2 && result.includes('0') && result.includes('1')"
check_output(&[
TestAction::Execute(init),
TestAction::TestEq(
"result.length === 2 && result.includes('0') && result.includes('1')",
"true",
),
"true"
);
]);
}
#[test]

110
boa/src/value/tests.rs

@ -1,7 +1,7 @@
#![allow(clippy::float_cmp)]
use super::*;
use crate::{forward, forward_val, Context};
use crate::{check_output, forward, forward_val, Context, TestAction};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
@ -64,63 +64,45 @@ fn number_is_true() {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
#[test]
fn abstract_equality_comparison() {
let mut context = Context::new();
assert_eq!(forward(&mut context, "undefined == undefined"), "true");
assert_eq!(forward(&mut context, "null == null"), "true");
assert_eq!(forward(&mut context, "true == true"), "true");
assert_eq!(forward(&mut context, "false == false"), "true");
assert_eq!(forward(&mut context, "'foo' == 'foo'"), "true");
assert_eq!(forward(&mut context, "0 == 0"), "true");
assert_eq!(forward(&mut context, "+0 == -0"), "true");
assert_eq!(forward(&mut context, "+0 == 0"), "true");
assert_eq!(forward(&mut context, "-0 == 0"), "true");
assert_eq!(forward(&mut context, "0 == false"), "true");
assert_eq!(forward(&mut context, "'' == false"), "true");
assert_eq!(forward(&mut context, "'' == 0"), "true");
assert_eq!(forward(&mut context, "'17' == 17"), "true");
assert_eq!(forward(&mut context, "[1,2] == '1,2'"), "true");
assert_eq!(forward(&mut context, "new String('foo') == 'foo'"), "true");
assert_eq!(forward(&mut context, "null == undefined"), "true");
assert_eq!(forward(&mut context, "undefined == null"), "true");
assert_eq!(forward(&mut context, "null == false"), "false");
assert_eq!(forward(&mut context, "[] == ![]"), "true");
assert_eq!(
forward(
&mut context,
"a = { foo: 'bar' }; b = { foo: 'bar'}; a == b"
check_output(&[
TestAction::TestEq("undefined == undefined", "true"),
TestAction::TestEq("null == null", "true"),
TestAction::TestEq("true == true", "true"),
TestAction::TestEq("false == false", "true"),
TestAction::TestEq("'foo' == 'foo'", "true"),
TestAction::TestEq("0 == 0", "true"),
TestAction::TestEq("+0 == -0", "true"),
TestAction::TestEq("+0 == 0", "true"),
TestAction::TestEq("-0 == 0", "true"),
TestAction::TestEq("0 == false", "true"),
TestAction::TestEq("'' == false", "true"),
TestAction::TestEq("'' == 0", "true"),
TestAction::TestEq("'17' == 17", "true"),
TestAction::TestEq("[1,2] == '1,2'", "true"),
TestAction::TestEq("new String('foo') == 'foo'", "true"),
TestAction::TestEq("null == undefined", "true"),
TestAction::TestEq("undefined == null", "true"),
TestAction::TestEq("null == false", "false"),
TestAction::TestEq("[] == ![]", "true"),
TestAction::TestEq("a = { foo: 'bar' }; b = { foo: 'bar'}; a == b", "false"),
TestAction::TestEq("new String('foo') == new String('foo')", "false"),
TestAction::TestEq("0 == null", "false"),
TestAction::TestEq("0 == '-0'", "true"),
TestAction::TestEq("0 == '+0'", "true"),
TestAction::TestEq("'+0' == 0", "true"),
TestAction::TestEq("'-0' == 0", "true"),
TestAction::TestEq("0 == NaN", "false"),
TestAction::TestEq("'foo' == NaN", "false"),
TestAction::TestEq("NaN == NaN", "false"),
TestAction::TestEq(
"Number.POSITIVE_INFINITY === Number.POSITIVE_INFINITY",
"true",
),
"false"
);
assert_eq!(
forward(&mut context, "new String('foo') == new String('foo')"),
"false"
);
assert_eq!(forward(&mut context, "0 == null"), "false");
assert_eq!(forward(&mut context, "0 == '-0'"), "true");
assert_eq!(forward(&mut context, "0 == '+0'"), "true");
assert_eq!(forward(&mut context, "'+0' == 0"), "true");
assert_eq!(forward(&mut context, "'-0' == 0"), "true");
assert_eq!(forward(&mut context, "0 == NaN"), "false");
assert_eq!(forward(&mut context, "'foo' == NaN"), "false");
assert_eq!(forward(&mut context, "NaN == NaN"), "false");
assert_eq!(
forward(
&mut context,
"Number.POSITIVE_INFINITY === Number.POSITIVE_INFINITY"
TestAction::TestEq(
"Number.NEGATIVE_INFINITY === Number.NEGATIVE_INFINITY",
"true",
),
"true"
);
assert_eq!(
forward(
&mut context,
"Number.NEGAVIVE_INFINITY === Number.NEGAVIVE_INFINITY"
),
"true"
);
]);
}
/// Helper function to get the hash of a `Value`.
@ -608,20 +590,20 @@ fn to_integer_or_infinity() {
#[test]
fn test_accessors() {
let mut context = Context::new();
let src = r#"
let arr = [];
let a = { get b() { return "c" }, set b(value) { arr = arr.concat([value]) }} ;
a.b = "a";
"#;
context.eval(src).unwrap();
assert_eq!(forward(&mut context, "a.b"), r#""c""#);
assert_eq!(forward(&mut context, "arr"), r#"[ "a" ]"#);
check_output(&[
TestAction::Execute(src),
TestAction::TestEq("a.b", r#""c""#),
TestAction::TestEq("arr", r#"[ "a" ]"#),
]);
}
#[test]
fn to_primitive() {
let mut context = Context::new();
let src = r#"
let a = {};
a[Symbol.toPrimitive] = function() {
@ -629,8 +611,10 @@ fn to_primitive() {
};
let primitive = a + 0;
"#;
context.eval(src).unwrap();
assert_eq!(forward(&mut context, "primitive"), "42");
check_output(&[
TestAction::Execute(src),
TestAction::TestEq("primitive", "42"),
]);
}
/// Test cyclic conversions that previously caused stack overflows

Loading…
Cancel
Save