use super::{eval, eval_result};
use tsrun::JsValue;
#[test]
fn test_strict_assign_infinity() {
let result = eval_result("Infinity = 1; Infinity");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.to_string().contains("constant") || err.to_string().contains("Assignment"),
"Expected constant assignment error, got: {}",
err
);
}
#[test]
fn test_strict_assign_nan() {
let result = eval_result("NaN = 1; NaN");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.to_string().contains("constant") || err.to_string().contains("Assignment"),
"Expected constant assignment error, got: {}",
err
);
}
#[test]
fn test_strict_assign_undefined() {
let result = eval_result("undefined = 1; undefined");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.to_string().contains("constant") || err.to_string().contains("Assignment"),
"Expected constant assignment error, got: {}",
err
);
}
#[test]
fn test_strict_can_shadow_infinity_in_function() {
let result = eval(
r#"
function test() {
var Infinity = 42;
return Infinity;
}
test()
"#,
);
assert_eq!(result.value(), &JsValue::Number(42.0));
}
#[test]
fn test_strict_can_shadow_with_let() {
let result = eval(
r#"
{
let Infinity = 42;
Infinity
}
"#,
);
assert_eq!(result.value(), &JsValue::Number(42.0));
}
#[test]
fn test_strict_no_var_eval() {
let result = eval_result("var eval = 1;");
assert!(result.is_err(), "Should not allow var eval in strict mode");
}
#[test]
fn test_strict_no_let_eval() {
let result = eval_result("let eval = 1;");
assert!(result.is_err(), "Should not allow let eval in strict mode");
}
#[test]
fn test_strict_no_const_eval() {
let result = eval_result("const eval = 1;");
assert!(
result.is_err(),
"Should not allow const eval in strict mode"
);
}
#[test]
fn test_strict_no_var_arguments() {
let result = eval_result("var arguments = 1;");
assert!(
result.is_err(),
"Should not allow var arguments in strict mode"
);
}
#[test]
fn test_strict_no_let_arguments() {
let result = eval_result("let arguments = 1;");
assert!(
result.is_err(),
"Should not allow let arguments in strict mode"
);
}
#[test]
fn test_strict_no_const_arguments() {
let result = eval_result("const arguments = 1;");
assert!(
result.is_err(),
"Should not allow const arguments in strict mode"
);
}
#[test]
fn test_strict_no_param_eval() {
let result = eval_result("function f(eval) { return eval; }");
assert!(
result.is_err(),
"Should not allow eval as parameter in strict mode"
);
}
#[test]
fn test_strict_no_param_arguments() {
let result = eval_result("function f(arguments) { return arguments; }");
assert!(
result.is_err(),
"Should not allow arguments as parameter in strict mode"
);
}
#[test]
fn test_strict_no_assign_eval() {
let result = eval_result("eval = 1;");
assert!(
result.is_err(),
"Should not allow assignment to eval in strict mode"
);
}
#[test]
fn test_strict_no_assign_arguments() {
let result = eval_result("arguments = 1;");
assert!(
result.is_err(),
"Should not allow assignment to arguments in strict mode"
);
}
#[test]
fn test_strict_no_duplicate_params() {
let result = eval_result("function f(a, a) { return a; }");
assert!(
result.is_err(),
"Should not allow duplicate parameter names in strict mode"
);
}
#[test]
fn test_strict_no_duplicate_params_arrow() {
let result = eval_result("const f = (a, a) => a;");
assert!(
result.is_err(),
"Should not allow duplicate params in arrow functions"
);
}
#[test]
fn test_strict_no_delete_variable() {
let result = eval_result("var x = 1; delete x;");
assert!(
result.is_err(),
"Should not allow delete on variable in strict mode"
);
}
#[test]
fn test_strict_delete_property_allowed() {
let result = eval("const obj = { x: 1 }; delete obj.x; obj.x");
assert_eq!(result.value(), &JsValue::Undefined);
}
#[test]
fn test_strict_no_legacy_octal() {
let result = eval_result("0777");
assert!(
result.is_err(),
"Should not allow legacy octal literals in strict mode"
);
}
#[test]
fn test_strict_es6_octal_allowed() {
let result = eval("0o777");
assert_eq!(result.value(), &JsValue::Number(511.0));
}
#[test]
fn test_strict_no_octal_escape() {
let result = eval_result(r#""\077""#);
assert!(
result.is_err(),
"Should not allow octal escape in string in strict mode"
);
}
#[test]
fn test_strict_no_with_statement() {
let result = eval_result("with ({}) {}");
assert!(
result.is_err(),
"Should not allow with statement in strict mode"
);
}
#[test]
fn test_delete_super_property_throws_reference_error() {
let result = eval_result(
r#"
class C extends Object {
test() {
delete super.x;
}
}
new C().test();
"#,
);
assert!(result.is_err(), "delete super.x should throw");
let err = result.unwrap_err();
assert!(
err.to_string().contains("ReferenceError") || err.to_string().contains("super"),
"Expected ReferenceError for delete super.x, got: {}",
err
);
}
#[test]
fn test_delete_super_property_with_type_cast() {
let result = eval_result(
r#"
class C extends Object {
test() {
delete (super as any).x;
}
}
new C().test();
"#,
);
assert!(result.is_err(), "delete (super as any).x should throw");
let err = result.unwrap_err();
assert!(
err.to_string().contains("ReferenceError") || err.to_string().contains("super"),
"Expected ReferenceError for delete super.x with type cast, got: {}",
err
);
}