use crous_core::decoder::Decoder;
use crous_core::encoder::Encoder;
use crous_core::limits::Limits;
use crous_core::value::Value;
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
#[test]
fn encoder_is_send() {
assert_send::<Encoder>();
}
#[test]
fn value_is_send_sync() {
assert_send::<Value>();
assert_sync::<Value>();
}
#[test]
fn limits_is_send_sync() {
assert_send::<Limits>();
assert_sync::<Limits>();
}
#[test]
fn concurrent_encode_decode_100_threads() {
use std::thread;
let handles: Vec<_> = (0..100)
.map(|i| {
thread::spawn(move || {
let val = Value::Object(vec![
("id".into(), Value::UInt(i)),
("name".into(), Value::Str(format!("thread-{i}"))),
("data".into(), Value::Array(vec![
Value::UInt(i * 10),
Value::Float(i as f64 * 0.1),
Value::Bool(i % 2 == 0),
])),
]);
for _ in 0..100 {
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val, "thread {i} mismatch");
}
})
})
.collect();
for h in handles {
h.join().expect("thread panicked");
}
}
#[test]
fn concurrent_dedup_encode_decode() {
use std::thread;
let handles: Vec<_> = (0..50)
.map(|i| {
thread::spawn(move || {
let items: Vec<Value> = (0..20)
.map(|j| {
if j % 3 == 0 {
Value::Str(format!("shared-{}", i % 5))
} else {
Value::Str(format!("unique-{i}-{j}"))
}
})
.collect();
let val = Value::Array(items.clone());
let mut enc = Encoder::new();
enc.enable_dedup();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val, "dedup thread {i} mismatch");
})
})
.collect();
for h in handles {
h.join().expect("dedup thread panicked");
}
}
#[test]
fn shared_bytes_decoded_by_many_threads() {
use std::sync::Arc;
use std::thread;
let val = Value::Object(vec![
("x".into(), Value::UInt(42)),
("y".into(), Value::Str("hello world".into())),
("z".into(), Value::Array(vec![Value::Bool(true); 10])),
]);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = Arc::new(enc.finish().unwrap());
let val = Arc::new(val);
let handles: Vec<_> = (0..200)
.map(|_| {
let bytes = Arc::clone(&bytes);
let val = Arc::clone(&val);
thread::spawn(move || {
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, *val);
})
})
.collect();
for h in handles {
h.join().expect("shared decode panicked");
}
}
#[test]
fn sustained_throughput_100k_encodes() {
let val = Value::Object(vec![
("id".into(), Value::UInt(12345)),
("msg".into(), Value::Str("test message".into())),
("ok".into(), Value::Bool(true)),
]);
for _ in 0..100_000 {
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
assert!(bytes.len() > 8);
}
}
#[test]
fn sustained_throughput_100k_decodes() {
let val = Value::Object(vec![
("id".into(), Value::UInt(12345)),
("msg".into(), Value::Str("test message".into())),
("ok".into(), Value::Bool(true)),
]);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
for _ in 0..100_000 {
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
}
#[test]
fn large_array_10k_items() {
let items: Vec<Value> = (0..10_000)
.map(|i| Value::Str(format!("item-{i:06}")))
.collect();
let val = Value::Array(items);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn large_object_1k_fields() {
let entries: Vec<(String, Value)> = (0..1000)
.map(|i| (format!("field_{i:04}"), Value::UInt(i)))
.collect();
let val = Value::Object(entries);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn large_string_1mb() {
let s = "A".repeat(1024 * 1024);
let val = Value::Str(s);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn large_binary_5mb() {
let blob = vec![0xCD; 5 * 1024 * 1024];
let val = Value::Bytes(blob);
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn mixed_payload_sizes() {
let values = vec![
Value::Null, Value::Bool(true), Value::UInt(42), Value::Str("short".into()), Value::Str("a".repeat(1000)), Value::Bytes(vec![0xAB; 10_000]), Value::Array(vec![Value::UInt(1); 1000]), Value::Object( (0..100)
.map(|i| (format!("k{i}"), Value::Str(format!("v{i}"))))
.collect(),
),
];
let mut enc = Encoder::new();
for v in &values {
enc.encode_value(v).unwrap();
}
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_all_owned().unwrap();
assert_eq!(decoded.len(), values.len());
for (original, decoded) in values.iter().zip(decoded.iter()) {
assert_eq!(decoded, original);
}
}
#[test]
#[ignore] fn soak_1_million_roundtrips() {
for i in 0u64..1_000_000 {
let val = match i % 9 {
0 => Value::Null,
1 => Value::Bool(i % 2 == 0),
2 => Value::UInt(i),
3 => Value::Int(-(i as i64)),
4 => Value::Float(i as f64 * 0.001),
5 => Value::Str(format!("soak-{i}")),
6 => Value::Bytes(vec![(i & 0xFF) as u8; 4]),
7 => Value::Array(vec![Value::UInt(i), Value::Null]),
8 => Value::Object(vec![("k".into(), Value::UInt(i))]),
_ => unreachable!(),
};
let mut enc = Encoder::new();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val, "soak mismatch at iteration {i}");
}
}
#[test]
fn dedup_with_many_unique_strings() {
let items: Vec<Value> = (0..1000)
.map(|i| Value::Str(format!("unique_string_number_{i:06}")))
.collect();
let val = Value::Array(items);
let mut enc = Encoder::new();
enc.enable_dedup();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn dedup_with_all_identical_strings() {
let items: Vec<Value> = (0..500)
.map(|_| Value::Str("identical".into()))
.collect();
let val = Value::Array(items);
let mut enc_dedup = Encoder::new();
enc_dedup.enable_dedup();
enc_dedup.encode_value(&val).unwrap();
let bytes_dedup = enc_dedup.finish().unwrap();
let mut enc_plain = Encoder::new();
enc_plain.encode_value(&val).unwrap();
let bytes_plain = enc_plain.finish().unwrap();
assert!(
bytes_dedup.len() < bytes_plain.len() / 2,
"dedup={} plain={}",
bytes_dedup.len(),
bytes_plain.len()
);
let mut dec = Decoder::new(&bytes_dedup);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}
#[test]
fn dedup_empty_strings() {
let items: Vec<Value> = (0..10)
.map(|_| Value::Str(String::new()))
.collect();
let val = Value::Array(items);
let mut enc = Encoder::new();
enc.enable_dedup();
enc.encode_value(&val).unwrap();
let bytes = enc.finish().unwrap();
let mut dec = Decoder::new(&bytes);
let decoded = dec.decode_next_owned().unwrap();
assert_eq!(decoded, val);
}