diablo2-web/TEST_INFRA.md

113 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Diablo II v1.13c Parity Test Infrastructure (`TEST_INFRA.md`)
This document defines the comprehensive test infrastructure, architectural contracts, test runner configuration, and execution guidelines for the Diablo II v1.13c parity test initiative (151 Issues, `#562–#712` across Milestones `M1`–`M8`).
---
## 1. Test Architecture & Runner Setup
### Test Framework
- **Test Runner**: [Vitest v2.1.9](https://vitest.dev/)
- **Runtime Environment**: Node.js v20+ with native TypeScript compilation and ESM modules.
- **Assertion Library**: Vitest BDD assertions (`describe`, `it`, `expect`, `vi`) with strict value and deep object matching against real production exports.
- **Execution Mode**: Hermetic, isolated, parallelized test runner with sub-millisecond execution times for model, renderer, and state-tree tests, and isolated headless Chromium browser automation for E2E browser flows.
### Standard Test Commands
```bash
# Run TypeScript typechecking across all 7 project references
npm run typecheck
# Run the M9 Gate verification suite (4-tier parity + arch boundaries + automap + netproto + frontend)
npx vitest run tests/e2e-parity/ tests/arch/boundaries.test.ts tests/frontend-flow.test.ts tests/netproto-bncs-packets.test.ts tests/netproto-online-flow.test.ts tests/automap-renderer.test.ts
# Run only the 4-tier Diablo II v1.13c parity test suite
npx vitest run tests/e2e-parity/
# Run individual tiers
npx vitest run tests/e2e-parity/tier1-feature-coverage.test.ts
npx vitest run tests/e2e-parity/tier2-boundary-corner.test.ts
npx vitest run tests/e2e-parity/tier3-cross-feature.test.ts
npx vitest run tests/e2e-parity/tier4-real-world-scenarios.test.ts
# Run Batch 1–8 subsystem verification suites
npx vitest run tests/client/
```
---
## 2. Four-Tier Parity Test Suite Structure & M1–M8 Batch Alignment
The parity test suite is organized into four complementary verification tiers inside `tests/e2e-parity/`:
```
tests/e2e-parity/
├── helpers.ts # Production bindings (ClientWorld, HudModel, Viewport, InventoryPanel, FrontendRenderer, BeltModel, i18n)
├── tier1-feature-coverage.test.ts # Tier 1: 48 Feature Coverage Tests (6 per batch across Batches 1–8)
├── tier2-boundary-corner.test.ts # Tier 2: 48 Boundary & Edge Case Tests (6 per batch across Batches 1–8)
├── tier3-cross-feature.test.ts # Tier 3: 8 Pairwise Cross-Feature Integration Tests
└── tier4-real-world-scenarios.test.ts # Tier 4: 5 Full-Lifecycle Gameplay Scenarios
```
### Subsystem Batch Taxonomy (`PROJECT.md § Feature Inventory`)
All 8 subsystem batches match `PROJECT.md` verbatim across `TEST_INFRA.md`, `TEST_READY.md`, `tests/e2e-parity/`, and `tests/client/`:
- **Batch 1 (M1: `#562–#576`, 15 issues)**: **Core World, 25Hz Timing, Movement, Missiles & Combat Formulas**
- 25Hz simulation tick accumulator (`40ms` ticks), isometric 2:1 projection (`subTileToWorldOrtho`, `worldOrthoToSubTile`), `S2C 0x59` `AssignPlayer` self authority, 1.13c AR/DR hit chance & running block formulas, 8.8 fixed-point step velocity, and `Missiles.txt` range scaling.
- **Batch 2 (M2: `#624–#641`, 18 issues)**: **Automap, Minimap, Control Bar, Globes, Belt & Speedbar**
- Universal DT1 tile loading (`Blank.dt1`, `InvisWal.dt1`, `Warp.dt1`), multi-flag collision masks (`COLLIDE_BLANK | COLLIDE_WALL` synchronized with `ClientWorld.setSubTileBlocked`), SplitMix64 spatial hashing (`pickVariant`), 8-sheet automap sprite loading (`Minimap.loadAtlases`), and belt/globe HUD models.
- **Batch 3 (M3: `#642–#663`, 22 issues)**: **Fonts, PL2 Text Colors, Cursor, Tooltips, NPC Dialogue & World Panels**
- Player walk/run velocity ratios (`UnitMove`), action state machine transitions (`Neutral -> Cast -> Neutral`), one-shot cast duration from `AnimData.d2`, town walk-only posture enforcement (`isTownLevel`), and bitmap font / tooltip / NPC menu layout.
- **Batch 4 (M4: `#604–#623`, 20 issues)**: **World Renderer, Animation, DCC Paperdoll, Lighting & Shaders**
- Diminishing returns FCR/IAS/FHR formulas (`computeDiminishingRate113c`, `computeEffectiveFcr`, `computeEffectiveIas`), one-shot animation clamping (`computeAnimFrameIndex`), `Overlay.txt` / `States.txt` point lights, ground item flippy animations, and strict missing-art reporting.
- **Batch 5 (M5: `#577–#603`, 27 issues)**: **Combat, Motion Kinematics, Targeting, Overlays, Shadows & Weather**
- Single-clock 25Hz missile kinematics, `ClientUnit.lifePercent` (`0..128` -> `0..100%`) scaling, `VIEWPORT_800x600` coordinate culling (`worldToScreen`, `computeViewportAnchors`), entity/corpse/overlay depth sorting (`buildSceneDrawables`), mouse hover hitboxes (`CommandMapper.findUnitAtScreenPoint`), and `UnitReassign` server authority.
- **Batch 6 (M6: `#664–#689`, 26 issues)**: **World Panels, Inventory `inventory.txt`, Item Variants, Usables, Sockets, Skills & Character Sheet**
- Canonical `inventory.txt` 10x4 grid (`getInventoryLayout('Sorceress2')`), Horadric Cube `(198, 199)` origin and `3x4 = 12` internal grid (`getInventoryLayout('Transmogrify Box Page 1')`) vs `2x2` exterior item footprint, `BeltModel` (`getBeltRowsForCode`), unformatted integer gold/XP display (`InventoryPanel.draw`, `STASH_GOLD_CAP`), and `Misc.txt` `useable=1` right-click item usage.
- **Batch 7 (M7: `#690–#703`, 14 issues)**: **In-Game UI Overlays, Missing-Art Fail-Fast, Offline Paperdoll/Skill Tree Rules & Character Select**
- Authoritative `C2S_PACKET_SIZES` / `S2C_PACKET_SIZES` tables, `S2C 0x0D` movement packet handling, Battle.net character/account name validation (`isValidCharacterName`, `canAcceptCharNameChar`, `isValidAccountChar`), `CAMPFIRE_FLAME_CONTROL_SPEC` `(345, 470)` alignment, MCP `0x19` avatar statstring parsing (`parseMcpAvatarStatstring`), and `S2C 0x8E` corpse assignment.
- **Batch 8 (M8: `#704–#712`, 9 issues)**: **Campfire Character Creation, `D2EditBox` / `TRANS50` Controls, TBL Strings & i18n**
- `FrontendRenderer.render` `D2WinEditBox` `_` cursor 250ms blink period, `DRAWMODE_TRANS50` (`globalAlpha = 0.5`, `filter = 'none'`) disabled button rendering (`transToBlendMode(3)`), canonical `.tbl` string resolution (`resolveStringByTblId`, `lookupTbl`, `requireTbl`), fail-fast resource validation (`charSummaryToRosterCharacter`), and URL/pathname i18n language routing (`resolveLangFromPathname`).
### Tier 2: Boundary & Corner Cases (48 Tests)
Stress tests extreme numerical bounds, edge conditions, invalid inputs, and corrupt state against real production functions:
- Zero, non-finite (`NaN`/`Infinity`), and capped (`200ms`) delta times in `ClientWorld.tick`.
- Extreme negative and out-of-bounds sub-tile coordinates returning `COLLIDE_BLANK | COLLIDE_WALL` and `ClientWorld.isSubTileBlocked === true`.
- Extreme combat math limits: 0 Attack Rating, 100,000 Defense, `lifePct = 0` (`ClientUnit.dead === true`), and `[5%, 95%]` hit chance clamps.
- Diminishing return caps for Faster Cast Rate (`500%` FCR clamped to `75%`, `-500%` clamped to `-85%`).
- Inventory boundary checks via `findFreeGridSlot` and `HudModel`: `2x2` item placement at `(8, 2)` accepted vs column `9` overflow rejected, `STASH_GOLD_CAP = 2,500,000` unformatted integer rendering in `InventoryPanel.draw`, and Horadric Cube `3x4 = 12` internal slots vs `2x2` exterior item footprint.
- Frontend & i18n bounds: 250ms `_` cursor toggle across `100ms / 300ms / 600ms / 800ms` in `FrontendRenderer.render`, `TRANS50` disabled button rendering on empty `char_select` roster, and missing TBL key fallback in `lookupTbl` vs fail-fast in `requireTbl` / `resolveStringByTblId`.
### Tier 3: Pairwise Cross-Feature Interactions (8 Tests)
Verifies multi-subsystem contracts across overlapping modules:
- **X1 (Movement + Weapon Swap + Skill Cast)**: Clicking weapon swap tab (`resolveWeaponSwapTabClick`) and calling `hudModel.swapWeapons()` emits `WeaponSwitch`, updates `STAT_FASTERCASTRATE`, and interrupts run motion upon skill cast.
- **X2 (Collision + Teleport + Town Portal)**: Teleporting bypasses wall barriers (`ClientWorld.isSubTileBlocked`) and stepping into a Town Portal transitions area to town posture (`isTownLevel`).
- **X3 (Missile Trajectory + Obstacle Collision + Impact Overlay)**: Projectiles traverse open cells, impact hostile entities, and resolve canonical `Overlay.txt` impact overlays.
- **X4 (S2C Server Correction + Reassign)**: Local client prediction is authoritatively corrected by `S2C UnitReassign` packets.
- **X5 (Item Drop + Inventory Placement + UI Item Bridge)**: Ground drop entities enter container slots and produce properly formatted UI inventory items (`onlineItemDataToUiInventoryItem`).
- **X6 (Character Selection + Account Validation + Flame Anchor)**: Validates account credentials, transitions `enterCharCreate` / `selectCampfireClass`, parses MCP `0x19` statstrings (`parseMcpAvatarStatstring`), and verifies `CAMPFIRE_FLAME_CONTROL_SPEC` `(345, 470)`.
- **X7 (Line-of-Sight Raycast + Viewport Coordinate Culling)**: Bresenham raycasting determines target visibility and projects screen coordinates via `worldToScreen` and `VIEWPORT_800x600`.
- **X8 (Stamina / Posture Toggle + Block Chance Degradation)**: Running posture reduces player block chance to one-third, capped at 25% (`calculatePlayerBlockChance`).
### Tier 4: Real-World Gameplay Scenarios (5 Scenarios)
Verifies authentic full-lifecycle gameplay journeys under 1.13c ground truth:
1. **Scenario 1 — Blood Moor Clearing**: Player departs Rogue Encampment (area 1 -> 2), transitions posture from town neutral to combat, navigates terrain obstacles, defeats Fallen, takes damage, and recovers via a belt health potion (`BeltUse`).
2. **Scenario 2 — Den of Evil Completion**: Enters cave (area 8), reveals cavern rooms, clears all 5 live monsters in `ClientWorld.units` down to `0`, and receives `a1q1` (`getActQuests(1)[0]`) completion bitmask from the server.
3. **Scenario 3 — Countess Tower Run**: Descends Forgotten Tower cellars (areas 21 -> 25), battles Superunique Countess with FCR-boosted spells, slays her, and loots a guaranteed Ral Rune (`r08`) into inventory.
4. **Scenario 4 — Tristram Rescue**: Steps through Cairn Stones Red Portal into Tristram (area 38), kites Griswold over multiple 25Hz ticks, interacts with the gibbet cage (`QuestMessage`), frees Deckard Cain, and advances Quest 2.
5. **Scenario 5 — Act Boss Kill (Andariel)**: Infiltrates Catacombs Level 4 (area 39), survives Andariel's Poison Spray, fires `fireball` projectiles (`spawnMissileByKey`) reducing `andariel.lifePercent` from `100% -> 50% -> 0%`, triggers death overlays, completes `a1q6` (`getActQuests(1)[5]`), and travels with Warriv's caravan to Act 2 Lut Gholein (`getActWaypoints(2)[0].levelId === 40`).
---
## 3. Ground Truth Invariants & Simulation Contracts
1. **Diablo II v1.13c Ground Truth Invariant**:
All formulas, packet sizes, collision flags, town level IDs, and animation step calculations strictly mirror 1.13c assembly from `D2Common.dll`, `D2Game.dll`, `D2Client.dll`, and `D2Launch.dll`.
2. **Discrete 25Hz Simulation Tick**:
Simulation logic runs on fixed 40ms intervals (`D2_TICK_MS = 40`). Sub-millisecond elapsed times accumulate until 40ms threshold is reached.
3. **Universal DT1 Tiles**:
Universal DT1s (`Blank.dt1`, `InvisWal.dt1`, `Warp.dt1`) are loaded unconditionally with `COLLIDE_BLANK | COLLIDE_WALL` for void safety.
4. **SplitMix64 Spatial Hash**:
Tile variant selection uses 64-bit SplitMix64 spatial hashing to prevent 45-degree mechanical tiling artifacts.
5. **Zero Tautological / Facade Tests**:
All tests import and execute real production modules (`ClientWorld`, `ClientUnit`, `CommandMapper`, `HudModel`, `InventoryPanel`, `WorldPanelsHud`, `BeltModel`, `FrontendRenderer`, `Minimap`, `viewport-profile`, `unit-drawables`, `flow-state`, `lang`) and verify real state mutations, draw calls, container contents, and packet serialization.