refactor(opencode): allow @test inside #[cfg(test)] mod blocks, drop file gate
The previous design routed Rust unit tests to NOT_TESTABLE: Rust
unit-only because @test was forbidden from touching src/, which
forced @make to write both the production code and the inline
#[cfg(test)] mod tests in one dispatch — losing TDD's RED→GREEN
separation. But Rust module tests inside #[cfg(test)] mod tests
{ ... } are the canonical unit-testing idiom, not an edge case.
@test's File Constraint now allows modifying src/**/*.rs, but
strictly inside #[cfg(test)] mod <name> { ... } blocks. Every line
outside such a block stays read-only — adding pub, importing crates,
declaring siblings, or any other production change is forbidden.
Integration tests at tests/**/*.rs continue to work as before.
The Phase 6 post-step file gate (git status snapshot + comm -23
diff against test-pattern globs) is removed. With @test legitimately
writing inside src/, a path-based gate proves nothing — production
edits and cfg(test) edits live in the same files. The boundary is
enforced by the prompt rule and Phase 8 reviewer scrutiny.
Phase 5 test-file guidance updated to distinguish module vs
integration tests for Rust, with stub-first TDD applying to both
when symbols don't yet exist. The "Rust integration TDD: stub-first"
section is renamed to "Rust stub-first TDD" and now covers module
tests too. NOT_TESTABLE's "Rust unit-only" reason is replaced with
"Missing testability seam" for cases where the production code
needs a small change before tests can be authored.
This commit is contained in:
parent
8373e32f34
commit
4dc3cffba6
2 changed files with 28 additions and 67 deletions
|
|
@ -113,29 +113,18 @@ Python:
|
|||
- `**/test_data/**`
|
||||
- `**/test_fixtures/**`
|
||||
|
||||
Rust (integration tests only — see "Rust unit tests" below):
|
||||
- `tests/**/*.rs` (crate-level integration tests directory)
|
||||
- `**/tests/**/*.rs` (per-crate integration tests in workspace layouts)
|
||||
- `**/test_data/**`
|
||||
- `**/test_fixtures/**`
|
||||
Rust:
|
||||
- **Integration tests:** `tests/**/*.rs` and `**/tests/**/*.rs` (workspace-style `<crate>/tests/...`). Create new files; do not modify existing integration tests in unrelated tasks.
|
||||
- **Module tests:** `src/**/*.rs` — but **only inside `#[cfg(test)] mod <name> { … }` blocks**. You may:
|
||||
- Append a new `#[cfg(test)] mod tests { use super::*; … }` block at the end of an existing source file.
|
||||
- Add new `#[test] fn` items inside an already-existing `#[cfg(test)] mod` block.
|
||||
- Edit/remove `#[test] fn` items you previously authored inside such a block.
|
||||
- **Test data / fixtures:** `**/test_data/**`, `**/test_fixtures/**`.
|
||||
|
||||
**Anti-patterns — refuse the path even if the glob above matches:**
|
||||
- Anything under `src/` (e.g. `src/tests/foo.rs`, `src/**/tests/...`). `src/tests/` is a regular module under `src/`; it would require declaring `mod tests;` in production code (`lib.rs` / `main.rs`) and creating `mod.rs`, which you cannot do. If the caller asks for such a path, treat it as a wrong task spec: return `BLOCKED` with a note that the path is not a valid Rust test location, suggesting `tests/<feature>.rs` (or `NOT_TESTABLE: Rust unit-only` if the test really needs to be in-source).
|
||||
**Strict boundary rule for Rust module tests:** every line outside a `#[cfg(test)] mod` block is read-only. Adding `pub`, changing function signatures, importing crates, declaring new `pub mod` siblings, touching the prelude, or any other production-code edit is forbidden — those changes belong to `@make`. If the test cannot be written without such a change, report the missing seam to the caller and return `NOT_TESTABLE` (or, for a fresh public API, request a stub-first `@make` pre-pass).
|
||||
|
||||
**You may NOT modify production/source code under any circumstances.**
|
||||
|
||||
### Rust unit tests
|
||||
|
||||
Rust unit tests live inside production source files (inside `#[cfg(test)] mod tests { ... }` blocks in `src/**/*.rs`). Because that would require modifying production code, **you do not write Rust unit tests.** Options when the task spec requests unit-level coverage in Rust:
|
||||
|
||||
1. Convert to an integration test under `tests/` if the unit is part of the public API.
|
||||
2. Return `NOT_TESTABLE` with reason `pure-wiring` or `external-system` if no integration-level seam exists, and let `@make` write the in-source tests.
|
||||
|
||||
Report this constraint to the caller rather than silently degrading coverage.
|
||||
|
||||
If you believe source code needs changes to be testable, report this to the caller — do not edit it yourself.
|
||||
|
||||
This constraint is enforced by a post-step file gate. Violations cause your output to be discarded.
|
||||
**Anti-patterns — refuse the path even if it would technically be writable:**
|
||||
- `src/tests/foo.rs` and similar regular submodule paths under `src/`. These are not `#[cfg(test)]` modules — they are normal modules that would require a `mod tests;` declaration in production code (`lib.rs` / `main.rs`), which you cannot add. Report as `BLOCKED` and suggest either `tests/<feature>.rs` (integration) or a `#[cfg(test)] mod tests` block inside the relevant `src/<module>.rs`.
|
||||
|
||||
## Test Philosophy
|
||||
|
||||
|
|
@ -257,7 +246,7 @@ You may return `NOT_TESTABLE` only for these allowed reasons:
|
|||
| **External system without harness** | Change only affects API call to service with no local mock possible |
|
||||
| **Non-deterministic** | GPU numerical results, timing-dependent behavior |
|
||||
| **Pure wiring** | Decorator swap, import / `use` reorganization, no logic change |
|
||||
| **Rust unit-only** | Coverage requires `#[cfg(test)]` mod tests in production source; @test cannot write those — let @make handle it |
|
||||
| **Missing testability seam** | Test would require a production-code change beyond a `#[cfg(test)] mod` block (e.g. a private function needs `pub(crate)`, a refactor exposes a hook). Report the missing seam so `@make` can add it before tests are authored. |
|
||||
|
||||
Must provide:
|
||||
- Which allowed reason applies
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue