1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! Property-based tests for Atom serialization round-trip.
//!
//! **Feature: Syna-db, Property 1: Atom Serialization Round-Trip**
//! **Validates: Requirements 5.4, 10.1**
use proptest::prelude::*;
use synadb::types::Atom;
/// Generator for arbitrary Atom values.
fn arb_atom() -> impl Strategy<Value = Atom> {
prop_oneof![
1 => Just(Atom::Null),
// Float with any f64 including NaN, infinity edge cases
10 => any::<f64>().prop_map(Atom::Float),
// Int with any i64
10 => any::<i64>().prop_map(Atom::Int),
// Text with arbitrary unicode strings (0-1000 chars)
10 => ".{0,1000}".prop_map(|s: String| Atom::Text(s)),
// Bytes with arbitrary byte vectors (0-10000 bytes)
10 => prop::collection::vec(any::<u8>(), 0..10000).prop_map(Atom::Bytes),
// Vector with arbitrary f32 values and dimensions (64-8192)
10 => arb_vector().prop_map(|(data, dims)| Atom::Vector(data, dims)),
]
}
/// Generator for arbitrary Vector data with valid dimensions.
fn arb_vector() -> impl Strategy<Value = (Vec<f32>, u16)> {
// Common embedding dimensions: 64, 128, 256, 384, 512, 768, 1024, 1536, 3072, 4096
prop_oneof![
Just(64u16),
Just(128u16),
Just(256u16),
Just(384u16), // MiniLM
Just(512u16),
Just(768u16), // BERT base
Just(1024u16), // BERT large
Just(1536u16), // OpenAI ada-002
]
.prop_flat_map(|dims| {
prop::collection::vec(any::<f32>(), dims as usize).prop_map(move |data| (data, dims))
})
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
/// **Feature: Syna-db, Property 1: Atom Serialization Round-Trip**
///
/// For any valid Atom value, serializing with bincode and then deserializing
/// SHALL produce a value equal to the original.
#[test]
fn prop_atom_serialization_roundtrip(atom in arb_atom()) {
// Serialize the atom
let serialized = bincode::serialize(&atom).expect("serialization should succeed");
// Deserialize back
let deserialized: Atom = bincode::deserialize(&serialized).expect("deserialization should succeed");
// Special handling for NaN floats - NaN != NaN by IEEE 754
match (&atom, &deserialized) {
(Atom::Float(a), Atom::Float(b)) if a.is_nan() && b.is_nan() => {
// Both are NaN, consider them equal for this test
}
(Atom::Vector(a_data, a_dims), Atom::Vector(b_data, b_dims)) => {
// Check dimensions match
prop_assert_eq!(a_dims, b_dims, "vector dimensions should match");
// Check data length matches
prop_assert_eq!(a_data.len(), b_data.len(), "vector data length should match");
// Check each element, handling NaN specially
for (a, b) in a_data.iter().zip(b_data.iter()) {
if a.is_nan() && b.is_nan() {
// Both NaN, consider equal
} else {
prop_assert_eq!(a, b, "vector elements should match");
}
}
}
_ => {
prop_assert_eq!(atom, deserialized, "round-trip should preserve value");
}
}
}
}