Files
Deukhoofd f9878e76ba
All checks were successful
Build / Build (push) Successful in 1m7s
Adds more tests, fixes
2026-07-04 13:03:54 +02:00

140 lines
8.3 KiB
Markdown

---
name: bulbapedia-tests
description: Fetches move/ability descriptions from Bulbapedia and translates them into atomic TUnit tests in the Gen7 test project. Use when asked to write Bulbapedia-based tests for moves or abilities, e.g. "test tackle" or "write tests for all moves starting with a".
argument-hint: <target, e.g. "tackle" | "ability intimidate" | "all moves starting with a">
allowed-tools: WebFetch(domain:bulbapedia.bulbagarden.net), Read, Glob, Grep, Write(Plugins/PkmnLib.Plugin.Gen7.Tests/**), Edit(Plugins/PkmnLib.Plugin.Gen7.Tests/**), Bash(dotnet build:*), Bash(dotnet test:*)
---
# Bulbapedia → Gen7 unit tests
Generate atomic unit tests for Gen7 move/ability script implementations, using their
Bulbapedia descriptions as the source of truth for correct behavior.
## Hard constraints (tool whitelist)
- **Web access**: only `https://bulbapedia.bulbagarden.net/...` via WebFetch. Never fetch any
other domain.
- **File modifications**: only inside `Plugins/PkmnLib.Plugin.Gen7.Tests/`. Never modify the
implementation project (`Plugins/PkmnLib.Plugin.Gen7/`) or anything else — even if you find a
bug there. Reading any file in the repo is allowed and encouraged.
- **Shell**: only `dotnet build` and `dotnet test`.
## Step 1 — Resolve targets from the argument
The argument describes what to test. Interpret it and resolve it to a list of implemented
script classes:
- A single name (`tackle`, `ability intimidate`) → that one script. Default to moves; the words
"ability"/"abilities" switch to abilities.
- A pattern (`all moves starting with a`, `abilities containing 'veil'`) → enumerate with Glob
against the implementation folders:
- Moves: `Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/*.cs`
- Abilities: `Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/*.cs`
- Only test scripts that actually exist in those folders. If a requested target has no
implementation file, don't invent one — list it as skipped in the final report.
- Skip base/helper classes (e.g. `BaseChargeMove.cs`) unless explicitly requested; they are
covered through the concrete moves.
For each target, check whether `Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/{Moves,Abilities}/<ClassName>Tests.cs`
already exists. If so, extend it with missing behaviors (via Edit) instead of overwriting it,
and don't duplicate behaviors that already have a test.
## Step 2 — Fetch the Bulbapedia description
This fetch procedure is verified to work; follow it exactly.
**Primary: WebFetch the rendered wiki page.** URL conventions (spaces become underscores,
each word capitalized as on Bulbapedia; the `(move)` suffix is lowercase, `(Ability)` is
capitalized):
- Moves: `https://bulbapedia.bulbagarden.net/wiki/<Move_Name>_(move)` — e.g. `Tackle_(move)`, `Fury_Cutter_(move)`
- Abilities: `https://bulbapedia.bulbagarden.net/wiki/<Ability_Name>_(Ability)` — e.g. `Intimidate_(Ability)`
Prompt the fetch with: *"Extract the full Effect section verbatim, including all per-generation
subsections."* The Effect section is structured as a base description plus generation-delta
subsections, e.g. for Tackle: base text "Tackle inflicts damage and has no secondary effect.",
then `Generations V and VI`: "power was increased from 35 to 50...", then
`Generation VII onwards`: "power was decreased from 50 to 40."
**Fallback / exact wording: the MediaWiki API, also via WebFetch.** When the summarized page
extract seems lossy or you need the exact sentence to quote, fetch the raw wikitext (the Effect
section is normally section index 1):
- `https://bulbapedia.bulbagarden.net/w/api.php?action=parse&page=Tackle_(move)&prop=wikitext&format=json&section=1`
**Name resolution**: if unsure of the exact page title, use the API's opensearch:
- `https://bulbapedia.bulbagarden.net/w/api.php?action=opensearch&search=Fury_C&limit=5&format=json`
→ returns matching titles and URLs (e.g. `Fury Cutter (move)`).
**Deriving Gen VII behavior**: this codebase implements **Generation VII**. The Effect section
is written as deltas — start from the base description and apply every subsection whose range
includes Gen VII (`Generation VII onwards`, `Generations V to VII`, `Generation VI onwards`, ...);
ignore subsections entirely outside it (`Generation I`, `Generation VIII`, side games like
Legends: Arceus). Ability pages often use range headers like "Generations V to VII" — take the
range containing VII. Also note interactions the page calls out (e.g. "does not activate if a
Pokémon with Damp is on the field") — those are test cases too.
## Step 3 — Read the implementation
Read the script class under `Plugins/PkmnLib.Plugin.Gen7/Scripts/{Moves,Abilities}/<ClassName>.cs`
to learn which hooks it overrides (`ChangeBasePower`, `OnIncomingHit`, `OnFaint`, ...) and what
its public surface looks like. Tests drive those hook methods directly — do not test behavior
the script class isn't responsible for (type effectiveness, generic damage formula, or static
data like base power and accuracy; `DataTests/` already covers move/ability data).
## Step 4 — Write atomic tests
Follow the existing conventions — `Scripts/Moves/DrainTests.cs` and
`Scripts/Abilities/AftermathTests.cs` are the reference examples (`DrainTests.cs` also shows
`<see>` usage and a real `[TestFailing]`), `Scripts/Moves/AcrobaticsTests.cs` a minimal one:
- File: `Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/<ClassName>Tests.cs` or
`.../Scripts/Abilities/<ClassName>Tests.cs`.
- Namespace: `PkmnLib.Plugin.Gen7.Tests.Scripts.Moves` / `...Abilities`. `TUnit` and
`NSubstitute` are global usings; add the `PkmnLib.*` usings the test needs.
- **One behavior per test** (atomic). Name: `Method_Scenario_ExpectedOutcome`, e.g.
`ChangeBasePower_UserNotHoldingItem_BasePowerDoubles`.
- Each test gets an XML doc comment **quoting the Bulbapedia sentence it verifies**:
`/// Bulbapedia: "When a Pokémon with this Ability faints from damage caused by a move that makes contact, ..."`.
- In doc comments, refer to other classes and members with `<see>` tags instead of plain text —
the class-level comment references the script under test
(`/// Tests for the <see cref="Aftermath"/> ability.`), and test comments reference types or
members they mention (`/// If the attacker has no <see cref="IPokemon.BattleData"/>, ...`).
- Arrange/Act/Assert with `Substitute.For<IExecutingMove>()`, `Substitute.For<IPokemon>()`, etc.
Assertions are TUnit style: `await Assert.That(actual).IsEqualTo(expected)`.
- Use `[Arguments(...)]` rows for numeric variations (damage fractions, rounding/integer
division, overflow guards).
- Cover the negative cases the description implies (non-contact move → no trigger, holding an
item → no boost, attacker already fainted, null `BattleData`, ...).
- `LibraryHelpers.LoadLibrary()` is available when a test genuinely needs the full Gen7 library
(e.g. looking up real move data); prefer pure mocks otherwise.
## Step 5 — Build, run, and mark failures
1. Build: `dotnet build Plugins/PkmnLib.Plugin.Gen7.Tests`. Compile errors are always
test-authoring mistakes — fix them; the attribute cannot rescue non-compiling code.
2. Run the new tests: `dotnet test Plugins/PkmnLib.Plugin.Gen7.Tests` (TUnit runs on
Microsoft.Testing.Platform; to run a single class, pass
`-- --treenode-filter '/*/*/<ClassName>Tests/*'`).
3. For each failing test, decide who is wrong:
- **The test is wrong** (misread the page, wrong mock setup, asserting behavior of a
different generation) → fix the test and rerun.
- **The implementation is wrong** (test correctly encodes Gen VII Bulbapedia behavior but the
script does something else) → keep the correct assertion and add the marker so it is
skipped but tracked:
```csharp
[Test, TestFailing("Aftermath deals 1/2 max HP instead of 1/4 (Bulbapedia: '¼ of its own maximum HP')")]
```
`TestFailingAttribute` lives in `PkmnLib.Plugin.Gen7.Tests` and takes the failure reason as
its argument — describe concretely what the implementation does wrong.
- Never make a wrong test pass by asserting the buggy behavior, and never touch the
implementation to make a test pass.
4. Rerun until every test either passes or carries `[TestFailing(...)]`.
## Step 6 — Report
Summarize: tests written per target, tests marked `[TestFailing]` with their reasons (these are
implementation bugs the user needs to fix), and targets skipped because no Gen7 implementation
exists.