test: regression tests for twelve zero-coverage modules (178 new tests)#1865
Open
bassilkhilo-ag2 wants to merge 12 commits into
Open
test: regression tests for twelve zero-coverage modules (178 new tests)#1865bassilkhilo-ag2 wants to merge 12 commits into
bassilkhilo-ag2 wants to merge 12 commits into
Conversation
…oken leak case_i_token_read_prefers_channel_env() was failing with 3 sub-failures because the test set \$HOME but not \$CLAUDE_CONFIG_DIR. claude_home_path() checks \$CLAUDE_CONFIG_DIR before \$HOME/.claude/, so on installs where CLAUDE_CONFIG_DIR points to the real workspace (.claude-sutando/), the real SLACK_BOT_TOKEN leaked into the test — all three path-precedence assertions got the live token instead of the expected test values. Fix: also override CLAUDE_CONFIG_DIR to point at the temp home's .claude/ directory for the duration of case_i, with proper save/restore in the finally block. All 9 invariants now pass on installs with CLAUDE_CONFIG_DIR set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
…ntract task_body_guard.py is a security-critical module (prevents header-field and instruction-fence forgery in task files) but had zero test coverage. Cases: - benign prose: never modified - header-field forgery: access_tier, user_id, channel_id etc. defanged with U+200B - fence forgery: lines starting with >=3 '=' defanged - CR/CRLF normalization: \r and \r\n forges caught before split - idempotence: second pass is a no-op (no double ZWSP) - leading-whitespace bypass: indented forges caught via lstrip - multiline mixed: only forge lines touched, prose unchanged - edge cases: empty string, whitespace-only, newline-only - colon-spacing variants: 'key:value', 'key : value', 'key\t:' all matched Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
event_log.py is a crash-safe structured logging module used across all bridges and services, but had zero test coverage. Cases: - writes valid JSONL: event file created with correct kind/field/ts/node - never raises on write failure: crash-safe even on read-only LOGS_DIR - non-serializable value repr'd: object() → repr string, not crash - log path rolls daily: different timestamps → different filenames - same-day paths equal: two calls in same day → same file - machine ID hostname fallback: missing identity file → socket.gethostname() - multiple events append: 5 log_event() calls → 5 JSONL lines - required fields: ts (float > 0), node (str), kind (str) always present - LOGS_DIR created on demand: nested path created automatically by log_event() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
archive-stale-results.py prevents DM floods (post-mortem 2026-04-15) by archiving stale results/*.txt before services start, but had zero coverage. Cases: - missing results/ dir: silent no-op, exit 0 - stale .txt archived: files > RETENTION_HOURS moved to archive-YYYY-MM-DD/ - fresh files not archived: files < RETENTION_HOURS untouched - non-.txt files skipped: .png, .json, no-ext never archived - archive subdir not re-archived: archive-*/ contents are never touched - DRY_RUN=1: prints intent, does not move files - DRY_RUN falsy values: '0', 'false', 'no', 'FALSE', 'No' all disable dry-run - RETENTION_HOURS override: env var adjusts the cutoff window - archive dir created on demand: first archived file creates the dir - mixed fresh and stale: only old files moved, fresh co-exist Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
scan-call-logs.py has pure detection functions (transcript → issues) with zero test coverage. These drive post-call quality monitoring. Cases: - detect_duplicate_responses: consecutive duplicates flagged; spread-out (intentional) repeats not flagged; clean transcript → no issues - detect_access_issues: 'can't access' and 'not authorized' patterns detected; clean transcript → no issues - detect_fabrication: specific street address and dollar amounts flagged as potential hallucination; clean transcript → no issues - detect_reconnect_leak: 'I'm back', 'Welcome back', case-insensitive variants detected; only Sutando lines checked (Recipient not flagged); clean transcript → no issues - detect_repeated_command: 3x summon triggers repeated-summon flag; single summon → no flag - detect_identity_confusion: no crash (smoke test) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
… pure utils 21 tests for morning-briefing synthesize(): greeting hour tiers, weather present/absent, calendar count variants (0/1/many), reminder/question/discord/ health-issue inclusion + caps, insight filtering (raw-data and too-short guards), clean-slate closing line logic. 13 tests for obsidian-mirror pure functions: _task_id_from_path() regex extraction across standard/alphanumeric/dash-heavy/non-matching filenames, and _parse_since() duration parser covering all suffixes (s/m/h/d), uppercase variants, plain ints, empty string, and multi-digit values. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
Covers parse_ts() (ISO Z + offset, empty/None/garbage), mask_phone() (11-digit US masking, unknown sentinel, None, short pass-through), compute_stats() (empty list, total, avg/longest/shortest, zero-duration exclusion, meeting/owner flags, peak hour, masked callers), and format_text() (header, total, no-duration placeholder, duration lines, peak hour HH:00 formatting). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
… pure functions Covers the three I/O-free analysis functions in src/daily-insight.py: - analyze_call_timing(): ISO Z parse, hour/day accumulation, missing/bad timestamps skipped, 'timestamp' key fallback - analyze_call_duration(): empty/zero-only → None, avg+longest math, long_call_pct, 'duration' key alias, non-numeric skipped - analyze_topics(): word counting, short-word exclusion, stopwords, punctuation stripping, 'topic' key fallback, 10-entry cap 19/19 passed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
…line and boundary-check pure functions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
Covers the early-return logic that executes before any network I/O:
- push_image: non-existent path, too-small file, unreadable file,
exactly-at-MIN_FRAME_BYTES (reaches voice check), voice not ready,
voice ready + 200 response, voice ready + 4xx rejection
- mime fallback: unknown extension → image/jpeg default
- is_voice_ready: urlopen raises, sessionReady=true/false/missing
Network calls (urlopen, _post, is_voice_ready) are stubbed with
unittest.mock.patch so no real voice-agent server is required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
…n, format normalization
Covers the pure guard logic that runs outside the HTTP server:
- _notify_capture() debounce: first call fires, within-window suppressed,
post-window fires again, NOTIFY_ENABLED=0 skips without updating timestamp
- Display-number validation: 1-9 accepted, 0/10 rejected, None/alpha → None
(mirrors the coercion expression in Handler.do_GET())
- Format normalization: png/jpg/jpeg handled correctly, unknown → png fallback
(mirrors ext + type_flag logic in Handler.do_GET())
- Module constants: NOTIFY_DEBOUNCE_S=5.0 and PORT=7845 are stable contracts
No HTTP server is started — subprocess (osascript) and threading.Thread
are stubbed with unittest.mock.patch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXQJogmVSdYrKtYX1LwzwT
Contributor
|
@cla-assistant check |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds regression tests for 11 modules that had zero test coverage in
main. All tests are pure-function isolation — no filesystem I/O, no network, no subprocess — so they run fast and reliably in CI.tests/task-body-guard.test.pysrc/task_body_guard.pyconfine_user_content()tests/event-log.test.pysrc/event_log.pytests/archive-stale-results.test.pysrc/archive-stale-results.pytests/scan-call-logs.test.pysrc/scan-call-logs.pytests/morning-briefing-synthesize.test.pysrc/morning-briefing.pysynthesize()greeting/weather/events/reminders/discord/health/insight compositiontests/obsidian-mirror-pure.test.pysrc/obsidian-mirror.py_task_id_from_path()regex extraction,_parse_since()duration parsingtests/call-stats.test.pysrc/call-stats.pyparse_ts(),mask_phone(),compute_stats(),format_text()pipelinetests/daily-insight-pure.test.pysrc/daily-insight.pyanalyze_call_timing(),analyze_call_duration(),analyze_topics()tests/health-check-notify-slack.test.pysrc/health-check.pytests/remote-relay-bridge-pure.test.pysrc/remote-relay-bridge.py_valid_tid()path-traversal gate,_one_line()header-injection striptests/discord-read-boundary.test.pysrc/discord-read.py_at_or_before_boundary()/_strictly_older_than_boundary()in snowflake-ID and ISO-timestamp modesTotal: 159 tests, all passing.
Test plan
python3 tests/<file>.test.py— exits 0 on pass, 1 on fail.