use super::experiment::ExperimentSpec;
use super::model_card::EquationModelCard;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EddViolation {
pub code: String,
pub message: String,
pub severity: ViolationSeverity,
pub context: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ViolationSeverity {
Info,
Warning,
Error,
Critical,
}
impl EddViolation {
#[must_use]
pub fn new(code: &str, message: &str, severity: ViolationSeverity) -> Self {
Self {
code: code.to_string(),
message: message.to_string(),
severity,
context: None,
}
}
#[must_use]
pub fn with_context(mut self, context: &str) -> Self {
self.context = Some(context.to_string());
self
}
}
pub type EddResult<T> = Result<T, EddViolation>;
#[derive(Debug, Default)]
pub struct EddValidator {
violations: Vec<EddViolation>,
#[allow(dead_code)]
jidoka_mode: bool,
}
impl EddValidator {
#[must_use]
pub fn new() -> Self {
Self {
violations: Vec::new(),
jidoka_mode: true,
}
}
#[must_use]
pub fn lenient() -> Self {
Self {
violations: Vec::new(),
jidoka_mode: false,
}
}
pub fn clear(&mut self) {
self.violations.clear();
}
#[must_use]
pub fn violations(&self) -> &[EddViolation] {
&self.violations
}
#[must_use]
pub fn has_critical_violations(&self) -> bool {
self.violations
.iter()
.any(|v| v.severity == ViolationSeverity::Critical)
}
#[must_use]
pub fn has_errors(&self) -> bool {
self.violations
.iter()
.any(|v| v.severity >= ViolationSeverity::Error)
}
pub fn validate_simulation_has_emc(&self, emc: Option<&EquationModelCard>) -> EddResult<()> {
match emc {
Some(_) => Ok(()),
None => Err(EddViolation::new(
"EDD-01",
"Simulation must have an Equation Model Card (Pillar 1: Prove It)",
ViolationSeverity::Critical,
)),
}
}
pub fn validate_emc_has_equation(&self, emc: &EquationModelCard) -> EddResult<()> {
if emc.equation.is_empty() {
Err(EddViolation::new(
"EDD-02",
"EMC must have a governing equation in LaTeX format",
ViolationSeverity::Critical,
))
} else {
Ok(())
}
}
pub fn validate_emc_has_citation(&self, emc: &EquationModelCard) -> EddResult<()> {
if emc.citation.authors.is_empty() {
Err(EddViolation::new(
"EDD-03",
"EMC must have a peer-reviewed citation",
ViolationSeverity::Critical,
))
} else {
Ok(())
}
}
pub fn validate_emc_has_tests(&self, emc: &EquationModelCard) -> EddResult<()> {
if emc.verification_tests.is_empty() {
Err(EddViolation::new(
"EDD-04",
"EMC must have at least one verification test (Pillar 2: Fail It)",
ViolationSeverity::Critical,
))
} else {
Ok(())
}
}
pub fn validate_emc(&mut self, emc: &EquationModelCard) -> Result<(), Vec<EddViolation>> {
let mut violations = Vec::new();
if let Err(v) = self.validate_emc_has_equation(emc) {
violations.push(v);
}
if let Err(v) = self.validate_emc_has_citation(emc) {
violations.push(v);
}
if let Err(v) = self.validate_emc_has_tests(emc) {
violations.push(v);
}
if violations.is_empty() {
Ok(())
} else {
self.violations.extend(violations.clone());
Err(violations)
}
}
pub fn validate_seed_specified(&self, seed: Option<u64>) -> EddResult<()> {
match seed {
Some(_) => Ok(()),
None => Err(EddViolation::new(
"EDD-05",
"Experiment must have an explicit seed (Pillar 3: Seed It)",
ViolationSeverity::Critical,
)),
}
}
pub fn validate_has_falsification_criteria(&self, spec: &ExperimentSpec) -> EddResult<()> {
if spec.falsification_criteria().is_empty() {
Err(EddViolation::new(
"EDD-06",
"Experiment should have falsification criteria (Pillar 4: Falsify It)",
ViolationSeverity::Warning,
))
} else {
Ok(())
}
}
pub fn validate_experiment(&mut self, spec: &ExperimentSpec) -> Result<(), Vec<EddViolation>> {
let mut violations = Vec::new();
if let Err(v) = self.validate_seed_specified(Some(spec.seed())) {
violations.push(v);
}
if let Err(v) = self.validate_has_falsification_criteria(spec) {
violations.push(v);
}
if let Err(errs) = spec.validate() {
for err in errs {
violations.push(EddViolation::new("EDD-00", &err, ViolationSeverity::Error));
}
}
if violations
.iter()
.any(|v| v.severity >= ViolationSeverity::Error)
{
self.violations.extend(violations.clone());
Err(violations)
} else {
self.violations.extend(violations);
Ok(())
}
}
pub fn validate_verification_tests<F>(
&mut self,
emc: &EquationModelCard,
evaluator: F,
) -> Result<(), Vec<EddViolation>>
where
F: Fn(&std::collections::HashMap<String, f64>) -> f64,
{
let results = emc.run_verification_tests(evaluator);
let failures: Vec<EddViolation> = results
.into_iter()
.filter(|(_, passed, _)| !passed)
.map(|(name, _, msg)| {
EddViolation::new(
"EDD-07",
&format!("Verification test failed: {name}"),
ViolationSeverity::Critical,
)
.with_context(&msg)
})
.collect();
if failures.is_empty() {
Ok(())
} else {
self.violations.extend(failures.clone());
Err(failures)
}
}
pub fn validate_conservation_law(
&self,
quantity_name: &str,
initial_value: f64,
current_value: f64,
tolerance: f64,
) -> EddResult<()> {
let relative_drift = if initial_value.abs() > f64::EPSILON {
(current_value - initial_value).abs() / initial_value.abs()
} else {
(current_value - initial_value).abs()
};
if relative_drift > tolerance {
Err(EddViolation::new(
"EDD-08",
&format!("Conservation law violated: {quantity_name} drifted beyond tolerance"),
ViolationSeverity::Critical,
).with_context(&format!(
"initial={initial_value:.6e}, current={current_value:.6e}, drift={relative_drift:.6e}, tolerance={tolerance:.6e}"
)))
} else {
Ok(())
}
}
pub fn validate_cross_platform_reproducibility(
&self,
platform_a: &str,
platform_b: &str,
result_a: f64,
result_b: f64,
tolerance: f64,
) -> EddResult<()> {
let diff = (result_a - result_b).abs();
if diff > tolerance {
Err(EddViolation::new(
"EDD-09",
&format!("Cross-platform reproducibility failed: {platform_a} vs {platform_b}"),
ViolationSeverity::Error,
)
.with_context(&format!(
"{platform_a}={result_a:.15e}, {platform_b}={result_b:.15e}, diff={diff:.15e}"
)))
} else {
Ok(())
}
}
pub fn validate_tdd_compliance(
&self,
implementation_name: &str,
has_test_file: bool,
test_count: usize,
) -> EddResult<()> {
if !has_test_file {
return Err(EddViolation::new(
"EDD-10",
&format!("Implementation '{implementation_name}' has no test file"),
ViolationSeverity::Critical,
)
.with_context("EDD requires TDD: write failing tests BEFORE implementation"));
}
if test_count == 0 {
return Err(EddViolation::new(
"EDD-10",
&format!("Implementation '{implementation_name}' has no tests"),
ViolationSeverity::Critical,
)
.with_context("Every implementation must have at least one test"));
}
Ok(())
}
pub fn validate_yaml_only_config(
has_yaml_config: bool,
hardcoded_params: &[String],
) -> Result<(), EddViolation> {
if !has_yaml_config {
return Err(EddViolation::new(
"EDD-13",
"Simulation requires YAML configuration",
ViolationSeverity::Critical,
)
.with_context("Three Pillars: Pillar 2 requires YAML-only configuration"));
}
if !hardcoded_params.is_empty() {
return Err(EddViolation::new(
"EDD-13",
&format!(
"Hardcoded parameters detected: {}",
hardcoded_params.join(", ")
),
ViolationSeverity::Critical,
)
.with_context("All parameters must come from YAML configuration"));
}
Ok(())
}
pub fn validate_probar_tui(
probar_tests_passed: bool,
test_count: usize,
) -> Result<(), EddViolation> {
if test_count == 0 {
return Err(EddViolation::new(
"EDD-14",
"No Probar TUI tests found",
ViolationSeverity::Critical,
)
.with_context("Three Pillars: Pillar 3 requires Probar TUI verification"));
}
if !probar_tests_passed {
return Err(EddViolation::new(
"EDD-14",
"Probar TUI tests failed",
ViolationSeverity::Critical,
)
.with_context("All Probar TUI tests must pass before release"));
}
Ok(())
}
pub fn validate_probar_wasm(
probar_wasm_passed: bool,
test_count: usize,
) -> Result<(), EddViolation> {
if test_count == 0 {
return Err(EddViolation::new(
"EDD-15",
"No Probar WASM tests found",
ViolationSeverity::Critical,
)
.with_context("Three Pillars: Pillar 3 requires Probar WASM verification"));
}
if !probar_wasm_passed {
return Err(EddViolation::new(
"EDD-15",
"Probar WASM tests failed",
ViolationSeverity::Critical,
)
.with_context("All Probar WASM tests must pass before release"));
}
Ok(())
}
#[must_use]
#[allow(clippy::fn_params_excessive_bools)]
pub fn validate_three_pillars(
z3_proofs_passed: bool,
has_yaml_config: bool,
seed_specified: bool,
probar_tui_passed: bool,
probar_tui_test_count: usize,
probar_wasm_passed: bool,
probar_wasm_test_count: usize,
) -> Vec<EddViolation> {
let mut violations = Vec::new();
if !z3_proofs_passed {
violations.push(
EddViolation::new(
"EDD-11",
"Z3 equation proofs did not pass",
ViolationSeverity::Critical,
)
.with_context("Pillar 1: All equations must be provable with Z3"),
);
}
if !has_yaml_config {
violations.push(
EddViolation::new(
"EDD-13",
"No YAML configuration provided",
ViolationSeverity::Critical,
)
.with_context("Pillar 2: All configuration must be YAML-based"),
);
}
if !seed_specified {
violations.push(
EddViolation::new(
"EDD-05",
"No seed specified in configuration",
ViolationSeverity::Critical,
)
.with_context("Pillar 2: Seed must be explicitly specified in YAML"),
);
}
if let Err(e) = Self::validate_probar_tui(probar_tui_passed, probar_tui_test_count) {
violations.push(e);
}
if let Err(e) = Self::validate_probar_wasm(probar_wasm_passed, probar_wasm_test_count) {
violations.push(e);
}
violations
}
}
#[derive(Debug)]
pub struct EddComplianceSummary {
pub total_violations: usize,
pub critical_count: usize,
pub error_count: usize,
pub warning_count: usize,
pub info_count: usize,
pub compliant: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TpsGrade {
ToyotaStandard,
KaizenRequired,
AndonWarning,
StopTheLine,
}
impl TpsGrade {
#[must_use]
pub fn from_score(score: f64) -> Self {
if score >= 0.95 {
Self::ToyotaStandard
} else if score >= 0.85 {
Self::KaizenRequired
} else if score >= 0.70 {
Self::AndonWarning
} else {
Self::StopTheLine
}
}
#[must_use]
pub fn from_violations(violations: &[EddViolation], total_checks: usize) -> Self {
if violations
.iter()
.any(|v| v.severity == ViolationSeverity::Critical)
{
return Self::StopTheLine;
}
let error_count = violations
.iter()
.filter(|v| v.severity >= ViolationSeverity::Error)
.count();
if total_checks == 0 {
return Self::ToyotaStandard;
}
let score = 1.0 - (error_count as f64 / total_checks as f64);
Self::from_score(score)
}
#[must_use]
pub const fn decision(&self) -> &'static str {
match self {
Self::ToyotaStandard => "Release OK",
Self::KaizenRequired => "Beta with documented limitations",
Self::AndonWarning => "Significant revision required",
Self::StopTheLine => "Block release",
}
}
#[must_use]
pub const fn score_range(&self) -> &'static str {
match self {
Self::ToyotaStandard => "95-100%",
Self::KaizenRequired => "85-94%",
Self::AndonWarning => "70-84%",
Self::StopTheLine => "<70% or Critical",
}
}
}
impl std::fmt::Display for TpsGrade {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::ToyotaStandard => "Toyota Standard",
Self::KaizenRequired => "Kaizen Required",
Self::AndonWarning => "Andon Warning",
Self::StopTheLine => "STOP THE LINE",
};
write!(f, "{name}")
}
}
#[derive(Debug, Clone)]
pub struct ConvergenceAnalysis {
pub order: f64,
pub expected_order: f64,
pub order_matches: bool,
pub tolerance: f64,
pub extrapolated_value: f64,
pub error_estimates: Vec<f64>,
}
#[must_use]
pub fn richardson_extrapolation(
values: &[f64],
refinement_ratio: f64,
expected_order: f64,
tolerance: f64,
) -> ConvergenceAnalysis {
assert!(
values.len() >= 3,
"Richardson extrapolation requires at least 3 values"
);
let n = values.len();
let r = refinement_ratio;
let mut error_estimates = Vec::with_capacity(n - 1);
for i in 0..n - 1 {
error_estimates.push((values[i] - values[i + 1]).abs());
}
let e1 = (values[n - 3] - values[n - 2]).abs();
let e2 = (values[n - 2] - values[n - 1]).abs();
let order = if e2 > f64::EPSILON && e1 > f64::EPSILON {
(e1 / e2).ln() / r.ln()
} else {
expected_order };
let extrapolated_value = if (r.powf(order) - 1.0).abs() > f64::EPSILON {
values[n - 1] + (values[n - 1] - values[n - 2]) / (r.powf(order) - 1.0)
} else {
values[n - 1]
};
let order_matches = (order - expected_order).abs() <= tolerance;
ConvergenceAnalysis {
order,
expected_order,
order_matches,
tolerance,
extrapolated_value,
error_estimates,
}
}
impl EddComplianceSummary {
#[must_use]
pub fn from_violations(violations: &[EddViolation]) -> Self {
let critical_count = violations
.iter()
.filter(|v| v.severity == ViolationSeverity::Critical)
.count();
let error_count = violations
.iter()
.filter(|v| v.severity == ViolationSeverity::Error)
.count();
let warning_count = violations
.iter()
.filter(|v| v.severity == ViolationSeverity::Warning)
.count();
let info_count = violations
.iter()
.filter(|v| v.severity == ViolationSeverity::Info)
.count();
Self {
total_violations: violations.len(),
critical_count,
error_count,
warning_count,
info_count,
compliant: critical_count == 0 && error_count == 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edd::equation::Citation;
use crate::edd::model_card::EmcBuilder;
#[test]
fn test_validator_new() {
let validator = EddValidator::new();
assert!(validator.violations().is_empty());
}
#[test]
fn test_validate_simulation_has_emc_fails() {
let validator = EddValidator::new();
let result = validator.validate_simulation_has_emc(None);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-01");
assert_eq!(err.severity, ViolationSeverity::Critical);
}
#[test]
fn test_validate_simulation_has_emc_passes() {
let validator = EddValidator::new();
let emc = EmcBuilder::new()
.name("Test")
.equation("x = y")
.citation(Citation::new(&["Test"], "Test", 2024))
.add_verification_test("test", 1.0, 0.1)
.build()
.ok()
.unwrap();
let result = validator.validate_simulation_has_emc(Some(&emc));
assert!(result.is_ok());
}
#[test]
fn test_validate_seed_specified_fails() {
let validator = EddValidator::new();
let result = validator.validate_seed_specified(None);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-05");
}
#[test]
fn test_validate_seed_specified_passes() {
let validator = EddValidator::new();
let result = validator.validate_seed_specified(Some(42));
assert!(result.is_ok());
}
#[test]
fn test_compliance_summary() {
let violations = vec![
EddViolation::new("EDD-01", "test", ViolationSeverity::Critical),
EddViolation::new("EDD-05", "test", ViolationSeverity::Error),
EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
];
let summary = EddComplianceSummary::from_violations(&violations);
assert_eq!(summary.total_violations, 3);
assert_eq!(summary.critical_count, 1);
assert_eq!(summary.error_count, 1);
assert_eq!(summary.warning_count, 1);
assert!(!summary.compliant);
}
#[test]
fn test_compliance_summary_compliant() {
let violations = vec![
EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
EddViolation::new("EDD-00", "test", ViolationSeverity::Info),
];
let summary = EddComplianceSummary::from_violations(&violations);
assert!(summary.compliant);
}
#[test]
fn test_violation_with_context() {
let violation = EddViolation::new("EDD-07", "Test failed", ViolationSeverity::Critical)
.with_context("Expected 10, got 15");
assert!(violation.context.is_some());
assert!(violation.context.unwrap().contains("Expected 10"));
}
#[test]
fn test_validator_collects_violations() {
let mut validator = EddValidator::lenient();
let emc = EquationModelCard {
name: "Test".to_string(),
version: "1.0".to_string(),
equation: String::new(), class: crate::edd::equation::EquationClass::Queueing,
citation: Citation::new(&[], "Test", 2024), references: vec![],
variables: vec![],
verification_tests: vec![], domain_constraints: vec![],
falsification_criteria: vec![],
implementation_notes: vec![],
description: String::new(),
lineage: vec![],
};
let result = validator.validate_emc(&emc);
assert!(result.is_err());
assert!(validator.violations().len() >= 3);
}
#[test]
fn test_has_critical_violations() {
let mut validator = EddValidator::new();
validator.violations.push(EddViolation::new(
"EDD-01",
"test",
ViolationSeverity::Critical,
));
assert!(validator.has_critical_violations());
assert!(validator.has_errors());
}
#[test]
fn test_clear_violations() {
let mut validator = EddValidator::new();
validator.violations.push(EddViolation::new(
"EDD-01",
"test",
ViolationSeverity::Critical,
));
validator.clear();
assert!(validator.violations().is_empty());
}
#[test]
fn test_validate_conservation_law_passes() {
let validator = EddValidator::new();
let result = validator.validate_conservation_law("energy", 100.0, 100.001, 1e-4);
assert!(result.is_ok());
}
#[test]
fn test_validate_conservation_law_fails() {
let validator = EddValidator::new();
let result = validator.validate_conservation_law("energy", 100.0, 110.0, 1e-4);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-08");
assert_eq!(err.severity, ViolationSeverity::Critical);
assert!(err.message.contains("energy"));
}
#[test]
fn test_validate_conservation_law_zero_initial() {
let validator = EddValidator::new();
let result = validator.validate_conservation_law("momentum", 0.0, 0.0001, 1e-4);
assert!(result.is_ok());
let result_fail = validator.validate_conservation_law("momentum", 0.0, 1.0, 1e-4);
assert!(result_fail.is_err());
}
#[test]
fn test_validate_cross_platform_reproducibility_passes() {
let validator = EddValidator::new();
let result = validator.validate_cross_platform_reproducibility(
"x86_64-linux",
"aarch64-darwin",
1.234567890123456,
1.234567890123456,
0.0,
);
assert!(result.is_ok());
}
#[test]
fn test_validate_cross_platform_reproducibility_fails() {
let validator = EddValidator::new();
let result = validator.validate_cross_platform_reproducibility(
"x86_64-linux",
"aarch64-darwin",
1.234567890123456,
1.234567890123999,
1e-15,
);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-09");
assert_eq!(err.severity, ViolationSeverity::Error);
assert!(err.context.is_some());
}
#[test]
fn test_validate_cross_platform_with_tolerance() {
let validator = EddValidator::new();
let result = validator.validate_cross_platform_reproducibility(
"x86_64-linux",
"wasm32",
1.0000000001,
1.0000000002,
1e-9,
);
assert!(result.is_ok());
}
#[test]
fn test_validate_tdd_compliance_passes() {
let validator = EddValidator::new();
let result = validator.validate_tdd_compliance("harmonic_oscillator", true, 5);
assert!(result.is_ok());
}
#[test]
fn test_validate_tdd_compliance_no_test_file() {
let validator = EddValidator::new();
let result = validator.validate_tdd_compliance("new_simulation", false, 0);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-10");
assert!(err.message.contains("no test file"));
}
#[test]
fn test_validate_tdd_compliance_no_tests() {
let validator = EddValidator::new();
let result = validator.validate_tdd_compliance("empty_simulation", true, 0);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-10");
assert!(err.message.contains("no tests"));
}
#[test]
fn test_tps_grade_from_score_toyota_standard() {
assert_eq!(TpsGrade::from_score(1.0), TpsGrade::ToyotaStandard);
assert_eq!(TpsGrade::from_score(0.95), TpsGrade::ToyotaStandard);
assert_eq!(TpsGrade::from_score(0.99), TpsGrade::ToyotaStandard);
}
#[test]
fn test_tps_grade_from_score_kaizen_required() {
assert_eq!(TpsGrade::from_score(0.94), TpsGrade::KaizenRequired);
assert_eq!(TpsGrade::from_score(0.85), TpsGrade::KaizenRequired);
assert_eq!(TpsGrade::from_score(0.90), TpsGrade::KaizenRequired);
}
#[test]
fn test_tps_grade_from_score_andon_warning() {
assert_eq!(TpsGrade::from_score(0.84), TpsGrade::AndonWarning);
assert_eq!(TpsGrade::from_score(0.70), TpsGrade::AndonWarning);
assert_eq!(TpsGrade::from_score(0.75), TpsGrade::AndonWarning);
}
#[test]
fn test_tps_grade_from_score_stop_the_line() {
assert_eq!(TpsGrade::from_score(0.69), TpsGrade::StopTheLine);
assert_eq!(TpsGrade::from_score(0.0), TpsGrade::StopTheLine);
assert_eq!(TpsGrade::from_score(0.50), TpsGrade::StopTheLine);
}
#[test]
fn test_tps_grade_from_violations_critical_always_stops() {
let violations = vec![EddViolation::new(
"EDD-01",
"test",
ViolationSeverity::Critical,
)];
assert_eq!(
TpsGrade::from_violations(&violations, 100),
TpsGrade::StopTheLine
);
}
#[test]
fn test_tps_grade_from_violations_no_violations() {
let violations: Vec<EddViolation> = vec![];
assert_eq!(
TpsGrade::from_violations(&violations, 10),
TpsGrade::ToyotaStandard
);
}
#[test]
fn test_tps_grade_from_violations_warnings_ignored() {
let violations = vec![
EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
];
assert_eq!(
TpsGrade::from_violations(&violations, 10),
TpsGrade::ToyotaStandard
);
}
#[test]
fn test_tps_grade_decision_text() {
assert_eq!(TpsGrade::ToyotaStandard.decision(), "Release OK");
assert_eq!(
TpsGrade::KaizenRequired.decision(),
"Beta with documented limitations"
);
assert_eq!(
TpsGrade::AndonWarning.decision(),
"Significant revision required"
);
assert_eq!(TpsGrade::StopTheLine.decision(), "Block release");
}
#[test]
fn test_tps_grade_display() {
assert_eq!(format!("{}", TpsGrade::ToyotaStandard), "Toyota Standard");
assert_eq!(format!("{}", TpsGrade::StopTheLine), "STOP THE LINE");
}
#[test]
fn test_validate_yaml_only_config_passes() {
let result = EddValidator::validate_yaml_only_config(true, &[]);
assert!(result.is_ok());
}
#[test]
fn test_validate_yaml_only_config_no_yaml() {
let result = EddValidator::validate_yaml_only_config(false, &[]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-13");
assert_eq!(err.severity, ViolationSeverity::Critical);
}
#[test]
fn test_validate_yaml_only_config_hardcoded_params() {
let hardcoded = vec!["omega".to_string(), "amplitude".to_string()];
let result = EddValidator::validate_yaml_only_config(true, &hardcoded);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-13");
assert!(err.message.contains("omega"));
assert!(err.message.contains("amplitude"));
}
#[test]
fn test_validate_probar_tui_passes() {
let result = EddValidator::validate_probar_tui(true, 5);
assert!(result.is_ok());
}
#[test]
fn test_validate_probar_tui_no_tests() {
let result = EddValidator::validate_probar_tui(true, 0);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-14");
assert_eq!(err.severity, ViolationSeverity::Critical);
}
#[test]
fn test_validate_probar_tui_failed() {
let result = EddValidator::validate_probar_tui(false, 5);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-14");
assert!(err.message.contains("failed"));
}
#[test]
fn test_validate_probar_wasm_passes() {
let result = EddValidator::validate_probar_wasm(true, 3);
assert!(result.is_ok());
}
#[test]
fn test_validate_probar_wasm_no_tests() {
let result = EddValidator::validate_probar_wasm(true, 0);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-15");
assert_eq!(err.severity, ViolationSeverity::Critical);
}
#[test]
fn test_validate_probar_wasm_failed() {
let result = EddValidator::validate_probar_wasm(false, 3);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.code, "EDD-15");
assert!(err.message.contains("failed"));
}
#[test]
fn test_validate_three_pillars_all_pass() {
let violations = EddValidator::validate_three_pillars(
true, true, true, true, 5, true, 3, );
assert!(violations.is_empty(), "All pillars should pass");
}
#[test]
fn test_validate_three_pillars_z3_fails() {
let violations = EddValidator::validate_three_pillars(
false, true, true, true, 5, true, 3,
);
assert_eq!(violations.len(), 1);
assert_eq!(violations[0].code, "EDD-11");
}
#[test]
fn test_validate_three_pillars_yaml_fails() {
let violations = EddValidator::validate_three_pillars(
true, false, true, true, 5, true, 3,
);
assert_eq!(violations.len(), 1);
assert_eq!(violations[0].code, "EDD-13");
}
#[test]
fn test_validate_three_pillars_seed_missing() {
let violations = EddValidator::validate_three_pillars(
true, true, false, true, 5, true, 3,
);
assert_eq!(violations.len(), 1);
assert_eq!(violations[0].code, "EDD-05");
}
#[test]
fn test_validate_three_pillars_probar_fails() {
let violations = EddValidator::validate_three_pillars(
true, true, true, false, 5, false, 3,
);
assert_eq!(violations.len(), 2);
assert!(violations.iter().any(|v| v.code == "EDD-14"));
assert!(violations.iter().any(|v| v.code == "EDD-15"));
}
#[test]
fn test_validate_three_pillars_multiple_failures() {
let violations = EddValidator::validate_three_pillars(
false, false, false, false, 0, false, 0, );
assert!(
violations.len() >= 4,
"Expected multiple violations: {:?}",
violations
);
}
#[test]
fn test_richardson_extrapolation_second_order() {
let values = vec![
2.0, 1.25, 1.0625, ];
let result = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
assert!(
(result.order - 2.0).abs() < 0.1,
"Expected order ~2.0, got {}",
result.order
);
assert!(result.order_matches);
assert!(
(result.extrapolated_value - 1.0).abs() < 0.1,
"Expected extrapolated ~1.0, got {}",
result.extrapolated_value
);
}
#[test]
fn test_richardson_extrapolation_first_order() {
let values = vec![
1.0, 0.5, 0.25, 0.125, ];
let result = richardson_extrapolation(&values, 2.0, 1.0, 0.1);
assert!(
(result.order - 1.0).abs() < 0.1,
"Expected order ~1.0, got {}",
result.order
);
assert!(result.order_matches);
}
#[test]
fn test_richardson_extrapolation_fourth_order() {
let values = vec![
1.0 + 1.0, 1.0 + 0.0625, 1.0 + 0.00390625, 1.0 + 0.000244140625, ];
let result = richardson_extrapolation(&values, 2.0, 4.0, 0.2);
assert!(
(result.order - 4.0).abs() < 0.3,
"Expected order ~4.0, got {}",
result.order
);
}
#[test]
fn test_richardson_extrapolation_error_estimates() {
let values = vec![2.0, 1.25, 1.0625];
let result = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
assert_eq!(result.error_estimates.len(), 2);
assert!(
result.error_estimates[0] > result.error_estimates[1],
"Errors should decrease: {:?}",
result.error_estimates
);
}
#[test]
#[should_panic(expected = "requires at least 3 values")]
fn test_richardson_extrapolation_requires_minimum_values() {
let values = vec![1.0, 0.5];
let _ = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
}
#[test]
fn test_richardson_extrapolation_tolerance() {
let values = vec![2.0, 1.25, 1.0625];
let result_tight = richardson_extrapolation(&values, 2.0, 2.5, 0.01);
assert!(!result_tight.order_matches);
let result_loose = richardson_extrapolation(&values, 2.0, 2.5, 1.0);
assert!(result_loose.order_matches);
}
}