Test project: UT-001..011 for JR-016 and JR-022
🏗️ Build Plugin / build (push) Successful in 39s
Latest Release / latest-release (push) Successful in 38s
🧪 Test Plugin / test (push) Successful in 26s

The register defined 46 requirements and zero tests, so every Done in it rested
on inspection. This adds the T1 tier: an xUnit project in the solution,
covering the two units whose logic is pure enough to test without a Jellyfin
host.

JR-022 (UT-001..006) covers the cases where removal could reach too far --
another plugin's injection, and an unmarked look-alike script tag -- because
index.html is a file JRay shares. UT-001 pins the trailing newline to the tag,
without which every install cycle leaves another blank line behind.

JR-016 (UT-007..011) covers specificity resolution, including the prioritised
series inside an ignored genre that motivated the rule, and a Series rule
valued Guid.Empty, which would otherwise swallow every movie in the library.

RemoveInjection is reached through InternalsVisibleTo rather than being made
public: it is factored out for testability, not part of the surface.

The suite BUILDS but does not RUN here. Jellyfin.Controller framework-
references Microsoft.AspNetCore.App, so the test host demands it even for pure
logic, and this machine has no ASP.NET Core runtime at any version --
RollForward cannot substitute for a framework that is absent entirely. Fix is
to install aspnet-runtime, which the CI image needs for the same reason.

So every UT here is recorded as Written, not Passing, and no requirement is
promoted to Done on their strength. A test whose result nobody has seen is not
evidence.

TRACES: UT-001, UT-002, UT-003, UT-004, UT-005, UT-006 | JR-022
TRACES: UT-007, UT-008, UT-009, UT-010, UT-011 | JR-016

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 19:12:24 +02:00
co-authored by Claude Opus 5
parent d786d56368
commit 5159692364
6 changed files with 287 additions and 6 deletions
+47 -4
View File
@@ -16,6 +16,26 @@ Tag code with `// TRACES: JR-012 | SR-002`.
| `JR` | Everything this plugin does — truth format, API, overlay, exchange client |
| `UT` / `IT` | Unit / integration tests |
## Tests (UT)
| ID | Asserts | Covers | Status |
|---|---|---|---|
| UT-001 | Marked tag **and its trailing newline** removed — no blank line accumulates per upgrade cycle | JR-022 | Written |
| UT-002 | Marked tag with no trailing newline removed | JR-022 | Written |
| UT-003 | Document without the marker left byte-identical | JR-022 | Written |
| UT-004 | Removal is idempotent — startup runs it on every boot forever after | JR-022 | Written |
| UT-005 | **Another plugin's injection left intact** — it is their file too | JR-022 | Written |
| UT-006 | An unmarked look-alike script tag is left alone — JRay did not write it | JR-022 | Written |
| UT-007 | No matching rule resolves to `null` | JR-016 | Written |
| UT-008 | Item rule beats Series rule | JR-016 | Written |
| UT-009 | **Prioritised series inside an ignored genre — series wins** | JR-016 | Written |
| UT-010 | Genre matching is case-insensitive | JR-016 | Written |
| UT-011 | A Series rule valued `Guid.Empty` does not swallow every movie | JR-016 | Written |
`Written` rather than `Passing`: see the execution blocker below. A test whose
result nobody has seen is not evidence, and recording it as passing would be the
same failure as counting a GPU-only test as covered.
`JR` is flat rather than split by theme. The plugin is one deployable with one
audience, and the thematic grouping lives in the section headings below, where it
costs nothing and cannot go stale against a prefix.
@@ -167,9 +187,32 @@ renumbering it. Calling jRay's live tier "T3" would make the gate count
live-only requirements as covered — the exact class of error the 158% coverage
bug belongs to.
**There is no test project today.** That is the single largest gap in this
register: 46 requirements, zero `UT`/`IT` IDs, so measured coverage will open at
zero and every `Done` above rests on inspection rather than evidence.
`Jellyfin.Plugin.JRay.Tests` (xUnit, in the solution) carries the T1 tier. It
builds clean alongside the plugin.
### Execution blocker — the suite does not run on this machine
The plugin framework-references **`Microsoft.AspNetCore.App`** through
`Jellyfin.Controller`, so the test host demands that shared framework even for
tests that touch only pure logic. This box has `Microsoft.NETCore.App` 8.0.29
and 10.0.10 and **no ASP.NET Core runtime at all**, so `dotnet test` aborts
before a single test executes:
```
Framework: 'Microsoft.AspNetCore.App', version '9.0.0' — No frameworks were found.
```
`<RollForward>LatestMajor</RollForward>` on the test project solves the *other*
half — the plugin targets `net9.0` to match Jellyfin's ABI, and no .NET 9
runtime is installed either — but roll-forward cannot conjure a framework of
which no version exists.
**Fix:** install the ASP.NET Core runtime (`aspnet-runtime` on Arch). It is
needed on the CI host for the same reason, so this belongs in the CI image
rather than in a developer's setup notes.
Until then every `UT` above is **Written, not Passing**, and no requirement
should be promoted to `Done` on the strength of them.
### Per-requirement verification plan
@@ -243,7 +286,7 @@ python3 scripts/vendor/jray-project/scripts/traceability/extract_traces.py \
--system-spec scripts/vendor/jray-project/SPEC.md \
--types JR \
--suffixes .cs,.js,.sh \
--scan-roots Jellyfin.Plugin.JRay,scripts/checks \
--scan-roots Jellyfin.Plugin.JRay,Jellyfin.Plugin.JRay.Tests,scripts/checks \
--format coverage
```