pub mod unit_tests;
pub mod integration_tests;
pub mod performance_tests;
pub mod concurrent_tests;
pub mod error_tests;
pub mod utils_tests;
pub mod mdx_encoding_test;
pub use unit_tests::*;
pub use integration_tests::*;
pub use performance_tests::*;
pub use concurrent_tests::*;
pub use error_tests::*;
pub use utils_tests::*;
pub use mdx_encoding_test::*;
use crate::traits::{Dict, DictConfig, DictError, Result, BatchResult, SearchResult};
use crate::util::test_utils::{generate_test_entries, MockDictBuilder};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
pub struct TestSetup {
pub config: DictConfig,
pub entries: Vec<(String, Vec<u8>)>,
pub mock_builder: MockDictBuilder,
}
impl TestSetup {
pub fn new() -> Self {
let config = DictConfig {
load_btree: true,
load_fts: true,
use_mmap: false, cache_size: 100,
batch_size: 50,
encoding: None,
build_btree: true,
build_fts: true,
};
let entries = generate_test_entries(1000);
let mock_builder = MockDictBuilder::new();
Self {
config,
entries,
mock_builder,
}
}
pub fn with_entries(count: usize) -> Self {
let mut setup = Self::new();
setup.entries = generate_test_entries(count);
setup
}
pub fn with_config(config: DictConfig) -> Self {
let entries = generate_test_entries(1000);
let mock_builder = MockDictBuilder::new();
Self {
config,
entries,
mock_builder,
}
}
}
impl Default for TestSetup {
fn default() -> Self {
Self::new()
}
}
pub struct TestAssertions;
impl TestAssertions {
pub fn assert_ok_result<T, E>(result: Result<T>, expected_value: T)
where
T: PartialEq + std::fmt::Debug,
E: std::fmt::Debug,
{
let actual_value = result.expect("Expected Ok result");
assert_eq!(actual_value, expected_value);
}
pub fn assert_error<T, E>(result: Result<T>, expected_error_type: E)
where
E: PartialEq + std::fmt::Debug,
{
let _error = result.expect_err("Expected error result");
}
pub fn assert_search_results_similar(
results: &Vec<SearchResult>,
expected_count: usize,
expected_keywords: &[&str],
) {
assert_eq!(results.len(), expected_count);
for result in results {
let word_matches = expected_keywords.iter().any(|keyword| result.word.contains(keyword));
assert!(word_matches, "Result word '{}' should match expected keywords", result.word);
}
}
pub fn assert_batch_results(
results: &Vec<BatchResult>,
expected_keys: &[String],
expected_hit_rate: f32,
) {
assert_eq!(results.len(), expected_keys.len());
let mut hit_count = 0;
for result in results {
if expected_keys.contains(&result.word) {
assert!(result.entry.is_some(), "Should find entry for '{}'", result.word);
hit_count += 1;
}
}
let actual_hit_rate = hit_count as f32 / results.len() as f32;
assert!(actual_hit_rate >= expected_hit_rate,
"Hit rate {} should be >= {}", actual_hit_rate, expected_hit_rate);
}
}
pub struct TestDataGenerators;
impl TestDataGenerators {
pub fn generate_patterned_data(pattern: &str, count: usize) -> Vec<(String, Vec<u8>)> {
let mut entries = Vec::new();
for i in 0..count {
let key = format!("{}_{}", pattern, i);
let content = format!("Content for {} item {} with detailed explanation.", pattern, i);
entries.push((key, content.into_bytes()));
}
entries
}
pub fn generate_unicode_data() -> Vec<(String, Vec<u8>)> {
vec![
("hello".to_string(), "Hello world! 🌍".into()),
("你好".to_string(), "Chinese greeting".into()),
("привет".to_string(), "Russian greeting".into()),
("مرحبا".to_string(), "Arabic greeting".into()),
("こんにちは".to_string(), "Japanese greeting".into()),
]
}
pub fn generate_large_dataset(size: usize) -> Vec<(String, Vec<u8>)> {
let mut entries = Vec::with_capacity(size);
for i in 0..size {
let key = format!("large_entry_{:08}", i);
let content = format!(
"This is a large content entry number {} for performance testing. \
It contains substantial text to simulate real dictionary entries with \
multiple sentences and varied content length for comprehensive testing.",
i
);
entries.push((key, content.into_bytes()));
}
entries
}
pub fn generate_varied_size_data() -> HashMap<String, Vec<u8>> {
let mut data = HashMap::new();
data.insert("small".to_string(), b"Small entry".to_vec());
data.insert("medium".to_string(),
"Medium length entry with some content for testing purposes.".into());
let large_content = "Large ".repeat(1000);
data.insert("large".to_string(), large_content.into_bytes());
data
}
}
pub struct MemoryTestUtils;
impl MemoryTestUtils {
pub fn estimate_data_memory_size(entries: &[(String, Vec<u8>)]) -> usize {
let mut total = 0;
for (key, value) in entries {
total += std::mem::size_of_val(key);
total += std::mem::size_of_val(value);
total += key.len();
total += value.len();
}
total
}
pub fn create_memory_pressure_data(entry_count: usize, entry_size: usize) -> Vec<(String, Vec<u8>)> {
let mut entries = Vec::with_capacity(entry_count);
for i in 0..entry_count {
let key = format!("memory_test_{:06}", i);
let value = vec![0u8; entry_size];
entries.push((key, value));
}
entries
}
}
pub struct ConcurrentTestUtils;
impl ConcurrentTestUtils {
pub fn run_concurrent_operations<F, T>(
operation_count: usize,
thread_count: usize,
operation: F,
) -> Vec<T>
where
F: Fn(usize) -> T + Send + Sync + 'static,
T: Send + 'static,
{
use std::thread;
use std::sync::Barrier;
let barrier = Arc::new(Barrier::new(thread_count));
let mut handles = vec![];
for thread_id in 0..thread_count {
let barrier = Arc::clone(&barrier);
let handle = thread::spawn(move || {
barrier.wait();
operation(thread_id)
});
handles.push(handle);
}
handles.into_iter()
.flat_map(|handle| handle.join().unwrap())
.collect()
}
pub fn test_concurrent_reads<D: Dict<String> + Send + Sync>(
dict: &D,
read_count: usize,
) -> Vec<Result<Vec<u8>>> {
let mut results = Vec::with_capacity(read_count);
for i in 0..read_count {
let key = format!("test_key_{:06}", i % 100); results.push(dict.get(&key));
}
results
}
}
pub struct PerformanceProfiler;
impl PerformanceProfiler {
pub fn profile_operation<F, T>(
name: &str,
iterations: usize,
operation: F,
) -> (T, std::time::Duration)
where
F: Fn() -> T,
{
let start = std::time::Instant::now();
let result = operation();
let duration = start.elapsed();
println!("{}: {} iterations in {:?}", name, iterations, duration);
(result, duration)
}
pub fn benchmark_lookups<D: Dict<String> + Send + Sync>(
dict: &D,
key_count: usize,
iterations: usize,
) -> std::time::Duration {
let start = std::time::Instant::now();
for _ in 0..iterations {
for i in 0..key_count {
let key = format!("word_{:06}", i);
let _ = dict.get(&key);
}
}
start.elapsed()
}
}
pub use crate::util::test_utils::{
generate_test_entries, generate_patterned_entries, temp_dir, cleanup_temp_dir,
create_test_dict, generate_unicode_entries, test_config, MockDictBuilder,
};