use javascript::Value;
use javascript::evaluate_script;
#[ctor::ctor]
fn __init_test_logger() {
let _ = env_logger::Builder::from_env(env_logger::Env::default()).is_test(true).try_init();
}
#[cfg(test)]
mod number_tests {
use super::*;
#[test]
fn test_number_max_value() {
let script = "Number.MAX_VALUE";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, f64::MAX);
}
_ => panic!("Expected Number.MAX_VALUE to be f64::MAX, got {:?}", result),
}
}
#[test]
fn test_number_min_value() {
let script = "Number.MIN_VALUE";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, f64::MIN_POSITIVE);
}
_ => panic!("Expected Number.MIN_VALUE to be f64::MIN_POSITIVE, got {:?}", result),
}
}
#[test]
fn test_number_nan() {
let script = "Number.NaN";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert!(n.is_nan());
}
_ => panic!("Expected Number.NaN to be NaN, got {:?}", result),
}
}
#[test]
fn test_number_positive_infinity() {
let script = "Number.POSITIVE_INFINITY";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, f64::INFINITY);
}
_ => panic!("Expected Number.POSITIVE_INFINITY to be f64::INFINITY, got {:?}", result),
}
}
#[test]
fn test_number_negative_infinity() {
let script = "Number.NEGATIVE_INFINITY";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, f64::NEG_INFINITY);
}
_ => panic!("Expected Number.NEGATIVE_INFINITY to be f64::NEG_INFINITY, got {:?}", result),
}
}
#[test]
fn test_number_epsilon() {
let script = "Number.EPSILON";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, f64::EPSILON);
}
_ => panic!("Expected Number.EPSILON to be f64::EPSILON, got {:?}", result),
}
}
#[test]
fn test_number_max_safe_integer() {
let script = "Number.MAX_SAFE_INTEGER";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, 9007199254740991.0);
}
_ => panic!("Expected Number.MAX_SAFE_INTEGER to be 9007199254740991.0, got {:?}", result),
}
}
#[test]
fn test_number_min_safe_integer() {
let script = "Number.MIN_SAFE_INTEGER";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, -9007199254740991.0);
}
_ => panic!("Expected Number.MIN_SAFE_INTEGER to be -9007199254740991.0, got {:?}", result),
}
}
#[test]
fn test_number_is_nan() {
let script = "Number.isNaN(NaN)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isNaN(NaN) to be true, got {:?}", result),
}
let script = "Number.isNaN(42)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isNaN(42) to be false, got {:?}", result),
}
let script = "Number.isNaN('not a number')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b), _ => panic!("Expected Number.isNaN('not a number') to be false, got {:?}", result),
}
let script = "Number.isNaN(undefined)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isNaN(undefined) to be false, got {:?}", result),
}
}
#[test]
fn test_number_is_finite() {
let script = "Number.isFinite(42)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isFinite(42) to be true, got {:?}", result),
}
let script = "Number.isFinite(Infinity)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isFinite(Infinity) to be false, got {:?}", result),
}
let script = "Number.isFinite(NaN)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isFinite(NaN) to be false, got {:?}", result),
}
let script = "Number.isFinite('42')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isFinite('42') to be false, got {:?}", result),
}
}
#[test]
fn test_number_is_integer() {
let script = "Number.isInteger(42)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isInteger(42) to be true, got {:?}", result),
}
let script = "Number.isInteger(42.5)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isInteger(42.5) to be false, got {:?}", result),
}
let script = "Number.isInteger(Infinity)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isInteger(Infinity) to be false, got {:?}", result),
}
let script = "Number.isInteger(NaN)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isInteger(NaN) to be false, got {:?}", result),
}
let script = "Number.isInteger('42')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isInteger('42') to be false, got {:?}", result),
}
}
#[test]
fn test_number_is_safe_integer() {
let script = "Number.isSafeInteger(42)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isSafeInteger(42) to be true, got {:?}", result),
}
let script = "Number.isSafeInteger(9007199254740991)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isSafeInteger(9007199254740991) to be true, got {:?}", result),
}
let script = "Number.isSafeInteger(-9007199254740991)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(b),
_ => panic!("Expected Number.isSafeInteger(-9007199254740991) to be true, got {:?}", result),
}
let script = "Number.isSafeInteger(9007199254740992)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isSafeInteger(9007199254740992) to be false, got {:?}", result),
}
let script = "Number.isSafeInteger(42.5)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isSafeInteger(42.5) to be false, got {:?}", result),
}
let script = "Number.isSafeInteger(Infinity)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Boolean(b)) => assert!(!b),
_ => panic!("Expected Number.isSafeInteger(Infinity) to be false, got {:?}", result),
}
}
#[test]
fn test_number_parse_float() {
let script = "Number.parseFloat('3.16')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 3.16),
_ => panic!("Expected Number.parseFloat('3.16') to be 3.16, got {:?}", result),
}
let script = "Number.parseFloat('42')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.0),
_ => panic!("Expected Number.parseFloat('42') to be 42.0, got {:?}", result),
}
let script = "Number.parseFloat('not a number')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert!(n.is_nan()),
_ => panic!("Expected Number.parseFloat('not a number') to be NaN, got {:?}", result),
}
let script = "Number.parseFloat(42.5)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.5),
_ => panic!("Expected Number.parseFloat(42.5) to be 42.5, got {:?}", result),
}
let script = "Number.parseFloat(' 3.16 ')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 3.16),
_ => panic!("Expected Number.parseFloat(' 3.16 ') to be 3.16, got {:?}", result),
}
}
#[test]
fn test_shift_edge_cases_and_bigint_mixing() {
let res = evaluate_script("let a = 1; a <<= 33; a", None::<&std::path::Path>).unwrap();
match res {
Value::Number(n) => assert_eq!(n, 2.0),
_ => panic!("Expected 2.0 for 1 <<= 33, got {:?}", res),
}
let res = evaluate_script("let a = 1; a <<= -1; a", None::<&std::path::Path>).unwrap();
match res {
Value::Number(n) => assert_eq!(n, -2147483648.0),
_ => panic!("Expected -2147483648.0 for 1 <<= -1, got {:?}", res),
}
let res = evaluate_script("let a = -1; a >>>= 1; a", None::<&std::path::Path>).unwrap();
match res {
Value::Number(n) => assert_eq!(n, 2147483647.0),
_ => panic!("Expected 2147483647.0 for -1 >>>= 1, got {:?}", res),
}
let res = evaluate_script("let a = 1n; let b = 2; a <<= b", None::<&std::path::Path>);
match res {
Err(err) => match err.kind() {
javascript::JSErrorKind::TypeError { message, .. } => assert!(message.contains("Cannot mix BigInt")),
_ => panic!("Expected TypeError for mixing BigInt and Number in <<=, got {:?}", err),
},
other => panic!("Expected TypeError for mixing BigInt and Number in <<=, got {:?}", other),
}
let res = evaluate_script("let a = 1n; a >>>= 1n", None::<&std::path::Path>);
match res {
Err(err) => match err.kind() {
javascript::JSErrorKind::TypeError { message, .. } => assert!(message.contains("Unsigned right shift")),
_ => panic!("Expected TypeError for BigInt >>>=, got {:?}", err),
},
other => panic!("Expected TypeError for BigInt >>>=, got {:?}", other),
}
}
#[test]
fn test_bigint_shift_and_bitwise_mixing_errors() {
let res = evaluate_script(
"let a = 1n; a <<= 100000000000000000000000000000000000000n",
None::<&std::path::Path>,
);
match res {
Err(err) => match err.kind() {
javascript::JSErrorKind::EvaluationError { message, .. } => {
assert!(
message.contains("invalid bigint shift") || message.contains("invalid bigint"),
"message={}",
message
)
}
_ => panic!("Expected EvaluationError for huge BigInt shift, got {:?}", err),
},
other => panic!("Expected EvaluationError for huge BigInt shift, got {:?}", other),
}
let res = evaluate_script("let a = 1n; a <<= -1n", None::<&std::path::Path>);
match res {
Err(err) => match err.kind() {
javascript::JSErrorKind::EvaluationError { message, .. } => {
assert!(
message.contains("invalid bigint shift") || message.contains("invalid bigint"),
"message={}",
message
)
}
_ => panic!("Expected EvaluationError for negative BigInt shift, got {:?}", err),
},
other => panic!("Expected EvaluationError for negative BigInt shift, got {:?}", other),
}
let res = evaluate_script("let a = 1n; let b = 2; a ^= b", None::<&std::path::Path>);
match res {
Err(err) => match err.kind() {
javascript::JSErrorKind::TypeError { message, .. } => assert!(message.contains("Cannot mix BigInt")),
_ => panic!("Expected TypeError for BigInt ^ Number mixing, got {:?}", err),
},
other => panic!("Expected TypeError for BigInt ^ Number mixing, got {:?}", other),
}
}
#[test]
fn test_number_parse_int() {
let script = "Number.parseInt('42')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.0),
_ => panic!("Expected Number.parseInt('42') to be 42.0, got {:?}", result),
}
let script = "Number.parseInt('42.5')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.0),
_ => panic!("Expected Number.parseInt('42.5') to be 42.0, got {:?}", result),
}
let script = "Number.parseInt('not a number')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert!(n.is_nan()),
_ => panic!("Expected Number.parseInt('not a number') to be NaN, got {:?}", result),
}
let script = "Number.parseInt('101', 2)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 5.0), _ => panic!("Expected Number.parseInt('101', 2) to be 5.0, got {:?}", result),
}
let script = "Number.parseInt('FF', 16)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 255.0),
_ => panic!("Expected Number.parseInt('FF', 16) to be 255.0, got {:?}", result),
}
let script = "Number.parseInt(42.7)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.0),
_ => panic!("Expected Number.parseInt(42.7) to be 42.0, got {:?}", result),
}
}
#[test]
fn test_number_constructor_no_args() {
let script = "Number()";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 0.0),
_ => panic!("Expected Number() to be 0.0, got {:?}", result),
}
}
#[test]
fn test_number_constructor_with_number() {
let script = "Number(42.5)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.5),
_ => panic!("Expected Number(42.5) to be 42.5, got {:?}", result),
}
}
#[test]
fn test_number_constructor_with_string() {
let script = "Number('42.5')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 42.5),
_ => panic!("Expected Number('42.5') to be 42.5, got {:?}", result),
}
}
#[test]
fn test_number_constructor_with_boolean() {
let script = "Number(true)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 1.0),
_ => panic!("Expected Number(true) to be 1.0, got {:?}", result),
}
let script = "Number(false)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert_eq!(n, 0.0),
_ => panic!("Expected Number(false) to be 0.0, got {:?}", result),
}
}
#[test]
fn test_number_constructor_with_invalid_string() {
let script = "Number('not a number')";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert!(n.is_nan()),
_ => panic!("Expected Number('not a number') to be NaN, got {:?}", result),
}
}
#[test]
fn test_number_constructor_with_undefined() {
let script = "Number(undefined)";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => assert!(n.is_nan()),
_ => panic!("Expected Number(undefined) to be NaN, got {:?}", result),
}
}
#[test]
fn test_number_object_properties_exist() {
let properties = vec![
"MAX_VALUE",
"MIN_VALUE",
"NaN",
"POSITIVE_INFINITY",
"NEGATIVE_INFINITY",
"EPSILON",
"MAX_SAFE_INTEGER",
"MIN_SAFE_INTEGER",
"isNaN",
"isFinite",
"isInteger",
"isSafeInteger",
"parseFloat",
"parseInt",
];
for prop in properties {
let script = format!("typeof Number.{}", prop);
let result = evaluate_script(&script, None::<&std::path::Path>);
match result {
Ok(Value::String(s)) => {
let type_str = String::from_utf16_lossy(&s);
assert_ne!(type_str, "undefined", "Number.{} should exist", prop);
}
_ => panic!("Expected typeof Number.{} to return a string, got {:?}", prop, result),
}
}
}
#[test]
fn test_bitwise_xor_numbers() {
let script = "5 ^ 3";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, 6.0); }
_ => panic!("Expected 5 ^ 3 to evaluate to 6, got {:?}", result),
}
}
#[test]
fn test_bitwise_xor_negative_numbers() {
let script = "-5 ^ 3";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, -8.0); }
_ => panic!("Expected -5 ^ 3 to evaluate to -8, got {:?}", result),
}
}
#[test]
fn test_bitwise_xor_assignment() {
let script = "let a = 5; a ^= 3; a";
let result = evaluate_script(script, None::<&std::path::Path>);
match result {
Ok(Value::Number(n)) => {
assert_eq!(n, 6.0); }
_ => panic!("Expected a ^= 3 to evaluate to 6, got {:?}", result),
}
}
#[test]
fn test_bitwise_compound_assignments() {
let script1 = "let a = 5; a &= 3; a";
let result1 = evaluate_script(script1, None::<&std::path::Path>);
assert!(
result1.is_ok(),
"evaluate_script(script1, None::<&std::path::Path>) failed: {:?}",
result1
);
match result1 {
Ok(Value::Number(n)) => assert_eq!(n, 1.0), _ => panic!("Expected 1.0, got {:?}", result1),
}
let script2 = "let b = 5; b |= 3; b";
let result2 = evaluate_script(script2, None::<&std::path::Path>);
assert!(
result2.is_ok(),
"evaluate_script(script2, None::<&std::path::Path>) failed: {:?}",
result2
);
match result2 {
Ok(Value::Number(n)) => assert_eq!(n, 7.0), _ => panic!("Expected 7.0, got {:?}", result2),
}
let script3 = "let c = 5; c ^= 3; c";
let result3 = evaluate_script(script3, None::<&std::path::Path>);
assert!(
result3.is_ok(),
"evaluate_script(script3, None::<&std::path::Path>) failed: {:?}",
result3
);
match result3 {
Ok(Value::Number(n)) => assert_eq!(n, 6.0), _ => panic!("Expected 6.0, got {:?}", result3),
}
let script4 = "let d = 5; d <<= 1; d";
let result4 = evaluate_script(script4, None::<&std::path::Path>);
assert!(
result4.is_ok(),
"evaluate_script(script4, None::<&std::path::Path>) failed: {:?}",
result4
);
match result4 {
Ok(Value::Number(n)) => assert_eq!(n, 10.0), _ => panic!("Expected 10.0, got {:?}", result4),
}
let script5 = "let e = 5; e >>= 1; e";
let result5 = evaluate_script(script5, None::<&std::path::Path>);
assert!(
result5.is_ok(),
"evaluate_script(script5, None::<&std::path::Path>) failed: {:?}",
result5
);
match result5 {
Ok(Value::Number(n)) => assert_eq!(n, 2.0), _ => panic!("Expected 2.0, got {:?}", result5),
}
let script6 = "let f = -5; f >>>= 1; f";
let result6 = evaluate_script(script6, None::<&std::path::Path>);
assert!(
result6.is_ok(),
"evaluate_script(script6, None::<&std::path::Path>) failed: {:?}",
result6
);
match result6 {
Ok(Value::Number(n)) => assert_eq!(n, 2147483645.0), _ => panic!("Expected 2147483645.0, got {:?}", result6),
}
}
}