Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
116
examples/exo-ai-2025/tests/common/assertions.rs
Normal file
116
examples/exo-ai-2025/tests/common/assertions.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
//! Custom assertions for integration tests
|
||||
//!
|
||||
//! Provides domain-specific assertions for cognitive substrate testing.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
/// Assert two embeddings are approximately equal (within epsilon)
|
||||
pub fn assert_embeddings_approx_equal(a: &[f32], b: &[f32], epsilon: f32) {
|
||||
assert_eq!(
|
||||
a.len(),
|
||||
b.len(),
|
||||
"Embeddings have different dimensions: {} vs {}",
|
||||
a.len(),
|
||||
b.len()
|
||||
);
|
||||
|
||||
for (i, (av, bv)) in a.iter().zip(b.iter()).enumerate() {
|
||||
let diff = (av - bv).abs();
|
||||
assert!(
|
||||
diff < epsilon,
|
||||
"Embedding mismatch at index {}: |{} - {}| = {} >= {}",
|
||||
i,
|
||||
av,
|
||||
bv,
|
||||
diff,
|
||||
epsilon
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert similarity scores are in descending order
|
||||
pub fn assert_scores_descending(scores: &[f32]) {
|
||||
for window in scores.windows(2) {
|
||||
assert!(
|
||||
window[0] >= window[1],
|
||||
"Scores not in descending order: {} < {}",
|
||||
window[0],
|
||||
window[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert causal ordering is respected
|
||||
pub fn assert_causal_order(results: &[String], expected_order: &[String]) {
|
||||
// TODO: Implement once CausalResult type exists
|
||||
// Verify results respect causal dependencies
|
||||
assert_eq!(results.len(), expected_order.len(), "Result count mismatch");
|
||||
}
|
||||
|
||||
/// Assert CRDT states are convergent
|
||||
pub fn assert_crdt_convergence(state1: &str, state2: &str) {
|
||||
// TODO: Implement once CRDT types exist
|
||||
// Verify eventual consistency
|
||||
assert_eq!(state1, state2, "CRDT states did not converge");
|
||||
}
|
||||
|
||||
/// Assert topological invariants match expected values
|
||||
pub fn assert_betti_numbers(betti: &[usize], expected: &[usize]) {
|
||||
assert_eq!(
|
||||
betti.len(),
|
||||
expected.len(),
|
||||
"Betti number dimension mismatch"
|
||||
);
|
||||
|
||||
for (i, (actual, exp)) in betti.iter().zip(expected.iter()).enumerate() {
|
||||
assert_eq!(
|
||||
actual, exp,
|
||||
"Betti number b_{} mismatch: {} != {}",
|
||||
i, actual, exp
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert consensus proof is valid
|
||||
pub fn assert_valid_consensus_proof(proof: &str, threshold: usize) {
|
||||
// TODO: Implement once CommitProof type exists
|
||||
// Verify proof has sufficient signatures
|
||||
assert!(
|
||||
!proof.is_empty(),
|
||||
"Consensus proof is empty (need {} votes)",
|
||||
threshold
|
||||
);
|
||||
}
|
||||
|
||||
/// Assert temporal ordering is consistent
|
||||
pub fn assert_temporal_order(timestamps: &[u64]) {
|
||||
for window in timestamps.windows(2) {
|
||||
assert!(
|
||||
window[0] <= window[1],
|
||||
"Timestamps not in temporal order: {} > {}",
|
||||
window[0],
|
||||
window[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert pattern is within manifold region
|
||||
pub fn assert_in_manifold_region(embedding: &[f32], center: &[f32], radius: f32) {
|
||||
let distance = euclidean_distance(embedding, center);
|
||||
assert!(
|
||||
distance <= radius,
|
||||
"Pattern outside manifold region: distance {} > radius {}",
|
||||
distance,
|
||||
radius
|
||||
);
|
||||
}
|
||||
|
||||
// Helper: Compute Euclidean distance
|
||||
fn euclidean_distance(a: &[f32], b: &[f32]) -> f32 {
|
||||
assert_eq!(a.len(), b.len());
|
||||
a.iter()
|
||||
.zip(b.iter())
|
||||
.map(|(av, bv)| (av - bv).powi(2))
|
||||
.sum::<f32>()
|
||||
.sqrt()
|
||||
}
|
||||
80
examples/exo-ai-2025/tests/common/fixtures.rs
Normal file
80
examples/exo-ai-2025/tests/common/fixtures.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
//! Test fixtures and data builders
|
||||
//!
|
||||
//! Provides reusable test data and configuration builders.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
/// Generate test embeddings with known patterns
|
||||
pub fn generate_test_embeddings(count: usize, dimensions: usize) -> Vec<Vec<f32>> {
|
||||
// TODO: Implement once exo-core types are available
|
||||
// Generate diverse embeddings for testing
|
||||
// Use deterministic seed for reproducibility
|
||||
|
||||
(0..count)
|
||||
.map(|i| {
|
||||
(0..dimensions)
|
||||
.map(|d| ((i * dimensions + d) as f32).sin())
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Generate clustered embeddings (for testing similarity)
|
||||
pub fn generate_clustered_embeddings(
|
||||
clusters: usize,
|
||||
per_cluster: usize,
|
||||
dimensions: usize,
|
||||
) -> Vec<Vec<f32>> {
|
||||
// TODO: Implement clustering logic
|
||||
// Create distinct clusters in embedding space
|
||||
vec![vec![0.0; dimensions]; clusters * per_cluster]
|
||||
}
|
||||
|
||||
/// Create a test pattern with default values
|
||||
pub fn create_test_pattern(embedding: Vec<f32>) -> String {
|
||||
// TODO: Return actual Pattern once exo-core exists
|
||||
// For now, return placeholder
|
||||
format!("TestPattern({:?})", &embedding[..embedding.len().min(3)])
|
||||
}
|
||||
|
||||
/// Create a test hypergraph with known topology
|
||||
pub fn create_test_hypergraph() -> String {
|
||||
// TODO: Build test hypergraph once exo-hypergraph exists
|
||||
// Should include:
|
||||
// - Multiple connected components
|
||||
// - Some 1-dimensional holes (cycles)
|
||||
// - Some 2-dimensional holes (voids)
|
||||
"TestHypergraph".to_string()
|
||||
}
|
||||
|
||||
/// Create a causal chain for testing temporal memory
|
||||
pub fn create_causal_chain(length: usize) -> Vec<String> {
|
||||
// TODO: Create linked patterns once exo-temporal exists
|
||||
// Returns pattern IDs in causal order
|
||||
(0..length).map(|i| format!("pattern_{}", i)).collect()
|
||||
}
|
||||
|
||||
/// Create a federation of test nodes
|
||||
pub async fn create_test_federation(node_count: usize) -> Vec<String> {
|
||||
// TODO: Implement once exo-federation exists
|
||||
// Returns federation node handles
|
||||
(0..node_count)
|
||||
.map(|i| format!("node_{}", i))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Default test configuration
|
||||
pub fn default_test_config() -> TestConfig {
|
||||
TestConfig {
|
||||
timeout_ms: 5000,
|
||||
log_level: "info".to_string(),
|
||||
seed: 42,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TestConfig {
|
||||
pub timeout_ms: u64,
|
||||
pub log_level: String,
|
||||
pub seed: u64,
|
||||
}
|
||||
130
examples/exo-ai-2025/tests/common/helpers.rs
Normal file
130
examples/exo-ai-2025/tests/common/helpers.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
//! Test helper functions
|
||||
//!
|
||||
//! Provides utility functions for integration testing.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
/// Run async test with timeout
|
||||
pub async fn with_timeout<F, T>(duration: Duration, future: F) -> Result<T, String>
|
||||
where
|
||||
F: std::future::Future<Output = T>,
|
||||
{
|
||||
match timeout(duration, future).await {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(format!("Test timed out after {:?}", duration)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize test logger
|
||||
pub fn init_test_logger() {
|
||||
// Initialize tracing/logging for tests
|
||||
// Only initialize once
|
||||
let _ = env_logger::builder()
|
||||
.is_test(true)
|
||||
.filter_level(log::LevelFilter::Info)
|
||||
.try_init();
|
||||
}
|
||||
|
||||
/// Generate deterministic random data for testing
|
||||
pub fn deterministic_random_vec(seed: u64, len: usize) -> Vec<f32> {
|
||||
// Simple LCG for deterministic "random" numbers
|
||||
let mut state = seed;
|
||||
(0..len)
|
||||
.map(|_| {
|
||||
state = state.wrapping_mul(1103515245).wrapping_add(12345);
|
||||
((state / 65536) % 32768) as f32 / 32768.0
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Measure execution time of a function
|
||||
pub async fn measure_async<F, T>(f: F) -> (T, Duration)
|
||||
where
|
||||
F: std::future::Future<Output = T>,
|
||||
{
|
||||
let start = std::time::Instant::now();
|
||||
let result = f.await;
|
||||
let duration = start.elapsed();
|
||||
(result, duration)
|
||||
}
|
||||
|
||||
/// Compare vectors with tolerance
|
||||
pub fn vectors_approx_equal(a: &[f32], b: &[f32], tolerance: f32) -> bool {
|
||||
if a.len() != b.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
a.iter()
|
||||
.zip(b.iter())
|
||||
.all(|(av, bv)| (av - bv).abs() < tolerance)
|
||||
}
|
||||
|
||||
/// Cosine similarity
|
||||
pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
|
||||
assert_eq!(a.len(), b.len());
|
||||
|
||||
let dot_product: f32 = a.iter().zip(b.iter()).map(|(av, bv)| av * bv).sum();
|
||||
let norm_a: f32 = a.iter().map(|av| av * av).sum::<f32>().sqrt();
|
||||
let norm_b: f32 = b.iter().map(|bv| bv * bv).sum::<f32>().sqrt();
|
||||
|
||||
if norm_a == 0.0 || norm_b == 0.0 {
|
||||
0.0
|
||||
} else {
|
||||
dot_product / (norm_a * norm_b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait for async condition to become true
|
||||
pub async fn wait_for_condition<F>(
|
||||
mut condition: F,
|
||||
timeout_duration: Duration,
|
||||
check_interval: Duration,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
F: FnMut() -> bool,
|
||||
{
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
while start.elapsed() < timeout_duration {
|
||||
if condition() {
|
||||
return Ok(());
|
||||
}
|
||||
tokio::time::sleep(check_interval).await;
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"Condition not met within {:?}",
|
||||
timeout_duration
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a temporary test directory
|
||||
pub fn create_temp_test_dir() -> std::io::Result<std::path::PathBuf> {
|
||||
let temp_dir = std::env::temp_dir().join(format!("exo-test-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
Ok(temp_dir)
|
||||
}
|
||||
|
||||
/// Clean up test resources
|
||||
pub async fn cleanup_test_resources(path: &std::path::Path) -> std::io::Result<()> {
|
||||
if path.exists() {
|
||||
tokio::fs::remove_dir_all(path).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Mock UUID for tests (replace with actual uuid crate when available)
|
||||
mod uuid {
|
||||
pub struct Uuid;
|
||||
impl Uuid {
|
||||
pub fn new_v4() -> String {
|
||||
format!("{:016x}", std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos())
|
||||
}
|
||||
}
|
||||
}
|
||||
12
examples/exo-ai-2025/tests/common/mod.rs
Normal file
12
examples/exo-ai-2025/tests/common/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
//! Common test utilities and helpers for integration tests
|
||||
//!
|
||||
//! This module provides shared functionality across all integration tests.
|
||||
|
||||
pub mod fixtures;
|
||||
pub mod assertions;
|
||||
pub mod helpers;
|
||||
|
||||
// Re-export commonly used items
|
||||
pub use fixtures::*;
|
||||
pub use assertions::*;
|
||||
pub use helpers::*;
|
||||
Reference in New Issue
Block a user