The chat screen stored the unsent message separately from the state cleared by panic wipe, leaving old text visible after completion. Mention suggestions could also put text back into the cleared input. Cleared the input and its command and mention suggestions when the user confirms the wipe. Rejected mention selections when suggestions are hidden or the nickname is no longer in the current list, including older click handlers and rows still visible during their closing animation.
3.1 KiB
Testing conventions
Purpose
These conventions keep the client-rewrite suite deterministic, reproducible, and portable across implementations.
Test locations
| Test type | Location | Naming |
|---|---|---|
| JVM unit and contract tests | app/src/test/ |
*Test.kt |
| Shared deterministic fakes and fixtures | app/src/test/**/testsupport/ |
Descriptive fixture name |
| Robolectric tests | app/src/test/ |
*RobolectricTest.kt |
| Android instrumented tests | app/src/androidTest/ |
*InstrumentedTest.kt |
| Coverage-tool tests | tools/coverage/ |
test_*.py |
| Interoperability fixtures | app/src/test/resources/contracts/ |
Protocol and version in filename |
Required behavior
- Tests must not use arbitrary sleeps. Advance a fake clock or coroutine test scheduler instead.
- Tests must not require public relays, internet access, Bluetooth hardware, or a user's persisted data.
- Time, randomness, dispatchers, storage, and transports must be injectable in code exercised by state-machine tests.
- Randomized failures must print a reproduction seed. Use
TEST_SEEDfor a specific replay. - Mutable byte arrays returned by fixtures and fakes must be defensively copied.
- Negative security tests must assert fail-closed behavior.
- Protocol round trips must be paired with literal golden vectors for critical externally visible formats.
- Asynchronous tests must have a deterministic completion condition and a bounded timeout.
- A fixed bug must retain its smallest reproducing input as a regression test.
Naming
Test names should describe observable behavior:
@Test
fun `replayed ciphertext is rejected without advancing receive state`() {
// ...
}
Avoid names tied to private methods or temporary implementation structure.
Fixtures and seeds
Reusable Kotlin fixtures live under
com.bitchat.android.testsupport. ReproducibleTestSeed resolves
TEST_SEED and provides a reproduction hint:
TEST_SEED=12345 ./gradlew clientRewriteContractTest
Never use production keys, contact information, messages, or other user data in fixtures.
Coverage
Run the full report and non-regression floor:
./gradlew clientRewriteContractTest
Reports are written to:
app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xmlapp/build/reports/jacoco/jacocoTestReport/html/
Check executable production lines changed from the base branch:
COVERAGE_BASE_REF=origin/main ./gradlew checkChangedLineCoverage
Generated resource classes, Compose-generated singleton classes, platform bridges, and vendored Noise code are excluded from first-party coverage metrics.
Quarantine and skips
- A flaky test must be fixed, not silently retried.
- A temporary quarantine must include an issue and removal condition.
- Unexpected skips fail review. Existing skips must be restored or replaced by equivalent coverage.
Composer UI regression
The composer panic regression runs locally in a disposable emulator with a separate installation and blocked external egress. This destructive UI suite is opt-in; default JVM and CI commands do not execute it.