./script/test # Run unit tests and corpus tests
./script/install # Build and installcctr uses cctr to test itself. The test suite lives in test/ and has a specific structure that can be confusing at first.
Most test suites follow a two-level pattern:
test/
feature_name/
feature_name.txt # Top-level: calls cctr on fixtures
fixture/
tests/ # Inner level: actual cctr test cases
test_file.txt
Top-level tests (test/feature_name/feature_name.txt) are corpus tests that:
- Call
cctras a command - Run cctr against the fixtures
- Verify cctr's output (pass/fail counts, error messages, etc.)
Fixture tests (test/feature_name/fixture/tests/*.txt) are:
- Actual cctr corpus test files
- What cctr runs when the top-level test executes
- May have their own fixtures (nested
fixture/directories)
test/json_types/
json_array.txt # Top-level: tests cctr behavior with json arrays
json_bool.txt
json_object.txt
json_string.txt
fixture/
json_array/
passing.txt # Inner: actual tests using json array variables
json_array_wrong_length.txt # Inner: test that should fail (for error testing)
json_bool/
passing.txt
json_bool_wrong_value.txt
...
The top-level json_array.txt contains tests like:
===
json_array passing tests
===
cctr $CCTR_FIXTURE_DIR/json_array/passing.txt --no-color 2>&1 | tail -1
---
All 25 tests passed in {{ t }}s
---
where
* t: number
This runs cctr on the fixture and verifies that all 25 inner tests pass.
Some fixtures have their own fixtures:
test/cctr/
run.txt # Top-level tests
fixture/
with_fixture/
read_fixture.txt # Inner test that reads from its fixture
fixture/
data.txt # Data file for the inner test
The inner test read_fixture.txt can use $CCTR_FIXTURE_DIR to access data.txt.
Every top-level test file (directly under test/*/) must call cctr as a command. This ensures we're always testing cctr's behavior, not just shell commands.
Correct pattern:
test/feature/
feature.txt # Calls: cctr $CCTR_FIXTURE_DIR/tests ...
fixture/
tests/
actual_tests.txt # Contains actual test cases
Wrong pattern:
test/feature/
feature.txt # Contains: echo hello ← WRONG! Should call cctr
If you need to test shell behavior (echo, pipes, loops), put those in a fixture and have the top-level test verify they pass via cctr.
| Directory | Purpose |
|---|---|
basic/ |
Basic cctr functionality, output format |
cctr/ |
cctr CLI behavior (run, list, failures, multiline commands) |
env_vars/ |
Environment variable expansion |
exit_only/ |
Exit-code-only tests (no expected output) |
expressions/ |
Constraint expression evaluation |
fixtures/ |
Fixture directory copying and access |
json_types/ |
JSON variable types and constraints |
no_fixture/ |
Tests that don't need fixtures |
setup_teardown/ |
_setup.txt and _teardown.txt behavior |
stdin/ |
Reading tests from stdin |
template_expansion/ |
{{ VAR }} template substitution |
update_mode/ |
-u flag for updating expected output |
variables/ |
Variable capture and constraints |
verbose/ |
-v verbose output mode |
with_fixture/ |
Basic fixture functionality |
-
Testing cctr behavior: Use the two-level pattern
- Create
test/your_feature/your_feature.txtthat calls cctr - Create
test/your_feature/fixture/tests/*.txtwith actual test cases - Top-level verifies cctr's output format, pass/fail counts, error messages
- Create
-
Testing shell/command behavior: Use simple tests
- Create
test/your_feature/simple.txtwith direct shell commands - No fixture needed if you're just testing echo, pipes, etc.
- Create
-
Testing error cases: Create intentionally failing fixtures
- Name them descriptively:
wrong_value.txt,missing_key.txt - Top-level test verifies the error message format
- Name them descriptively:
# Run all tests
cctr test/
# Run a specific suite
cctr test/json_types/
# Run with verbose output
cctr test/ -v
# Run tests matching a pattern
cctr test/ -p jsoncrates/
cctr/ # Main CLI application
src/
cli.rs # Command-line argument parsing
discover.rs # Test file discovery
main.rs # Entry point
matcher.rs # Pattern matching with variables
output.rs # Terminal output formatting
parse.rs # Corpus file parser
runner.rs # Test execution
template.rs # {{ VAR }} expansion
update.rs # -u mode file updates
cctr-corpus/ # Corpus file parsing library
cctr-expr/ # Constraint expression parser/evaluator
- Update version in
Cargo.toml(workspace version) - Update
CHANGELOG.mdin each crate - Run
cargo testandcctr test/ - Commit and tag:
git tag v0.X.Y - Push with tags:
git push --tags - CI builds and publishes to crates.io and creates GitHub release