mod jidoka;
mod scheduler;
mod stress;
mod visual;
pub use visual::{
BufferRenderer, ColorPalette, GoldenBaseline, PixelDiffResult, Rgb, VisualRegressionConfig,
};
pub use stress::{
StressAnomaly, StressAnomalyKind, StressResult, StressTestConfig, StressThresholds,
};
pub use jidoka::{JidokaAction, JidokaCondition, JidokaError, JidokaGuard};
pub use scheduler::{
BackendCategory, BackendSelector, BackendTolerance, HeijunkaScheduler, NeedsSeed, Ready,
SimTestConfig, SimTestConfigBuilder, SimulationTest,
};
#[cfg(test)]
pub use simular::engine::rng::SimRng;
#[cfg(test)]
mod tests {
use super::*;
use crate::Backend;
#[test]
fn test_simrng_reproducibility() {
let mut rng1 = SimRng::new(42);
let mut rng2 = SimRng::new(42);
let seq1: Vec<f64> = (0..100).map(|_| rng1.gen_f64()).collect();
let seq2: Vec<f64> = (0..100).map(|_| rng2.gen_f64()).collect();
assert_eq!(seq1, seq2, "Same seed must produce identical sequences");
}
#[test]
fn test_simrng_different_seeds() {
let mut rng1 = SimRng::new(42);
let mut rng2 = SimRng::new(43);
let seq1: Vec<f64> = (0..100).map(|_| rng1.gen_f64()).collect();
let seq2: Vec<f64> = (0..100).map(|_| rng2.gen_f64()).collect();
assert_ne!(seq1, seq2, "Different seeds must produce different sequences");
}
#[test]
fn test_simrng_partitioning() {
let mut rng = SimRng::new(42);
let partitions = rng.partition(4);
assert_eq!(partitions.len(), 4);
let mut seqs: Vec<Vec<f64>> = Vec::new();
for mut p in partitions {
seqs.push((0..10).map(|_| p.gen_f64()).collect());
}
for i in 0..seqs.len() {
for j in (i + 1)..seqs.len() {
assert_ne!(seqs[i], seqs[j], "Partitions must be independent");
}
}
}
#[test]
fn test_simrng_gen_f32_for_trueno() {
let mut rng = SimRng::new(42);
let test_data: Vec<f32> = (0..1000).map(|_| rng.gen_f64() as f32).collect();
for v in &test_data {
assert!(v.is_finite(), "Generated value should be finite");
assert!(*v >= 0.0 && *v < 1.0, "Value should be in [0, 1)");
}
}
#[test]
fn test_full_simulation_workflow() {
let config = SimTestConfig::builder()
.seed(42)
.tolerance(BackendTolerance::default())
.backends(vec![Backend::Scalar, Backend::AVX2])
.input_sizes(vec![100])
.cycles(2)
.build();
let mut scheduler = config.create_scheduler();
let nan_guard = JidokaGuard::nan_guard("simulation_test");
let mut test_count = 0;
while let Some(test) = scheduler.next_test() {
let mut rng = SimRng::new(test.seed);
let data: Vec<f32> = (0..test.input_size).map(|_| rng.gen_f64() as f32).collect();
let result = nan_guard.check_output(&data);
assert!(result.is_ok(), "Generated data should not contain NaN");
test_count += 1;
}
assert_eq!(test_count, 4);
}
}
#[cfg(test)]
mod proptests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_nan_detection_complete(values in prop::collection::vec(-1000.0f32..1000.0, 0..100)) {
let guard = JidokaGuard::nan_guard("test");
let result = guard.check_output(&values);
prop_assert!(result.is_ok());
}
}
}