# Testing Guidelines

Testing rules for the causal-triangulations library.

Agents must follow these expectations when adding or modifying code.

---

## Testing Philosophy

This project is a **Causal Dynamical Triangulations library** for quantum gravity simulations.

Tests should verify:

- mathematical correctness (Regge action, coupling constants)
- geometric invariants (Delaunay property, triangulation validity)
- topological consistency (vertex/edge/face counts, Euler characteristic)
- Monte Carlo algorithm stability (ergodic moves, Metropolis acceptance)

When possible, prefer **property-based testing** over single-case tests.

Tests should focus on validating invariants rather than merely executing code.

---

## Test Types

### Unit Tests

Location:

```text
src/**
```

Defined inline using:

```rust
#[cfg(test)]
mod tests {
```

Unit tests validate:

- small internal algorithms
- helper utilities
- invariants within modules

They should be small, deterministic, and fast.

---

### Integration Tests

Location:

```text
tests/
```

Integration tests compile as **separate crates** and test the public API.

Each integration test crate should include a crate-level documentation comment:

```rust
//! Integration tests for CDT simulation.
```

This satisfies `clippy::missing_docs` in CI.

Integration tests should validate:

- full simulation construction
- public API behavior
- cross-module interactions (geometry ↔ CDT)

---

### Python Tests

Location:

```text
scripts/tests/
```

Python tests use **pytest** (never unittest). Run via:

```bash
just test-python
```

All Python tests should:

- use type hints
- include `-> None` return annotations on test functions

---

## Floating-Point Comparisons

Never compare floating-point values using `assert_eq!`.

Use the **approx** crate for tolerant comparisons:

```rust
use approx::assert_relative_eq;

assert_relative_eq!(a, b, epsilon = 1e-12);
```

---

## Deterministic Randomness

Tests must be deterministic.

If randomness is required, use a seeded RNG:

```rust
use rand::{SeedableRng, rngs::StdRng};

let rng = StdRng::seed_from_u64(1234);
```

Do **not** use `thread_rng()`. Deterministic seeds allow failures to be reproduced.

---

## Error Handling in Tests

Tests may freely use `unwrap()` or `expect()` when a failure should cause the test to fail immediately.

Explicit error handling is usually unnecessary in tests unless the test is specifically verifying error behavior.

---

## Test Commands

Run standard tests:

```bash
just test
```

Run integration tests:

```bash
just test-integration
```

Run all tests:

```bash
just test-all
```

Run Python tests:

```bash
just test-python
```

---

## Documentation Tests

Public documentation examples must compile and pass.

Validate with:

```bash
just test-doc
```

---

## Performance-Sensitive Tests

Tests should remain fast.

Avoid:

- extremely large random inputs
- quadratic or worse scaling test loops
- heavy allocations

Large-scale performance validation belongs in **benchmarks**, not tests.

---

## CI Expectations

All tests must pass under CI.

Before proposing patches agents should run:

```bash
just ci
```

The `ci` recipe runs `check bench-compile test-all examples`, which enforces:

- **check** (via `lint`): formatting, clippy, documentation builds, markdown, spelling, config validation (JSON, TOML, YAML, GitHub Actions)
- **bench-compile**: benchmarks compile without warnings under `-D warnings`
- **test-all**: unit tests, doc tests, integration tests, and Python tests (pytest)
- **examples**: all example scripts run successfully

---

## Preferred Test Style

Tests should be:

- deterministic
- focused
- invariant-driven
- easy to reproduce

Avoid large monolithic tests or tests that do not verify correctness.
