language-agnostic testing for unix hackers
theodore "tc" calvin - helicopter pilot, testing framework namesake, legend
|=o=o=o=o=o=o=o=o=o=o=o=| tc v1.0.0 - island hopper
| testing any language, anywhere
___/ \___ (o) π fly safe, test well
(( tc ))======\
\_______/ (o)
^ ^
^-----------^
What: Language-agnostic test framework. Write tests once, run against any language (bash, python, rust, go, whatever).
How: Tests are directories. Your code reads input.json from stdin, writes expected.json to stdout. That's it.
Get Started:
# clone and install
git clone https://github.com/ahoward/tc.git
cd tc
# IMPORTANT: Add to PATH (avoids conflict with Unix traffic control command)
export PATH="$PWD/tc/bin:$PATH"
# verify
tc --version
# try the hello-world example
tc examples/hello-world
# create your first test
tc new tests/my-featureThat's it. See full docs for advanced features.
tc conflicts with the Unix traffic control command. You MUST add this project's tc to your PATH.
# Add to PATH for current session
export PATH="$PWD/tc/bin:$PATH"
# Add to shell config for persistence (optional)
echo 'export PATH="$PWD/tc/bin:$PATH"' >> ~/.bashrc # or ~/.zshrcVerify:
which tc # should show: ./tc/bin/tc (NOT /usr/sbin/tc)
tc --version # should show: tc v1.0.0 - island hoppertc is a dead-simple testing framework that lets you:
- test any language with the same test suite
- organize tests as directories with json input/output
- run tests with zero dependencies (just jq)
- port code between languages without rewriting tests
simple β’ portable β’ language-agnostic β’ unix β’ spec-driven
π€ In the AI age, specifications and tests are permanent while implementations are disposable.
Tests are the spec. Code is a build artifact. Port languages freely, keep tests forever.
See projects/ and examples/multi-lang-dao/ for a working example of identical DAO interfaces in 5 languages (Ruby, Go, Python, JavaScript, Rust) all passing the same test suite.
Vision: Disposable applications. Swap languages freely, keep tests forever.
See docs/THEORY.md for the full system adapter pattern vision.
# test execution
tc # run all tests (KISS!)
tc <suite-path> # run single test suite
tc <path> --all # run all suites in directory tree
tc <path> --tags TAG # run suites matching tag
tc <path> --parallel # run all suites in parallel (auto CPU detection)
tc <path> --parallel N # run with N parallel workers
# test generation
tc new <test-path> # generate new test suite
tc init [directory] # initialize test directory with README
# discovery & metadata
tc list [path] # list all test suites with metadata
tc tags [path] # show all available tags
tc explain <suite> # explain what a test suite does
# info
tc --version # show version
tc --help # show helpTTY mode (terminal): Clean single-line status with π spinner, fail-fast behavior
Non-TTY mode (CI/CD): Traditional verbose output with full logs
Override: TC_FANCY_OUTPUT=true/false
β full docs | β tc new guide | β system adapter theory (WIP)
my-feature/
βββ run # executable: reads input.json, writes json to stdout
βββ data/
βββ scenario-1/
βββ input.json # test input
βββ expected.json # expected output
tc my-feature # β pass or β failtc supports simple pattern matching in expected.json for dynamic values:
{
"id": "<uuid>",
"status": "pending",
"created_at": "<timestamp>",
"count": "<number>",
"message": "<string>"
}Patterns:
<uuid>- validates UUID v4 format<timestamp>- validates ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS)<number>- any JSON number<string>- any string value<boolean>- true or false<null>- null value<any>- matches anything
Works everywhere:
- Nested objects
- Array elements
- Mixed with exact values
No configuration needed - patterns are auto-detected.
Define your own patterns via TC_CUSTOM_PATTERNS:
export TC_CUSTOM_PATTERNS="email:^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
ipv4:^([0-9]{1,3}\.){3}[0-9]{1,3}$
phone:^\+?[0-9]{10,15}$"Then use in expected.json:
{
"email": "<email>",
"server": "<ipv4>",
"contact": "<phone>"
}Format: pattern_name:regex (one per line, standard regex syntax)
test execution:
- run single test suite
- semantic json comparison (order-independent)
- pattern matching (
<uuid>,<timestamp>,<number>,<string>, etc.) - timeout management
- result persistence (tc-result files)
- hierarchical test discovery (--all flag)
- tag-based filtering (--tags flag)
- parallel execution (--parallel flag, auto-detect CPU cores)
- single-line animated status (TTY mode: helicopter π, spinner, colors)
- fail-fast on first error (TTY mode stops immediately, shows log path)
- final stats summary (colored counts: passed/failed/errors, cumulative time)
- traditional verbose output (non-TTY mode for CI/CD)
- machine-readable logs (JSONL format in
tc/tmp/report.jsonl)
test generation:
- scaffold generation (
tc new) - test directory initialization (
tc init) - metadata flags (--tags, --priority, --description)
- template system (--from, --list-examples)
- TDD workflow (tests fail until implemented)
discovery & metadata:
- list all tests (
tc list) - show available tags (
tc tags) - explain test suite (
tc explain) - AI-friendly metadata format
quality:
- dogfooding (tc tests itself!)
roadmap:
- pattern-based selection
- distributed test execution
β tc-kit: AI-driven testing
tc-kit integrates with spec-kit for automatic test generation from specifications. Perfect for AI-assisted development workflows where specs and tests are permanent while implementations are disposable.
Quick start:
# Generate tests from spec
/tc.specify
# Implement to pass tests
edit tc/tests/my-feature/user-story-01/run
# Validate & refine
/tc.validate
/tc.refineSee AI.md for full documentation.
Prerequisites: bash 4.0+, jq
# Install jq
brew install jq # macOS
sudo apt-get install jq # Ubuntu/Debian
# Clone tc
git clone https://github.com/ahoward/tc.git
cd tc
# Add to PATH
export PATH="$PWD/tc/bin:$PATH"
# Verify
tc --versionSee the TL;DR section above for PATH setup details.
mit license - see LICENSE
made with β and helicopters
"the chopper's fueled up and ready to go. let's test some code." β tc
π fly safe, test well
an #n5 joint π¬