Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Pattern 3: Boundary Conditions

Context

Logic depends on limits: minimum quantities, maximum run lengths, exclusive ranges. You must guarantee behavior at and around those boundaries.

Problem

Happy-path tests routinely miss off-by-one errors, buffer limits, or guardrail regressions. Without explicit boundary coverage, downstream invariants fail silently.

Solution

Adopt a deliberate boundary grid: below, at, and above each documented limit. Use param_test! to table-drive the grid and Chicago TDD Tools assertions such as assert_in_range! and assert_guard_constraint!. Include boundary-focused names so a failing case communicates which edge is breached.

Forces

  • Thoroughness vs. duplication: table-driven tests keep boundaries concise
  • Performance vs. realism: small data sets reproduce the failure quickly
  • Maintainability vs. specificity: boundary constants should live in one place

Examples

#![allow(unused)]
fn main() {
use chicago_tdd_tools::prelude::*;
use chicago_tdd_tools::validation::guards::{GuardValidator, MAX_RUN_LEN};

param_test! {
    #[case("below", MAX_RUN_LEN - 1, true)]
    #[case("at", MAX_RUN_LEN, true)]
    #[case("above", MAX_RUN_LEN + 1, false)]
    fn test_run_length_boundaries(label: &str, length: usize, expected_ok: bool) {
        let validator = GuardValidator::new();
        let result = validator.validate_run_length(length);
        match expected_ok {
            true => assert_ok!(&result, "{label} should be accepted"),
            false => assert_err!(&result, "{label} should be rejected"),
        }
    }
}
}
  • Pattern 2: Error Path Testing
  • Pattern 4: Resource Cleanup
  • Pattern 20: Macro Pattern Enforcement