docs(openup): move WI-2 OpenUP work set verbatim from skara-brae-server
All OpenUP artifacts are versioned in skara-brae-common under docs/openup/ per the 2026-10-03 decision reversal in design-wi-2-architecture-cleanup.md (supersedes the earlier in-server-docs decision). Verbatim move, no content changes: analysis-design/, requirements/, test/ (6 files).
This commit is contained in:
parent
9cd8e2f717
commit
4798f55660
6 changed files with 1066 additions and 0 deletions
60
docs/openup/test/test-cases.md
Normal file
60
docs/openup/test/test-cases.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Skara Brae — Test Cases (existing coverage mapped to use cases)
|
||||
|
||||
Version 1.0 (WI-2, 2026-10-03) · OpenUP artifact: `test/test-cases.md`
|
||||
Baseline: 45 unit tests, all green on `wi-2-architecture-cleanup` @ 899fde8 (`cargo test --workspace`).
|
||||
|
||||
## 1. Existing tests → use-case mapping
|
||||
|
||||
| Test (file::name) | Verifies | UC |
|
||||
|---|---|---|
|
||||
| character::`stat_bonus_at_20_is_zero` / `_below_20_is_negative` / `_above_20_is_positive` / `_handles_large_values` | OB/DB stat-bonus curve incl. BIGINT headroom | UC-08, UC-05 |
|
||||
| character::`xp_for_level_1_is_zero` / `_2_is_1800` / `_scales_subexponentially` / `_does_not_overflow` | XP curve 18·100·(level−1)² | UC-12 |
|
||||
| character::`level_up_fails_at_max_level` / `_succeeds_with_enough_xp_and_gold` / `_fails_without_enough_xp` / `_fails_without_enough_gold` | review-board rules | UC-12 |
|
||||
| character::`level_up_cost_scales` | 500·level cost | UC-12 |
|
||||
| character::`calc_max_hp_depends_on_class_and_con` / `calc_max_energy_and_nerve_vary_by_class` | class tables | UC-03 |
|
||||
| character::`training_cost_scales_with_stat` | 5·1.3^(stat/10) cost curve | UC-05 |
|
||||
| character::`apply_regen_restores_resources` / `_no_change_if_no_time_passed` | lazy regen (180 s / 300 s / 300 s) | shared sub-flow Regenerate Resources |
|
||||
| character::`roll_stats_returns_all_five` / `race_modifiers_apply` | character creation rolls ± race mods | UC-03 |
|
||||
| character::`create_character_is_deterministic_under_seeded_rng` | WI-1 injectable RNG at creation | UC-03, NFR-05 |
|
||||
| combat::`open_ended_roll_stays_in_range` | d100 open-ended re-rolls (≥96 / ≤5) | UC-08 |
|
||||
| combat::`offensive_bonus_includes_stat_and_base` / `defensive_bonus_includes_stat_and_base` | OB/DB composition | UC-08 |
|
||||
| combat::`crit_damage_cap_equal_level_is_none` / `_higher_defender_reduces` / `_scaling` | level-gap crit caps (0.60/0.40/0.15/0.05) | UC-08 |
|
||||
| combat::`resolve_attack_can_hit_or_miss` | round structure and HP clamping | UC-08 |
|
||||
| combat::`resolve_combat_produces_winner` | fight termination, winner/loser | UC-08 |
|
||||
| combat::`parse_attack_type_maps_known_types` | slash/crush/puncture + default crush | UC-08 |
|
||||
| services::`pick_enemy_respects_weights` | weighted encounter draw | UC-08 |
|
||||
| services::`train_stat_increases_stat` / `_fails_without_energy` / `_fails_without_gold` / `_fails_invalid_stat` / `train_constitution_recals_hp` | gym rules incl. max-HP recompute | UC-05 |
|
||||
| services::`equip_item_moves_from_inventory_to_slot` / `_swaps_previous` / `_fails_if_not_in_inventory` | equip semantics | UC-06 |
|
||||
| services::`unequip_item_moves_to_inventory` / `_fails_empty_slot` | unequip semantics | UC-06 |
|
||||
| services::`equipped_damage_sums_weapon_slots` / `total_defense_sums_all_slots` / `equipped_attack_type_returns_weapon_type` / `_defaults_to_crush` | equipment → combat stats | UC-08 |
|
||||
| (WI-1) seeded determinism pattern across the above | RNG injection | NFR-05 |
|
||||
|
||||
## 2. Coverage gaps the WI-2 refactor must not lose (and currently uncovered areas)
|
||||
|
||||
**Covered code being moved** — the run_adventure handler body (routes/mod.rs:409–567) is currently **not directly tested**; its ingredients (regen, pick_enemy, equipped stats, combat resolution) are covered per §1. WI-2 therefore **adds** direct service-level tests while moving the code:
|
||||
|
||||
| New test | Vector (design note §7) | UC |
|
||||
|---|---|---|
|
||||
| adventure::`run_adventure_win_applies_rewards_and_loot` | A1: seeded win → xp/gold/nerve/loot/inventory/exact outcome fields | UC-08 main |
|
||||
| adventure::`run_adventure_defeat_sets_hp_to_zero` | A2: overwhelming enemy → no rewards | UC-08 alt |
|
||||
| adventure::`run_adventure_rejects_incapacitated` | A3: hp = 0 → `CharacterIncapacitated`, nerve intact | UC-08 exception |
|
||||
| adventure::`run_adventure_rejects_insufficient_nerve` | A4 → `NotEnoughNerve` | UC-08 exception |
|
||||
| adventure::`run_adventure_applies_regen_before_guards` | A5: regen visible in combat HP | shared sub-flow |
|
||||
| adventure::`run_adventure_charges_spell_upkeep_on_win_and_loss` | A6 both paths | UC-08 step 8 / UC-11 interplay |
|
||||
| adventure::`run_adventure_filters_loot_to_catalog_items` | A7 drop for unknown item id skipped | UC-08 step 6 / NFR-07 |
|
||||
| adventure::`run_adventure_is_deterministic_under_seeded_rng` (+ optional golden CombatLog fixture) | A8 two seeds-42 runs identical | NFR-05 |
|
||||
| routes::`wire_identity_adventure_response` … `wire_identity_learn_response` (W1–W6) | byte-for-byte `serde_json::to_string` equality of each new DTO against golden strings recorded from the current `json!` expressions **before** the refactor; golden keys in lexicographic order **at every nesting level** (serde_json has no `preserve_order` — json! objects emit sorted keys; the adventure DTO's `combat_log` is the §4.3 Value bridge, defect #14) | UC-08/09/11, NFR-19 |
|
||||
|
||||
**New helper/constant pins** (design note §4.4–4.5): `as_str` parity for `ItemType`/`Quality` (wire-format guarantee NFR-19), `gym_display_order_covers_all_training_grounds` (pins GymResponse.stats order to routes/mod.rs:588–594, which differs from TRAINING_GROUNDS order), `race/class` table exhaustiveness, embedded-JSON loader parses (5), `caster_spell_level` spot values, `spell_learn_cost` guard spot checks (0, −1, 8 → 999_999).
|
||||
|
||||
**Known remaining gaps (documented, out of WI-2 scope — see design note Q3):**
|
||||
- Heal cost logic (UC-09) and spell learn/activate rules (UC-11) live in handlers and have no unit tests; WI-2 only types their responses.
|
||||
- Shop buy/sell stock transitions (UC-07), auth flows (UC-01/02), and level-up handler status mapping (UC-12 → all 422) have no HTTP-level integration tests. The exhaustive `domain_status` match (compile-time totality) is the WI-2 mitigation for the mapping itself.
|
||||
- No test asserts JSON field **order**; the response structs declare fields in wire order and the golden CombatLog fixture pins the largest payload.
|
||||
|
||||
## 3. Regression protocol for WI-2 (coder must run per commit)
|
||||
|
||||
1. `cargo fmt --check`
|
||||
2. `cargo clippy --all-targets -- -D warnings`
|
||||
3. `cargo test --workspace` — 45 baseline tests green at every step; the only permitted test edits are the **9** mechanical assertion updates listed in design note §4.1 (3 `level_up`, 3 `train_stat`, 1 `equip_item`, 1 `unequip_item`, 1 `pick_enemy_respects_weights` — the last gains an Ok-path `.unwrap()` because `pick_enemy` becomes `Result`-returning) plus newly added tests.
|
||||
4. Manual wire spot-check (recommended once, after commit 5): run the server, exercise `GET /api/characters/{id}/adventure`, `POST …/heal`, `GET …/spells`, `POST …/spells` (both modes) and diff responses **byte-for-byte** against pre-refactor output — field names, key **order** (lexicographic, since serde_json runs without `preserve_order`), null-ness, number formatting.
|
||||
Loading…
Add table
Add a link
Reference in a new issue