Assertions
Probar provides a rich set of assertions for testing game state.
Basic Assertions
#![allow(unused)] fn main() { use jugar_probar::Assertion; // Equality let eq = Assertion::equals(&actual, &expected); assert!(eq.passed); assert_eq!(eq.message, "Values are equal"); // Inequality let ne = Assertion::not_equals(&a, &b); // Boolean let truthy = Assertion::is_true(condition); let falsy = Assertion::is_false(condition); }
Numeric Assertions
#![allow(unused)] fn main() { // Range check let range = Assertion::in_range(value, min, max); // Approximate equality (for floats) let approx = Assertion::approx_eq(3.14159, std::f64::consts::PI, 0.001); // Greater/Less than let gt = Assertion::greater_than(value, threshold); let lt = Assertion::less_than(value, threshold); let gte = Assertion::greater_than_or_equal(value, threshold); let lte = Assertion::less_than_or_equal(value, threshold); }
Collection Assertions
#![allow(unused)] fn main() { // Contains let contains = Assertion::contains(&collection, &item); // Length let len = Assertion::has_length(&vec, expected_len); // Empty let empty = Assertion::is_empty(&vec); let not_empty = Assertion::is_not_empty(&vec); // All match predicate let all = Assertion::all_match(&vec, |x| x > 0); // Any match predicate let any = Assertion::any_match(&vec, |x| x == 42); }
String Assertions
#![allow(unused)] fn main() { // Contains substring let contains = Assertion::string_contains(&text, "expected"); // Starts/ends with let starts = Assertion::starts_with(&text, "prefix"); let ends = Assertion::ends_with(&text, "suffix"); // Regex match let matches = Assertion::matches_regex(&text, r"\d{3}-\d{4}"); // Length let len = Assertion::string_length(&text, expected_len); }
Option/Result Assertions
#![allow(unused)] fn main() { // Option let some = Assertion::is_some(&option_value); let none = Assertion::is_none(&option_value); // Result let ok = Assertion::is_ok(&result); let err = Assertion::is_err(&result); }
Custom Assertions
#![allow(unused)] fn main() { // Create custom assertion fn assert_valid_score(score: u32) -> Assertion { Assertion::custom( score <= 10, format!("Score {} should be <= 10", score), ) } // Use it let assertion = assert_valid_score(game.score); assert!(assertion.passed); }
Assertion Result
All assertions return an Assertion struct:
#![allow(unused)] fn main() { pub struct Assertion { pub passed: bool, pub message: String, pub expected: Option<String>, pub actual: Option<String>, } }
Combining Assertions
#![allow(unused)] fn main() { // All must pass let all_pass = Assertion::all(&[ Assertion::in_range(x, 0.0, 800.0), Assertion::in_range(y, 0.0, 600.0), Assertion::greater_than(health, 0), ]); // Any must pass let any_pass = Assertion::any(&[ Assertion::equals(&state, &State::Running), Assertion::equals(&state, &State::Paused), ]); }
Game-Specific Assertions
#![allow(unused)] fn main() { // Entity exists let exists = Assertion::entity_exists(&world, entity_id); // Component value let has_component = Assertion::has_component::<Position>(&world, entity); // Position bounds let in_bounds = Assertion::position_in_bounds( position, Bounds::new(0.0, 0.0, 800.0, 600.0), ); // Collision occurred let collided = Assertion::entities_colliding(&world, entity_a, entity_b); }
Example Test
#![allow(unused)] fn main() { #[test] fn test_game_state_validity() { let mut platform = WebPlatform::new_for_test(WebConfig::default()); // Advance game for _ in 0..100 { platform.advance_frame(1.0 / 60.0); } let state = platform.get_game_state(); // Multiple assertions assert!(Assertion::in_range(state.ball.x, 0.0, 800.0).passed); assert!(Assertion::in_range(state.ball.y, 0.0, 600.0).passed); assert!(Assertion::in_range(state.paddle_left.y, 0.0, 600.0).passed); assert!(Assertion::in_range(state.paddle_right.y, 0.0, 600.0).passed); assert!(Assertion::lte(state.score_left, 10).passed); assert!(Assertion::lte(state.score_right, 10).passed); } }