use std::io::Write;
use std::process::{Command, Stdio};
use parse_rust_core::js_number::to_ecma_string;
fn edge_cases() -> Vec<f64> {
let mut v = vec![
0.0,
-0.0,
1.0,
-1.0,
0.1,
0.5,
1.5,
-1.5,
1e20,
9.999_999_999_999_999e20,
1e21,
1.000_000_000_000_000_1e21,
1e22,
1e-5,
1e-6,
9.999e-7,
1e-7,
1e-8,
1e15,
1e16,
1e17,
1e18,
1e19,
123_456_789_012_345_678_901.0,
9_007_199_254_740_992.0, 9_007_199_254_740_994.0, f64::MAX,
f64::MIN_POSITIVE,
5e-324, f64::EPSILON,
f64::NAN,
f64::INFINITY,
f64::NEG_INFINITY,
];
for e in -323i32..=308 {
let p = format!("1e{e}").parse::<f64>().unwrap_or(0.0);
if p != 0.0 {
v.push(p);
v.push(-p);
}
}
for i in 0..1000 {
v.push(i as f64);
v.push(-(i as f64));
v.push(i as f64 / 8.0);
v.push(i as f64 * 1e6);
}
v
}
fn random_bit_patterns(count: usize) -> Vec<f64> {
let mut state: u64 = 0x2545_F491_4F6C_DD1D;
let mut out = Vec::with_capacity(count);
for _ in 0..count {
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
let bits = state.wrapping_mul(0x2545_F491_4F6C_DD1D);
out.push(f64::from_bits(bits));
}
out
}
#[test]
#[ignore = "requires node; run with --ignored or via tools/test.sh"]
fn every_formatted_number_matches_node() {
let mut corpus = edge_cases();
corpus.extend(random_bit_patterns(200_000));
let mut tsv = String::with_capacity(corpus.len() * 32);
for v in &corpus {
tsv.push_str(&v.to_bits().to_string());
tsv.push('\t');
tsv.push_str(&to_ecma_string(*v));
tsv.push('\n');
}
let oracle = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../tools/js-number-oracle.js"
);
let mut child = Command::new("node")
.env_remove("NODE_OPTIONS")
.arg(oracle)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("node must be on PATH for this test; it is #[ignore]d by default");
child
.stdin
.take()
.expect("stdin was piped")
.write_all(tsv.as_bytes())
.expect("failed writing corpus to node");
let out = child
.wait_with_output()
.expect("node did not run to completion");
assert!(
out.status.success(),
"js_number diverges from Node.\n{}\n{}",
String::from_utf8_lossy(&out.stderr),
String::from_utf8_lossy(&out.stdout),
);
println!("{}", String::from_utf8_lossy(&out.stdout).trim());
}