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

Testing Overview

Cambrian embeds a test language in .cam sources. The same declarations lower to Foundry tests or Lean theorems depending on the target — you do not maintain a separate Solidity or Lean test suite by hand.

Write tests next to the entity they exercise (same file or a sibling *.test.cam merged via project.yaml). Validation rules T* / I* catch arity, context, and forall mistakes before codegen.

The triad

ConstructRoleTypical lowering
testConcrete, deterministic scenarioFoundry test_*, Lean theorem with fixed values
propertyParameterised statement + nested test / fuzz instancesLean: one theorem. EVM: concrete tests and fuzz cases
invariantStateful random call sequences + checksFoundry invariant handler, Lean runTrace
entity Counter {
    routes {
        increment(amount: u64) => []
        reset() => []
        getCount() -> u64 => [ return(m_count) ]
    }
    m_count: u64 {
        in increment(amount) => m_count + amount
        in reset() => 0
    }
}

test "starts at zero" for Counter with { m_count: 0 } {
    call getCount()
    expect return 0
}

property "reset zeroes" for Counter with { m_count: * } {
    call reset()
    expect state { m_count: 0 }
    fuzz { }
}

invariant "count stays non-negative" for Counter {
    init { m_count: 0 }
    action increment(amount: u64) { bound amount in 0..1000 }
    action reset() { }
    check m_count >= 0
}

How they relate

  • A test answers “does this exact scenario pass?”
  • A property answers “does this hold for a family of inputs?” — Lean keeps the family; fuzz backends sample it.
  • An invariant answers “does this hold after arbitrary sequences of allowed actions?”

Prefer properties for single-step algebraic facts; reach for invariants when order and interleaving matter.

Backend map (public targets)

BackendHow you run itDriven by
Foundryforge test after --target evmtest / property instances / invariant
Lean Speclake build / --check-leanRaw property + test + invariant theorems

See Backend matrix for the feature grid (multi-entity invariants, trace::*, fuzz types, …).

Design rules worth remembering

  • Entity state vs context: pins and forall markers for members live in with / init; msg:: / sys:: live in ctx { … } (T22).
  • assume vs bound: logical preconditions vs sampling ranges — only assume reaches Lean.
  • Desugar: --target evm lowers property before codegen; Lean keeps properties intact for clean theorems.
  • Expects stack: after each call, you may assert state, throw, return, and (where supported) effects. Lean conjoins every expect on that call.
  • Shared fixtures: Domain EVM cores (evm, lean) should reuse the same .cam matrices where the surface is accepted.

Project-level knobs

fuzz:
  runs: 256
  seed: 0
invariant:
  runs: 256
  depth: 50
  fail_on_revert: false

These feed Foundry profiles. Per-decl attributes (#[runs], #[depth], #[fail_on_revert]) override globals where the backend honours them.

Chapter map

ChapterContents
Unit teststest syntax, lenses, multi-step, skip from, with/ctx
PropertiesNested instances, assume/bound, forall *
InvariantsActions/checks, track/derived, trace::*, multi-entity, attributes
BackendsFoundry and Lean — support matrix