---
phase: 05-distribution-and-hardening
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - SharepointToolbox/Core/Helpers/ExecuteQueryRetryHelper.cs
  - SharepointToolbox/Core/Helpers/SharePointPaginationHelper.cs
  - SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs
  - SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs
  - SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs
autonomous: true
requirements:
  - FOUND-11

must_haves:
  truths:
    - "ExecuteQueryRetryHelper.IsThrottleException correctly classifies 429, 503, and throttle messages"
    - "SharePointPaginationHelper.BuildPagedViewXml injects or replaces RowLimit in CAML XML"
    - "Every EN key in Strings.resx has a non-empty, non-bracketed FR translation in Strings.fr.resx"
  artifacts:
    - path: "SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs"
      provides: "Throttle exception classification unit tests"
      min_lines: 20
    - path: "SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs"
      provides: "CAML XML RowLimit injection unit tests"
      min_lines: 20
    - path: "SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs"
      provides: "Exhaustive FR locale parity test"
      min_lines: 15
  key_links:
    - from: "SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs"
      to: "SharepointToolbox/Core/Helpers/ExecuteQueryRetryHelper.cs"
      via: "InternalsVisibleTo + internal static IsThrottleException"
      pattern: "ExecuteQueryRetryHelper\\.IsThrottleException"
    - from: "SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs"
      to: "SharepointToolbox/Core/Helpers/SharePointPaginationHelper.cs"
      via: "InternalsVisibleTo + internal static BuildPagedViewXml"
      pattern: "SharePointPaginationHelper\\.BuildPagedViewXml"
---

<objective>
Create unit tests for the retry helper, pagination helper, and locale completeness — the three testable verification axes of Phase 5. Change private static methods to internal static so tests can access them (established InternalsVisibleTo pattern from Phase 2).

Purpose: These tests prove the reliability guarantees (throttle retry, 5k-item pagination) and locale completeness that FOUND-11's success criteria require. Without them, the only verification is manual smoke testing.
Output: Three new test files, two visibility changes in helpers.
</objective>

<execution_context>
@C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/dev/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/05-distribution-and-hardening/05-RESEARCH.md

@SharepointToolbox/Core/Helpers/ExecuteQueryRetryHelper.cs
@SharepointToolbox/Core/Helpers/SharePointPaginationHelper.cs
@SharepointToolbox/Localization/Strings.resx
@SharepointToolbox/Localization/Strings.fr.resx
@SharepointToolbox/AssemblyInfo.cs
</context>

<tasks>

<task type="auto">
  <name>Task 1: Make helper methods internal static and create retry + pagination tests</name>
  <files>
    SharepointToolbox/Core/Helpers/ExecuteQueryRetryHelper.cs,
    SharepointToolbox/Core/Helpers/SharePointPaginationHelper.cs,
    SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs,
    SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs
  </files>
  <action>
1. In `ExecuteQueryRetryHelper.cs`, change `private static bool IsThrottleException(Exception ex)` to `internal static bool IsThrottleException(Exception ex)`. No other changes to the file.

2. In `SharePointPaginationHelper.cs`, change `private static string BuildPagedViewXml(string? existingXml, int rowLimit)` to `internal static string BuildPagedViewXml(string? existingXml, int rowLimit)`. No other changes.

3. Create `SharepointToolbox.Tests/Helpers/ExecuteQueryRetryHelperTests.cs`:
   - Namespace: `SharepointToolbox.Tests.Helpers`
   - Using: `SharepointToolbox.Core.Helpers`
   - `[Theory]` with `[InlineData]` for throttle messages: "The request has been throttled -- 429", "Service unavailable 503", "SharePoint has throttled your request"
   - Each creates `new Exception(message)` and asserts `ExecuteQueryRetryHelper.IsThrottleException(ex)` returns true
   - `[Fact]` for non-throttle: `new Exception("File not found")` returns false
   - `[Fact]` for nested throttle: `new Exception("outer", new Exception("429"))` — test whether inner exceptions are checked (current implementation only checks top-level Message — test should assert false to document this behavior)

