113 lines
12 KiB
Markdown
113 lines
12 KiB
Markdown
# 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.
|