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 Guide

TestHarness

The primary testing tool. No host UI required.

#![allow(unused)]
fn main() {
use boruna_framework::testing::TestHarness;
use boruna_framework::runtime::AppMessage;
use boruna_bytecode::Value;

let mut harness = TestHarness::from_source(SOURCE)?;
}

Send Messages

#![allow(unused)]
fn main() {
let (state, effects) = harness.send(
    AppMessage::new("increment", Value::Int(0))
)?;
}

Simulate Sequences

#![allow(unused)]
fn main() {
let final_state = harness.simulate(vec![
    AppMessage::new("add", Value::Int(0)),
    AppMessage::new("add", Value::Int(0)),
    AppMessage::new("complete", Value::Int(0)),
])?;
}

Assertions

#![allow(unused)]
fn main() {
// Check a specific field by index
harness.assert_state_field(0, &Value::Int(3))?;

// Check full state equality
harness.assert_state(&expected_value)?;

// Check effects from last cycle
harness.assert_effects(&["http_request"])?;
}

Snapshots

#![allow(unused)]
fn main() {
let json = harness.snapshot();  // JSON string of current state
}

Time Travel

#![allow(unused)]
fn main() {
harness.rewind(0)?;  // Go back to init state
}

Replay Verification

#![allow(unused)]
fn main() {
let messages = vec![
    AppMessage::new("increment", Value::Int(0)),
    AppMessage::new("increment", Value::Int(0)),
];
for msg in &messages {
    harness.send(msg.clone())?;
}

// Replay same messages on fresh runtime, verify identical states
let identical = harness.replay_verify(SOURCE, messages)?;
assert!(identical);
}

Golden Tests

Golden tests verify determinism. Run the same messages twice, compare:

#![allow(unused)]
fn main() {
let mut h1 = TestHarness::from_source(SOURCE)?;
let mut h2 = TestHarness::from_source(SOURCE)?;

for msg in &messages {
    h1.send(msg.clone())?;
    h2.send(msg.clone())?;
}

assert_eq!(h1.state(), h2.state());
assert_eq!(h1.snapshot(), h2.snapshot());
}

CLI Testing

# Validate app protocol
boruna framework validate my_app.ax

# Send messages and see state
boruna framework test my_app.ax -m "add:0,add:0,complete:0"

# Inspect state as JSON
boruna framework inspect-state my_app.ax -m "add:0,add:0"

# Step-by-step simulation
boruna framework simulate my_app.ax "add:0,add:0,complete:0"

# Machine-readable diagnostics
boruna framework diag my_app.ax -m "add:0,add:0"

# Stable trace hash (for CI comparison)
boruna framework trace-hash my_app.ax -m "add:0,add:0"

# App contract summary
boruna framework inspect my_app.ax --json

Message Format

CLI messages use tag:payload format:

  • increment:0 → tag=“increment”, payload=Int(0)
  • fetch:https://example.com → tag=“fetch”, payload=String(“https://example.com”)
  • reset → tag=“reset”, payload=Int(0) (default)

Comma-separated for sequences: add:0,add:0,complete:0

Writing Test Apps

Include fn main() -> Int for standalone execution:

fn main() -> Int {
    let s0: State = init()
    let r1: UpdateResult = update(s0, Msg { tag: "add", payload: 0 })
    let r2: UpdateResult = update(r1.state, Msg { tag: "add", payload: 0 })
    r2.state.total
}

Run directly: boruna run my_app.ax