---
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.
