mod common;
use common::project::TempRustProject;
use common::utils::expect_panic;
use hegel::generators as gs;
use hegel::{Mode, TestCase};
#[test]
fn test_single_test_case_runs_exactly_one_case() {
let mut count = 0;
hegel::Hegel::new(|tc| {
tc.draw(gs::integers::<i32>());
count += 1;
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
assert_eq!(count, 1);
}
#[test]
fn test_single_test_case_passing() {
hegel::Hegel::new(|tc| {
tc.draw(gs::booleans());
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
}
#[test]
fn test_single_test_case_failing_propagates() {
expect_panic(
|| {
hegel::Hegel::new(|_tc| {
panic!("deliberate failure");
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
},
"deliberate failure",
);
}
#[test]
fn test_single_test_case_no_shrinking() {
let mut count = 0;
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
hegel::Hegel::new(|tc| {
tc.draw(gs::integers::<i32>());
count += 1;
panic!("always fails");
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
}));
assert!(result.is_err());
assert_eq!(count, 1);
}
#[test]
fn test_single_test_case_with_seed_is_deterministic() {
let mut values = Vec::new();
for _ in 0..3 {
let mut value = 0i32;
hegel::Hegel::new(|tc| {
value = tc.draw(gs::integers::<i32>());
})
.settings(
hegel::Settings::new()
.mode(Mode::SingleTestCase)
.seed(Some(42)),
)
.run();
values.push(value);
}
assert_eq!(values[0], values[1]);
assert_eq!(values[1], values[2]);
}
#[test]
fn test_single_test_case_assume_produces_invalid() {
hegel::Hegel::new(|tc| {
let n = tc.draw(gs::integers::<i32>());
tc.assume(n > 0);
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
}
#[test]
fn test_single_test_case_generation_works() {
hegel::Hegel::new(|tc| {
let v: Vec<i32> = tc.draw(gs::vecs(gs::integers::<i32>()));
let _ = v.len();
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
}
#[test]
fn test_single_test_case_debug_verbosity() {
hegel::Hegel::new(|tc| {
tc.draw(gs::booleans());
})
.settings(
hegel::Settings::new()
.mode(Mode::SingleTestCase)
.verbosity(hegel::Verbosity::Debug),
)
.run();
}
#[hegel::test(mode = Mode::SingleTestCase)]
fn test_single_test_case_via_test_macro(tc: TestCase) {
tc.draw(gs::booleans());
}
#[test]
fn test_single_test_case_repeat_loops_indefinitely() {
let iteration_count = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let counter = iteration_count.clone();
expect_panic(
|| {
hegel::Hegel::new(move |tc| {
tc.repeat(|| {
let n = counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
if n >= 100 {
panic!("reached 100 iterations");
}
});
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
},
"reached 100 iterations",
);
assert_eq!(
iteration_count.load(std::sync::atomic::Ordering::Relaxed),
100
);
}
#[test]
fn test_single_test_case_stateful_runs_forever() {
let step_count = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let counter = step_count.clone();
struct Counter {
count: std::sync::Arc<std::sync::atomic::AtomicU64>,
}
#[hegel::state_machine]
impl Counter {
#[rule]
fn step(&mut self, _tc: TestCase) {
let n = self
.count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
+ 1;
if n >= 200 {
panic!("reached 200 steps");
}
}
}
expect_panic(
move || {
hegel::Hegel::new(move |tc| {
let m = Counter {
count: counter.clone(),
};
hegel::stateful::run(m, tc);
})
.settings(hegel::Settings::new().mode(Mode::SingleTestCase))
.run();
},
"reached 200 steps",
);
assert_eq!(step_count.load(std::sync::atomic::Ordering::Relaxed), 200);
}
#[test]
fn test_hegel_main_macro_with_single_test_case() {
let code = r#"
use hegel::generators as gs;
#[hegel::main]
fn main(tc: hegel::TestCase) {
tc.draw(gs::booleans());
}
"#;
TempRustProject::new()
.main_file(code)
.cargo_run(&["--", "--single-test-case"]);
}
#[test]
fn test_hegel_main_macro_without_args() {
let code = r#"
use hegel::generators as gs;
#[hegel::main]
fn main(tc: hegel::TestCase) {
tc.draw(gs::booleans());
}
"#;
TempRustProject::new().main_file(code).cargo_run(&[]);
}