# Phase 12: Test Reset & Coverage — Testing Guide

## Summary

Phase 12 adds comprehensive tests for the LLM module functions that were missing coverage. All tests are automated unit tests that mock LLM interactions.

**New Test Files Created:**
- `tests/test_llm_structured.py` — 35 tests

**Tests Added to Existing Files:**
- `tests/test_llm_provider.py` — +14 tests (8 for get_retry_delay, 6 for get_effective_token_budget)
- `tests/test_mission_generator.py` — +6 tests for generate_category_missions_multi

**Total New Tests:** 55

---

## Running Automated Tests

### Run All Tests
```bash
pytest --tb=short -q
```

### Run Phase 12 Specific Tests
```bash
# Test llm/structured.py functions
pytest tests/test_llm_structured.py -v

# Test get_retry_delay and get_effective_token_budget
pytest tests/test_llm_provider.py::TestGetRetryDelay -v
pytest tests/test_llm_provider.py::TestGetEffectiveTokenBudget -v

# Test generate_category_missions_multi
pytest tests/test_mission_generator.py::TestGenerateCategoryMissionsMulti -v
```

### Run with Coverage
```bash
pytest tests/test_llm_structured.py tests/test_llm_provider.py::TestGetRetryDelay tests/test_llm_provider.py::TestGetEffectiveTokenBudget tests/test_mission_generator.py::TestGenerateCategoryMissionsMulti --cov=src/unfamiliar/llm --cov-report=term-missing
```

---

## Expected Test Counts

| Test File | Test Count |
|-----------|------------|
| `test_llm_structured.py` (new) | 35 |
| `test_llm_provider.py` additions | 14 |
| `test_mission_generator.py` additions | 6 |
| **Total new tests** | **55** |

---

## Test Classes Summary

### tests/test_llm_structured.py (NEW FILE)

| Class | Tests | Purpose |
|-------|-------|---------|
| `TestTruncationResult` | 4 | Dataclass field validation for all valid states |
| `TestDetectTruncationCompleteResponse` | 4 | Complete JSON parsing, markdown fence extraction |
| `TestDetectTruncationEmptyInput` | 2 | Empty/whitespace input handling |
| `TestDetectTruncationTruncatedResponse` | 3 | Truncated JSON recovery scenarios |
| `TestDetectTruncationInvalidInput` | 4 | No JSON, invalid structure handling |
| `TestExtractJson` | 8 | JSON extraction from various formats |
| `TestCreateStructuredChain` | 6 | Tool-calling vs prompt-based chain creation |
| `TestJsonOutputParser` | 4 | Internal parser for non-tool-calling models |

### tests/test_llm_provider.py (ADDITIONS)

| Class | Tests | Purpose |
|-------|-------|---------|
| `TestGetRetryDelay` | 8 | Provider-specific retry delay values |
| `TestGetEffectiveTokenBudget` | 6 | Provider token budget capping |

### tests/test_mission_generator.py (ADDITIONS)

| Class | Tests | Purpose |
|-------|-------|---------|
| `TestGenerateCategoryMissionsMulti` | 6 | Multi-call truncation resume behavior |

---

## Phase Completion Checklist

- [x] All new test files created
- [x] All existing tests still pass (725 → 780)
- [x] All functions from contracts have tests
- [x] All edge cases from contracts covered with expected return values
- [x] Error conditions tested with correct exception types
- [x] No mirror tests (tests don't reimplement logic)
- [x] Negative test ratio ≥ 1:2

---

## Test Quality Verification

### Field Coverage
All tests assert ALL fields on returned objects:
- `TruncationResult`: all 4 fields asserted
- `CategoryMissionsResponse`: mission counts and chain counts asserted

### Exact Counts
All count assertions use `==`, never `>=` or `> 0`

### Negative Test Ratio
| Test Class | Happy | Error/Edge | Ratio |
|------------|-------|------------|-------|
| TestTruncationResult | 4 | 0 | N/A (dataclass) |
| TestDetectTruncation* | 4 | 9 | 1:2.25 |
| TestExtractJson | 5 | 3 | 1:1.67 |
| TestCreateStructuredChain | 4 | 2 | 1:2 |
| TestGetRetryDelay | 5 | 3 | 1:1.67 |
| TestGetEffectiveTokenBudget | 5 | 1 | 1:5 |
| TestGenerateCategoryMissionsMulti | 3 | 3 | 1:1 |

All classes meet or exceed the 1:2 minimum ratio.
