use proptest::prelude::*;
use synadb::{Atom, SynaDB};
use tempfile::tempdir;
fn arb_unicode_key() -> impl Strategy<Value = String> {
prop_oneof![
10 => ".{1,100}",
5 => prop::collection::vec(
prop_oneof![
Just("π".to_string()),
Just("π".to_string()),
Just("π".to_string()),
Just("β€οΈ".to_string()),
Just("π".to_string()),
Just("π₯".to_string()),
Just("β¨".to_string()),
Just("π΅".to_string()),
],
1..10
).prop_map(|v| v.join("")),
5 => prop::collection::vec(
prop_oneof![
Just("δΈ".to_string()),
Just("ζ".to_string()),
Just("ζ₯".to_string()),
Just("ζ¬".to_string()),
Just("ν".to_string()),
Just("κΈ".to_string()),
Just("ζΌ’".to_string()),
Just("ε".to_string()),
],
1..20
).prop_map(|v| v.join("")),
5 => prop::collection::vec(
prop_oneof![
Just("Ω
Ψ±ΨΨ¨Ψ§".to_string()),
Just("Χ©ΧΧΧ".to_string()),
Just("Ψ§ΩΨΉΨ±Ψ¨ΩΨ©".to_string()),
Just("Χ’ΧΧ¨ΧΧͺ".to_string()),
],
1..5
).prop_map(|v| v.join(" ")),
5 => prop::collection::vec(
prop_oneof![
Just("Γ©".to_string()), Just("e\u{0301}".to_string()), Just("Γ±".to_string()),
Just("n\u{0303}".to_string()), Just("ΓΌ".to_string()),
Just("u\u{0308}".to_string()), ],
1..20
).prop_map(|v| v.join("")),
5 => prop::collection::vec(
prop_oneof![
Just(" ".to_string()),
Just("\t".to_string()),
Just("\n".to_string()),
Just("\r\n".to_string()),
Just("a".to_string()),
],
1..20
).prop_map(|v| v.join(""))
.prop_filter("non-empty after trim check", |s: &String| !s.is_empty()),
5 => (
".{1,30}",
prop::collection::vec(
prop_oneof![
Just("π".to_string()),
Just("δΈ".to_string()),
Just("Ω
Ψ±ΨΨ¨Ψ§".to_string()),
],
1..5
),
".{1,30}"
).prop_map(|(a, mid, b)| format!("{}{}{}", a, mid.join(""), b)),
2 => ".{100,1000}",
]
.prop_filter("non-empty key", |s: &String| !s.is_empty())
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_schema_free_key_acceptance(key in arb_unicode_key()) {
let dir = tempdir().expect("failed to create temp dir");
let db_path = dir.path().join("test.db");
let mut db = SynaDB::new(&db_path).expect("failed to create db");
let result = db.append(&key, Atom::Null);
prop_assert!(result.is_ok(), "append with unicode key should succeed: {:?}", result.err());
let read_result = db.get(&key);
prop_assert!(read_result.is_ok(), "get with unicode key should succeed: {:?}", read_result.err());
let value = read_result.unwrap();
prop_assert!(value.is_some(), "key should exist after write");
prop_assert_eq!(value.unwrap(), Atom::Null, "read value should equal written value");
}
#[test]
fn prop_schema_free_key_with_various_atoms(
key in arb_unicode_key(),
atom in prop_oneof![
Just(Atom::Null),
any::<f64>().prop_filter("filter NaN", |f| !f.is_nan()).prop_map(Atom::Float),
any::<i64>().prop_map(Atom::Int),
".{0,100}".prop_map(|s: String| Atom::Text(s)),
prop::collection::vec(any::<u8>(), 0..100).prop_map(Atom::Bytes),
]
) {
let dir = tempdir().expect("failed to create temp dir");
let db_path = dir.path().join("test.db");
let mut db = SynaDB::new(&db_path).expect("failed to create db");
let result = db.append(&key, atom.clone());
prop_assert!(result.is_ok(), "append should succeed: {:?}", result.err());
let read_result = db.get(&key);
prop_assert!(read_result.is_ok(), "get should succeed: {:?}", read_result.err());
let value = read_result.unwrap();
prop_assert!(value.is_some(), "key should exist after write");
prop_assert_eq!(value.unwrap(), atom, "read value should equal written value");
}
#[test]
fn prop_schema_free_key_persistence(key in arb_unicode_key()) {
let dir = tempdir().expect("failed to create temp dir");
let db_path = dir.path().join("test.db");
{
let mut db = SynaDB::new(&db_path).expect("failed to create db");
db.append(&key, Atom::Int(42)).expect("append should succeed");
}
{
let mut db = SynaDB::new(&db_path).expect("failed to reopen db");
let value = db.get(&key).expect("get should succeed");
prop_assert!(value.is_some(), "key should exist after reopen");
prop_assert_eq!(value.unwrap(), Atom::Int(42), "value should persist");
}
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
fn test_empty_key_rejected() {
let dir = tempdir().expect("failed to create temp dir");
let db_path = dir.path().join("test.db");
let mut db = SynaDB::new(&db_path).expect("failed to create db");
let result = db.append("", Atom::Null);
assert!(result.is_err(), "empty key should be rejected");
}
#[test]
fn test_specific_unicode_keys() {
let dir = tempdir().expect("failed to create temp dir");
let db_path = dir.path().join("test.db");
let mut db = SynaDB::new(&db_path).expect("failed to create db");
let test_keys = vec![
"ππβ¨",
"δΈζζ₯ζ¬θͺνκΈ",
"Ω
Ψ±ΨΨ¨Ψ§ Χ©ΧΧΧ",
"cafΓ©",
"e\u{0301}", "key with spaces",
"key\twith\ttabs",
"key\nwith\nnewlines",
"user_π_δΈζ_123",
"βββ«β",
"β¬Β£Β₯βΉ",
];
for (i, key) in test_keys.iter().enumerate() {
let atom = Atom::Int(i as i64);
db.append(key, atom.clone())
.expect(&format!("append should succeed for key: {}", key));
let value = db.get(key).expect("get should succeed");
assert_eq!(value, Some(atom), "value mismatch for key: {}", key);
}
}
}