4. Create `SharepointToolbox.Tests/Helpers/SharePointPaginationHelperTests.cs`:
   - Namespace: `SharepointToolbox.Tests.Helpers`
   - Using: `SharepointToolbox.Core.Helpers`
   - `[Fact]` BuildPagedViewXml_NullInput_ReturnsViewWithRowLimit: `BuildPagedViewXml(null, 2000)` returns `"<View><RowLimit>2000</RowLimit></View>"`
   - `[Fact]` BuildPagedViewXml_EmptyString_ReturnsViewWithRowLimit: same for `""`
   - `[Fact]` BuildPagedViewXml_ExistingRowLimit_Replaces: input `"<View><RowLimit>100</RowLimit></View>"` with rowLimit 2000 returns `"<View><RowLimit>2000</RowLimit></View>"`
   - `[Fact]` BuildPagedViewXml_NoRowLimit_Appends: input `"<View><Query><OrderBy><FieldRef Name='Title'/></OrderBy></Query></View>"` with rowLimit 2000 returns the same XML with `<RowLimit>2000</RowLimit>` inserted before `</View>`
   - `[Fact]` BuildPagedViewXml_WhitespaceOnly_ReturnsViewWithRowLimit: input `"   "` returns minimal view

Note: Create the `Helpers/` subdirectory under the test project if it doesn't exist.
  </action>
  <verify>
    <automated>dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --filter "ExecuteQueryRetryHelper|SharePointPagination" -v quiet</automated>
  </verify>
  <done>All retry helper and pagination helper tests pass. IsThrottleException correctly classifies 429/503/throttle messages. BuildPagedViewXml correctly handles null, empty, existing RowLimit, and missing RowLimit inputs.</done>
</task>

<task type="auto">
  <name>Task 2: Create exhaustive FR locale completeness test</name>
  <files>SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs</files>
  <action>
Create `SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs`:
- Namespace: `SharepointToolbox.Tests.Localization`
- Using: `System.Globalization`, `System.Resources`, `System.Collections`, `SharepointToolbox.Localization`

Test 1 — `[Fact] AllEnKeys_HaveNonEmptyFrTranslation`:
  - Create `ResourceManager` for `"SharepointToolbox.Localization.Strings"` using `typeof(Strings).Assembly`
  - Get the invariant resource set via `GetResourceSet(CultureInfo.InvariantCulture, true, true)`
  - Create `CultureInfo("fr")` (not "fr-FR" — the satellite assembly uses neutral "fr" culture)
  - Iterate all `DictionaryEntry` in the resource set
  - For each key: call `GetString(key, frCulture)` and assert it is not null or whitespace
  - Also assert it does not start with `"["` (bracketed fallback indicator)
  - Collect all failures into a list and assert the list is empty (single assertion with all missing keys listed in the failure message for easy debugging)

Test 2 — `[Fact] FrStrings_ContainExpectedDiacritics`:
  - Spot-check 5 known keys that MUST have diacritics after the fix in Plan 02:
    - `"transfer.mode.move"` should contain `"é"` (Deplacer -> Deplacer is wrong, Déplacer is correct)
    - `"bulksites.execute"` should contain `"é"` (Créer)
    - `"templates.list"` should contain `"è"` (Modèles)
    - `"bulk.result.success"` should contain `"é"` (Terminé, réussis, échoués)
    - `"folderstruct.library"` should contain `"è"` (Bibliothèque)
  - For each: get FR string via ResourceManager and assert it contains the expected accented character

Note: This test will FAIL until Plan 02 fixes the diacritics — that is correct TDD-style behavior. The test documents the expected state.
  </action>
  <verify>
    <automated>dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --filter "LocaleCompleteness" -v quiet</automated>
  </verify>
  <done>LocaleCompletenessTests.cs exists and compiles. Test 1 (AllEnKeys_HaveNonEmptyFrTranslation) passes (all keys have values). Test 2 (FrStrings_ContainExpectedDiacritics) fails until Plan 02 fixes diacritics — expected behavior.</done>
</task>

</tasks>

<verification>
All new tests compile and the helper tests pass:
```bash
dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --filter "ExecuteQueryRetryHelper|SharePointPagination|LocaleCompleteness" -v quiet
```
Existing test suite remains green (no regressions from visibility changes).
</verification>

<success_criteria>
- ExecuteQueryRetryHelperTests: 4+ tests pass (3 throttle-true, 1 non-throttle-false)
- SharePointPaginationHelperTests: 4+ tests pass (null, empty, replace, append)
- LocaleCompletenessTests: Test 1 passes (key parity), Test 2 may fail (diacritics pending Plan 02)
- Full existing test suite still green
</success_criteria>

<output>
After completion, create `.planning/phases/05-distribution-and-hardening/05-01-SUMMARY.md`
</output>
