Skip to main content

Testing cosh-ng

中文版

cosh-ng uses layered deterministic tests. Start at the cheapest layer that can prove the behavior, then widen coverage in proportion to process, PTY, wire, or security risk. Do not use exact test counts as documentation; inventory floors change as the implementation grows.

Fast feedback

Run from src/cosh-ng:

cargo test --locked -p cosh-types
cargo test --locked -p cosh-platform
cargo test --locked -p cosh-cli --test cli_integration
cargo test --locked -p cosh-core --lib
cargo test --locked -p cosh-shell --lib

Use a test-name filter while iterating:

cargo test --locked -p cosh-core session_recovery
cargo test --locked -p cosh-shell --test logic slash_registry

Shell integration layers

TargetPut a test here when it provesTypical cost
--libPrivate pure logic or a lightweight componentLowest
--test logicPublic multi-module behavior without process transportLow
--test protocolAdapter/control serialization and state transitionsLow to medium
--test raw_cliA spawned shell binary, cards, provider handoff, or scripted raw inputMedium
--test shell_hostPTY, OSC, termios, native shell, or foreground-program behaviorHighest default layer

Examples:

cargo test --locked -p cosh-shell --test logic
cargo test --locked -p cosh-shell --test protocol -- --test-threads=4
cargo test --locked -p cosh-shell --test raw_cli <test-name> -- --exact
cargo test --locked -p cosh-shell --test shell_host -- --test-threads=4

Do not put real-provider, visual, or manual-terminal checks into the default Cargo gate. Such validation must be explicitly requested and reported separately from deterministic behavior.

Core integration targets

Core tests are organized by contract rather than one monolithic suite:

TargetContract
jsonl_protocolHeadless message and streaming behavior
registry_protocolSkills, extensions, auth, and registry actions
tool_approvalTool decision protocol
session_recoveryPersisted conversation lifecycle
compaction_lifecycleManual and automatic compaction
oauth_mcpMCP OAuth control flow
sls_integrationExport integration with deterministic fixtures
sigintProcess interruption behavior

Run the target closest to the change, then the complete core package when the change affects shared runtime state.

Canonical gates

The repository scripts avoid duplicate lib/bin executions and audit test/layout inventory:

scripts/run-test-gates.sh fast # local iteration and focused handoff
scripts/run-test-gates.sh integration # all process/protocol integration targets
scripts/run-test-gates.sh all # canonical deterministic suite
scripts/run-test-gates.sh heavy # selected ignored manual-grade cases

scripts/check-test-inventory.sh enforces regression floors and ignored-test ceilings. scripts/check-test-necessity.sh checks whether a change that needs a test has one. crates/cosh-shell/scripts/check-layout.sh audits source and test placement. Do not lower these baselines in a feature or fix merely to pass CI.

Broader local gates

For ordinary code changes, stop after the formatter and tests closest to the changed behavior. Run the complete local gate only for large or cross-cutting code changes when the task explicitly asks for that depth; otherwise CI owns broad regression coverage.

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked -- -D warnings
scripts/run-test-gates.sh all
cargo build --workspace --release

Add cargo doc --workspace --no-deps when changing public API or rustdoc. Documentation-only changes need link, formatting, command, and bilingual parity checks rather than Rust tests.

Test design rules

  • Use temporary directories and test-only path overrides; never depend on a developer's real home, config, keyring, or session store.
  • Mock providers and transports. A network credential is not a test fixture.
  • Verify the public boundary: JSON envelope, JSONL message, terminal output, filesystem permission, exit status, or protocol bytes.
  • For safety fixes, include the benign control case and the adversarial input that previously bypassed the gate.
  • Keep PTY timing bounded and wait on observable state instead of arbitrary sleeps.
  • Never remove assertions, ignore tests, or broaden timeouts without explaining the behavioral reason.

The optional e2e/run.py runner validates installed launchers and real PTY paths under named profiles. It is a later system gate, not a substitute for the scoped Cargo tests above.