Files
simplex-chat/plans/directory-tests-coverage.md
sh 279119e134 simplex-directory-service: add audio captcha (#6619)
* simplex-directory-service: add audio captcha

* add plan

* updated plan

* implement changes

* add tests with coverage

* add tests

* implement further changes

* directory tests overview

* fix tests on 8.10.7

* /audio command toggles between text and voice captcha

* core: /audio enables voice captcha, retry sends both image and voice

* remove irrelevant directory service tests

* fix flaky testJoinGroup message ordering
2026-02-07 13:29:41 +00:00

80 lines
4.6 KiB
Markdown

# Directory Modules: Test Coverage Report
## Final Coverage
| Module | Expressions | Coverage | Gap |
|---|---|---|---|
| **Captcha** | 84/84 | **100%** | -- |
| **Search** | 3/3 | **100%** | -- |
| **BlockedWords** | 158/158 | **100%** | -- |
| **Events** | 527/559 | **94%** | 32 expr |
| **Options** | 223/291 | **76%** | 68 expr |
| **Store** | 1137/1306 | **87%** | 169 expr |
| **Listing** | 379/650 | **58%** | 271 expr |
84 tests, 0 failures.
## What was covered
Tests added to `tests/Bots/DirectoryTests.hs`:
- **Search**: `SearchRequest` field selectors (`searchType`, `searchTime`, `lastGroup`)
- **BlockedWords**: `BlockedWordsConfig` field selectors, `removeTriples` with `'\0'` input to force initial `False` argument
- **Options**: `directoryOpts` parser via `execParserPure` (minimal args, non-default args, all `MigrateLog` variants), `mkChatOpts` remaining fields
- **Events**: command parser edge cases (`/`, `/filter 1 name=all`, `/submit`, moderate/strong presets), `Show` instances for `DirectoryCmdTag`, `DirectoryCmd`, `SDirectoryRole`, `DirectoryHelpSection`, `DirectoryEvent`, `ADirectoryCmd` (including `showList`), `DCApproveGroup` field selectors via `OverloadedRecordDot`, `CEvtChatErrors` path
- **Store**: `Show` instances for `GroupRegStatus` constructors, `ProfileCondition`, `noJoinFilter`, `GroupReg.createdAt` field
- **Listing**: `DirectoryEntryType` JSON round-trip with field selectors
Source changes:
- `Directory/Options.hs`: exported `directoryOpts`
- `Directory/Events.hs`: exported `DirectoryCmdTag (..)`
## Why not 100%
### Events (32 expr remaining)
**Field selectors (9 expr)** on `DEGroupInvitation`, `DEServiceJoinedGroup`, `DEGroupUpdated` -- need `Contact`, `GroupInfo`, `GroupMember` types which have 20+ nested required fields each with no test constructors available.
**`crDirectoryEvent_` branches (3 expr)**: `DEItemDeleteIgnored`, `DEUnsupportedMessage`, `CEvtMessageError` -- need `AChatItem` or `User`, both strict-data types with deep dependency chains impossible to construct in unit tests.
**`DCSubmitGroup` paths (2 expr)**: constructor and `directoryCmdTag` case -- need a valid `ConnReqContact` (SMP queue URI with cryptographic keys).
**Lazy `fail` strings (2 expr)**: `"bad command tag"` and `"bad help section"` -- Attoparsec discards the string argument to `fail` without evaluating it. Inherently uncoverable by HPC.
### Options (68 expr remaining)
**Parser metadata strings (~50 expr)**: `metavar` and `help` string literals in `optparse-applicative` option declarations are evaluated lazily by the library. `execParserPure` constructs the parser but doesn't force help strings unless `--help` is invoked.
**`getDirectoryOpts` (~10 expr)**: wraps `execParser` which reads process `argv` -- can't unit-test without spawning a process.
**`parseKnownGroup` internals (~8 expr)**: the `--owners-group` arg is parsed but the `KnownContacts` parser internals are instrumented separately.
### Store (169 expr remaining)
**DB operations (~150 expr)**: `withDB'` wrappers, SQL query strings, error message literals inside database functions (`setGroupStatusStore`, `setGroupRegOwnerStore`, `searchListedGroups`, `getAllGroupRegs_`, etc.) -- all require a running SQLite database with realistic data.
**Pagination branches (~15 expr)**: `searchListedGroups` and `getAllGroupRegs_` cursor pagination -- need multi-page result sets.
**Parser failure (~4 expr)**: `GroupRegStatus` `strDecode` failure path -- needs malformed stored data.
### Listing (271 expr remaining)
**Image processing (~80 expr)**: `imgFileData`, image file Base64 encoding paths -- require groups with profile images.
**Listing generation (~120 expr)**: `generateListing`, `groupDirectoryEntry` -- require `GroupInfo` (21+ fields), `GroupLink`, `CreatedLinkContact` types with deep nesting into chat protocol internals.
**Field selectors (~40 expr)**: `DirectoryEntry` fields (`displayName`, `fullName`, `image`, `memberCount`, etc.) -- need full `DirectoryEntry` construction which requires `CreatedLinkContact`.
**TH-generated JSON (~30 expr)**: Template Haskell `deriveJSON` expressions are marked as runtime-uncovered by HPC despite executing at compile time.
## Summary
All remaining gaps fall into three categories:
1. **DB integration paths** -- require a running database (Store)
2. **Complex chat protocol types** -- types with 20+ required nested fields (Events, Listing)
3. **Lazy evaluation artifacts** -- HPC can't observe values that are never forced at runtime (Options `help` strings, Attoparsec `fail` strings, TH-generated code)
None are testable with pure unit tests without either standing up a database or constructing massive type hierarchies.