use autumn_web::sim::{
Sim, assert_all_sometimes_satisfied, reset_sometimes_registry, sometimes_snapshot,
sometimes_unsatisfied,
};
use autumn_web::{always, sometimes};
#[test]
fn always_true_is_a_noop() {
always!(true);
always!(1 + 1 == 2);
always!(2 > 1, "formatted {} arg", 42);
}
#[test]
fn always_false_panics_with_greppable_message() {
let payload = std::panic::catch_unwind(|| {
always!(false);
})
.expect_err("always!(false) must panic");
let msg = payload
.downcast_ref::<String>()
.cloned()
.or_else(|| payload.downcast_ref::<&str>().map(|s| (*s).to_owned()))
.expect("panic payload should be a string");
assert!(
msg.contains("always! invariant violated"),
"message must be greppable: {msg}"
);
assert!(
msg.contains("false"),
"message must include the stringified condition: {msg}"
);
}
#[test]
fn always_false_with_format_args_includes_user_message() {
let balance = -3;
let payload = std::panic::catch_unwind(|| {
always!(balance >= 0, "balance went negative: {}", balance);
})
.expect_err("always! with a false condition must panic");
let msg = payload
.downcast_ref::<String>()
.cloned()
.or_else(|| payload.downcast_ref::<&str>().map(|s| (*s).to_owned()))
.expect("panic payload should be a string");
assert!(
msg.contains("always! invariant violated"),
"message must be greppable: {msg}"
);
assert!(
msg.contains("balance went negative: -3"),
"message must include the formatted user message: {msg}"
);
}
#[test]
fn sometimes_records_satisfied_and_observed_only() {
reset_sometimes_registry();
sometimes!(true, "satisfied-label");
sometimes!(false, "observed-only-label");
let (observed, satisfied) = sometimes_snapshot();
assert!(observed.contains("satisfied-label"));
assert!(observed.contains("observed-only-label"));
assert!(satisfied.contains("satisfied-label"));
assert!(!satisfied.contains("observed-only-label"));
assert_eq!(
sometimes_unsatisfied().into_iter().collect::<Vec<_>>(),
vec!["observed-only-label".to_owned()]
);
}
#[test]
fn sometimes_evaluates_condition_once() {
reset_sometimes_registry();
let mut calls = 0;
sometimes!(
{
calls += 1;
true
},
"counts-once"
);
assert_eq!(
calls, 1,
"sometimes! must evaluate its condition exactly once"
);
}
#[test]
fn from_seed_resets_registry_between_runs() {
let _first = Sim::from_seed(1);
sometimes!(false, "leaked-across-seeds");
assert!(sometimes_snapshot().0.contains("leaked-across-seeds"));
let _second = Sim::from_seed(2);
let (observed, satisfied) = sometimes_snapshot();
assert!(
observed.is_empty(),
"from_seed must clear observed labels: {observed:?}"
);
assert!(
satisfied.is_empty(),
"from_seed must clear satisfied labels: {satisfied:?}"
);
}
#[test]
fn assert_all_sometimes_satisfied_passes_when_all_satisfied() {
reset_sometimes_registry();
sometimes!(true, "a");
sometimes!(true, "b");
assert_all_sometimes_satisfied(); }
#[test]
fn assert_all_sometimes_satisfied_panics_on_unsatisfied_label() {
reset_sometimes_registry();
sometimes!(true, "green-ok");
sometimes!(false, "never-fired");
let payload = std::panic::catch_unwind(assert_all_sometimes_satisfied)
.expect_err("an observed-but-unsatisfied label must fail the assertion");
let msg = payload
.downcast_ref::<String>()
.cloned()
.or_else(|| payload.downcast_ref::<&str>().map(|s| (*s).to_owned()))
.expect("panic payload should be a string");
assert!(
msg.contains("never-fired"),
"panic must name the unsatisfied label: {msg}"
);
assert!(
!msg.contains("green-ok"),
"panic must not list satisfied labels: {msg}"
);
}