Files
LorenEteval_Furious/tests/AGENTS.md
T
2026-10-07 23:34:18 +08:00

90 lines
8.1 KiB
Markdown

# Furious test guidance
Inherit the [nearest parent guide](../AGENTS.md).
This scope owns isolated verification and the meaning of its evidence. Preserve the production boundary
under examination while replacing real host/network effects.
Read `tests/support.py` with `tests/README.md`; paths are relative to this source tree's root.
## Isolation is a product invariant
- Tests must not affect a running Furious instance, production settings/data, desktop windows, tray, system proxy, DNS,
routing, TUN, startup registration, interfaces, unrelated processes, or external services. Use `tests/support.py`, an
offscreen Qt platform set before Qt import, a temporary INI settings identity, temporary files, and fully mocked host
and network boundaries.
- Own exact child processes, threads, timers, replies, sockets, and handles created by a test. All waits are bounded and
cleanup targets only those resources. Normal suites require neither network access nor installed proxy cores.
- Tests may exercise real Qt event loops, subprocesses, and compiled probes when that boundary is the defect, but use a
hermetic child, temporary settings, disabled singleton/tray/restoration, and mocked host mutation.
- Import order is part of isolation: select the offscreen Qt platform and temporary settings identity before importing
modules that can create Qt/application globals. A late patch is not equivalent to preventing the side effect.
Canonicalize both QSettings file paths and the sandbox root before containment checks, including symlinked
temporary directories; retain an outside-path rejection case so portability does not weaken isolation. A temporary
QSettings namespace does not reset cached `Storage` collections: isolate and restore live repository fixtures too.
## Test the contract
- Assert semantic behavior and architectural invariants, not private coordinates or incidental call order. Internal
counters/registries are valid evidence when ownership, reclamation, or complexity is the contract; pair them with
an observable result instead of treating every implementation detail as forbidden. Cover success, invalid input,
timeout/cancel, stale/partial completion, rollback, cleanup, and compatible persisted input where applicable.
- Small workflow tests compose real shared controllers, models, and signals across the relevant UI surfaces;
mock the external effect instead of replacing the authority whose consistency is under test. A mocked reconnect
proves a request was issued, not which document a real runtime launched.
A directly invoked exception hook does not prove that a spawned process routes factory/run exceptions through it.
For supervision claims, retain the real child exit/crash-result boundary and bound/reap that exact test process.
- For staged changes, fail immediately before commit and prove live plus persisted state is unchanged. Test a
post-commit side-effect failure separately. Keep persisted-profile assertions distinct from runtime-copy output.
- Use stable profile/subscription identities in reconciliation and async tests. Exercise supersession, removal/reorder,
duplicate endpoints, bounded scheduling, and unrelated-work preservation rather than relying on row positions.
- Qt behavior involving focus, selection, proxy mapping, shortcuts, queued delivery, geometry, animation, or destruction
uses real widgets and `QTest`. Localized-text tests choose an explicit language inside `isolatedSettings()`.
Rendering regressions may assert targeted pixel/alpha or geometry properties under explicit themes and scaling.
Stylesheet selector counts are not rendering invariants: shared rules and component overrides can both be valid.
- Prefer exact state, signal counts, destroyed signals, weak references, registry/child counts, thread/process/handle
ownership, and final exit status. A mock cleared from its owner does not prove termination: failure-to-reap tests
must independently retain and inspect the fake process. Include stopped-but-undisposed resources: false
liveness does not prove that handles, reader threads, callbacks, or reserved ports were released. Reentrant
result observers must see retained cleanup ownership before admitting replacement work. For Qt API compatibility,
a permissive Python fake cannot validate a real binding's accepted argument types; exercise a harmless real
object at that boundary.
RSS/handle trends and repeated lifecycle batches belong in stress tiers; `gc.collect()` is diagnostic at batch
boundaries, never a production fix or per-cycle requirement.
## Tiers and maintenance
- Use `python -m unittest tests.<module> -v` from the root for focused work and `python -m unittest discover -s
tests -v` for full source-suite discovery (opt-in tests still skip). The runner is unittest, not pytest. Run the
narrow module first, then the affected tier documented in `tests/README.md`. The release-confidence tier is
explicitly opt-in with `FURIOUS_VERY_HEAVY_TESTS=1`; packaged/manual smoke work uses disposable environments.
Discovered tests must be self-contained in the checkout: do not load or execute source from Git history.
The standalone log benchmark compares saved JSON timing reports; keep that optional measurement outside
unittest and report opt-ins, platform skips, and standalone measurements separately. Discovery is an inventory,
not execution evidence: record the actual runner result, opt-in state, and skips. Standalone benchmarks and
compiled fixture entrypoints need separate invocations; a full discovered-suite pass does not run them.
Run child scripts and standalone probes without `python -O`: plain assertions are part of their verification.
- Source-only tests and an offscreen platform do not prove a packaged Qt runtime. Compiler-sensitive changes need
native lifecycle tests and the compiled fixture documented in `tests/README.md`, including accept/reject/close
and owner-first teardown. An unavailable private Nuitka counter is unknown, not measured zero; combine toolchain
inspection with native destruction, weak-wrapper and registry evidence. Record the interpreter, binding/compiler,
target, and relevant build flags with results: diagnostic flags can change the failing behavior and are not a
substitute for the ordinary release build. Report skipped/unavailable targets and distinguish commented test
examples from discovered tests. Release artifact checks do not execute this source behavioral suite.
Validate an exposed private callback-protection counter with a bounded compiled direct-connection control before
treating zero growth as a result. Include the harness configuration and actual package data in standalone probes;
import success without `tests/fixtures/offscreen.json` does not establish a runnable isolated fixture.
- Separate deterministic correctness/scale assertions from performance measurements. Opt-in stress tests may gate
relative scaling or resource bounds; document the measured contract and environment rather than treating one
machine's absolute timing as a portable product requirement.
- Update `tests/README.md` when coverage ownership, modules, commands, tiers, opt-ins, or environment requirements change.
Expected negative-path logs do not themselves mean failure. However, an exception raised inside a Qt-dispatched
callback may reach `sys.excepthook` without failing the surrounding unittest. Reentrant/lifetime tests must also
capture and assert callback exceptions, restoring the hook afterward; a successful runner exit alone is insufficient.
For each meaningful defect fix, retain a focused behavioral regression and establish the before/after failure
where practical. Keep native destruction, logical cancellation, stale-result rejection, and wrapper retention as
distinct assertions.
- Review new tests for production-state mutation, live network dependence, process-name cleanup, unbounded waits,
shared mutable fixtures, order dependence, timing-only assertions, and storage assertions where runtime output is
the contract. For guidance-only changes, verify path preservation, changed-file scope, referenced commands/tests,
and contradictory claims; run existing behavior tests only to resolve architecture uncertainty rather than adding
tests of prose.