Skip to content

Test Harness ​

The test harness provides a standardized way to run conformance tests against any PTA implementation.

Quick Start ​

bash
# Run all Beancount tests
python runners/python/runner.py --manifest ../beancount/v3/manifest.json

# Run specific suite
python runners/python/runner.py --manifest ../beancount/v3/manifest.json --suite syntax/valid

# Output JSON results
python runners/python/runner.py --manifest ../beancount/v3/manifest.json --format json > results.json

# Filter by tags
python runners/python/runner.py --manifest ../beancount/v3/manifest.json --tags booking,fifo

Directory Structure ​

harness/
├── README.md              # This file
├── spec.md                # Test format specification
├── interface.md           # Runner interface specification
├── manifest.schema.json   # JSON Schema for manifest files
├── test-case.schema.json  # JSON Schema for test cases
└── runners/
    ├── python/            # Reference Python runner
    │   ├── runner.py      # Main entry point
    │   └── loader.py      # Test case loading
    └── rust/              # Rust runner (template)
        ├── Cargo.toml
        └── src/main.rs

Test Organization ​

Tests are organized by format and version:

tests/
├── beancount/v3/
│   ├── manifest.json      # Test suite manifest
│   ├── syntax/valid/      # Valid syntax tests
│   ├── syntax/invalid/    # Invalid syntax tests
│   ├── validation/        # Semantic validation
│   ├── booking/           # Booking algorithm tests
│   ├── bql/               # Query language tests
│   └── regression/        # Bug fix tests
├── ledger/v1/
│   └── ...
└── hledger/v1/
    └── ...

Writing Tests ​

Test Case Format ​

json
{
  "id": "unique-test-id",
  "description": "What this test verifies",
  "input": {
    "inline": "2024-01-01 open Assets:Bank"
  },
  "expected": {
    "parse": "success",
    "directives": 1
  },
  "tags": ["open", "directive"]
}

Input Types ​

Inline content:

json
"input": {
  "inline": "2024-01-01 * \"Test\"\n  Assets:A  100 USD\n  Assets:B"
}

External file:

json
"input": {
  "file": "fixtures/complex-example.beancount"
}

Expected Outcomes ​

json
"expected": {
  "parse": "success|error",
  "validate": "success|error|skip",
  "directives": 5,
  "error_count": 2,
  "error_contains": ["balance", "failed"],
  "balance": {
    "Assets:Bank": {"USD": "1000.00"}
  }
}

Running Tests ​

Command Line Options ​

OptionDescription
--manifest PATHPath to manifest.json (required)
--suite NAMERun only specific test suite
--test IDRun single test by ID
--tags TAG,...Filter by tags
--format tap|jsonOutput format (default: tap)
--verboseShow detailed output
--fail-fastStop on first failure

Output Formats ​

TAP (Test Anything Protocol):

TAP version 14
1..164
ok 1 - empty-file: Empty file is valid
ok 2 - comment-only: File with only comments
not ok 3 - invalid-date: Invalid date format
  ---
  expected: parse error
  actual: parse success
  ...

JSON:

json
{
  "summary": {
    "total": 164,
    "passed": 160,
    "failed": 3,
    "skipped": 1
  },
  "results": [...]
}

Implementing a Runner ​

See interface.md for the runner interface specification.

Requirements:

  1. Parse manifest.json to find test suites
  2. Load tests.json from each suite directory
  3. Execute tests against target implementation
  4. Compare actual vs expected results
  5. Output results in TAP or JSON format

Conformance Levels ​

Tests are tagged by conformance level:

LevelRequired Tests
1 - Parsesyntax/valid, syntax/invalid
2 - ValidateLevel 1 + validation
3 - QueryLevel 2 + bql
4 - FullAll tests

See Also ​