mod common;
use common::deep_eq;
use serpent_serializer::value::{Key, Table, Value};
use serpent_serializer::{block, load, LoadOptions};
struct Rng(u64);
impl Rng {
fn next(&mut self) -> u64 {
let mut x = self.0;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.0 = x;
x
}
fn range(&mut self, lo: i64, hi: i64) -> i64 {
let span = (hi - lo + 1) as u64;
lo + (self.next() % span) as i64
}
}
fn random_var(rng: &mut Rng, is_key: bool, depth: u32) -> Value {
let key = rng.range(1, 1000);
if key <= 100 {
if is_key {
Value::Number(0.0)
} else {
Value::Nil
}
} else if key <= 200 {
Value::Bool(false)
} else if key <= 500 {
Value::Number(rng.range(-1_000_000, 1_000_000) as f64)
} else if key <= 900 {
let len = rng.range(0, 100);
let mut s = Vec::with_capacity(len as usize);
for _ in 0..len {
s.push(rng.range(65, 90) as u8);
}
Value::Str(s)
} else if depth > 3 || is_key {
Value::Number(0.0)
} else {
let len = rng.range(0, 10);
let t = Table::new();
for _ in 0..len {
if rng.range(0, 1) == 0 {
t.push(random_var(rng, false, depth + 1));
} else {
let k = random_var(rng, true, depth + 1);
let v = random_var(rng, false, depth + 1);
if let Ok(key) = to_key(k) {
t.set(key, v);
}
}
}
Value::Table(t)
}
}
fn to_key(v: Value) -> Result<Key, ()> {
match v {
Value::Bool(b) => Ok(Key::Bool(b)),
Value::Number(n) => Ok(Key::Number(n)),
Value::Str(s) => Ok(Key::Str(s)),
Value::Table(t) => Ok(Key::Table(t)),
_ => Err(()),
}
}
#[test]
fn random_values_round_trip() {
for seed in [
0x1234_5678u64,
0x9abc_def0,
0xdead_beef,
0x0f0f_0f0f,
0xa5a5_5a5a,
0xcafe_babe,
] {
let mut rng = Rng(seed | 1);
for i in 0..256 {
let x = random_var(&mut rng, false, 0);
let s = block(&x).unwrap();
let back = load(&s, &LoadOptions::default())
.unwrap_or_else(|e| panic!("load failed seed={seed} i={i}: {e}\n{s}"));
assert!(
deep_eq(&x, &back),
"mismatch seed={seed} i={i}\nsource:\n{s}"
);
}
}
}