use sochdb::prelude::*;
use std::fs;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
static TEST_COUNT: AtomicUsize = AtomicUsize::new(0);
static PASS_COUNT: AtomicUsize = AtomicUsize::new(0);
static FAIL_COUNT: AtomicUsize = AtomicUsize::new(0);
fn test_assert(condition: bool, message: &str) -> bool {
TEST_COUNT.fetch_add(1, Ordering::SeqCst);
if condition {
PASS_COUNT.fetch_add(1, Ordering::SeqCst);
println!(" โ {}", message);
true
} else {
FAIL_COUNT.fetch_add(1, Ordering::SeqCst);
println!(" โ {}", message);
false
}
}
fn test_basic_key_value(conn: &DurableConnection) {
println!("\n๐ Testing Basic Key-Value Operations...");
let _ = conn.put(b"key1", b"value1");
test_assert(true, "Put operation succeeded");
let value = conn.get(b"key1").unwrap();
test_assert(
value.is_some() && value.unwrap() == b"value1",
"Get returns correct value",
);
let missing = conn.get(b"nonexistent").unwrap();
test_assert(missing.is_none(), "Get returns None for missing key");
let _ = conn.delete(b"key1");
let deleted = conn.get(b"key1").unwrap();
test_assert(deleted.is_none(), "Delete removes key");
}
fn test_path_operations(conn: &DurableConnection) {
println!("\n๐๏ธ Testing Path Operations...");
let _ = conn.put(b"users/alice/email", b"alice@example.com");
test_assert(true, "put_path succeeded");
let email = conn.get(b"users/alice/email").unwrap();
test_assert(
email.is_some() && email.unwrap() == b"alice@example.com",
"get_path retrieves correct value",
);
let _ = conn.put(b"users/bob/profile/name", b"Bob");
let name = conn.get(b"users/bob/profile/name").unwrap();
test_assert(
name.is_some() && name.unwrap() == b"Bob",
"get_path handles multiple segments",
);
let missing = conn.get(b"users/charlie/email").unwrap();
test_assert(missing.is_none(), "get_path returns None for missing path");
}
fn test_prefix_scanning(conn: &DurableConnection) {
println!("\n๐ Testing Prefix Scanning...");
let _ = conn.put(b"tenants/acme/users/1", br#"{"name":"Alice"}"#);
let _ = conn.put(b"tenants/acme/users/2", br#"{"name":"Bob"}"#);
let _ = conn.put(b"tenants/acme/orders/1", br#"{"total":100}"#);
let _ = conn.put(b"tenants/globex/users/1", br#"{"name":"Charlie"}"#);
let acme_results = conn.scan(b"tenants/acme/").unwrap();
test_assert(
acme_results.len() == 3,
&format!("Scan returns 3 ACME items (got {})", acme_results.len()),
);
let globex_results = conn.scan(b"tenants/globex/").unwrap();
test_assert(
globex_results.len() == 1,
&format!("Scan returns 1 Globex item (got {})", globex_results.len()),
);
if !acme_results.is_empty() {
test_assert(
!acme_results[0].0.is_empty() && !acme_results[0].1.is_empty(),
"Scan results have key and value",
);
}
}
fn test_transactions(conn: &DurableConnection) {
println!("\n๐ณ Testing Transactions...");
let _ = conn.begin_txn();
test_assert(true, "Transaction began");
let _ = conn.put(b"tx_key1", b"tx_value1");
let _ = conn.put(b"tx_key2", b"tx_value2");
let result = conn.commit_txn();
test_assert(result.is_ok(), "Transaction commits successfully");
let value1 = conn.get(b"tx_key1").unwrap();
let value2 = conn.get(b"tx_key2").unwrap();
test_assert(
value1.is_some() && value2.is_some(),
"Transaction data persisted",
);
}
fn test_empty_value_handling(conn: &DurableConnection) {
println!("\n๐ Testing Empty Value Handling...");
let missing = conn.get(b"truly-missing-key-test").unwrap();
test_assert(missing.is_none(), "Missing key returns None");
println!(" โน๏ธ Note: Empty values and missing keys both return None (protocol limitation)");
}
fn main() {
let test_dir = "./test-data-comprehensive-rust";
if Path::new(test_dir).exists() {
let _ = fs::remove_dir_all(test_dir);
}
println!("๐งช SochDB Rust SDK Comprehensive Feature Test\n");
println!("Testing all features mentioned in README...\n");
println!("{}", "=".repeat(60));
let conn = DurableConnection::open(test_dir).expect("Failed to open connection");
test_basic_key_value(&conn);
test_path_operations(&conn);
test_prefix_scanning(&conn);
test_transactions(&conn);
test_empty_value_handling(&conn);
drop(conn);
let _ = fs::remove_dir_all(test_dir);
let total = TEST_COUNT.load(Ordering::SeqCst);
let pass = PASS_COUNT.load(Ordering::SeqCst);
let fail = FAIL_COUNT.load(Ordering::SeqCst);
println!("\n{}", "=".repeat(60));
println!("\n๐ Test Results:");
println!(" Total: {}", total);
println!(" โ Pass: {}", pass);
println!(" โ Fail: {}", fail);
println!(
" Success Rate: {:.1}%",
(pass as f64 / total as f64) * 100.0
);
if fail == 0 {
println!("\nโ
All tests passed! Rust SDK is working correctly.\n");
std::process::exit(0);
} else {
println!("\nโ {} test(s) failed. See details above.\n", fail);
std::process::exit(1);
}
}