Closes the XMLTV-guide half of #28 (follow-up to #11's M3U goldens). The channel-logo image test is deliberately not included — see below.
What
ChannelGuideGoldenTests drives the real GetChannelGuideHandler against a Testably fake filesystem (seeded channels.xml + per-channel fragments) and a SQLite-backed IDbContextFactory<TvContext>, then snapshots ChannelGuide.ToXml() to goldens under Iptv/Goldens/guide-*.xml. Same [CallerFilePath] + ETV_UPDATE_GOLDENS harness as the M3U goldens.
Locks the surfaces a guide regression would hit:
{RequestBase} host substitution — the XMLTV counterpart to the #1 regression net.
{AccessTokenUri} — with and without an access token.
etv:-tag stripping — both paired and self-closing forms.
hidden-channel exclusion — ShowInEpg=false channel keeps its <channel> def but drops its programme.
decimal fragment ordering — channels 2 and 10 prove the sort is decimal, not string.
external icon URL passthrough.
The volatile ?v={mtime} cache-buster is normalized; output is OS-independent (static time literals, single-line, LF, BOM stripped).
Adversarial-review fixes folded in
Removed a dead/leaking TvContext.IsSqlite static; made decimal ordering actually exercised (was vacuous with one fragment); canonicalized a trailing newline so the goldens satisfy .editorconfig; included channels.xml in the ListFiles mock to hit the skip branch; switched seeding to EnsureCreatedAsync (suite back to ~2s).
Deliberately deferred
Channel-logo image test — ChannelLogoGenerator loads its font from a global ResourcesCacheFolder path and its overlay from a hardcoded relative path, and SkiaSharp isn't byte-reproducible; a clean test needs a small DI refactor. Tracked as #39. (#28's text pre-authorized skipping it.)
Verification
Full ErsatzTV.Core.Tests: 484 passed, 0 failed (TZ=UTC).
Closes the XMLTV-guide half of #28 (follow-up to #11's M3U goldens). The channel-logo image test is deliberately **not** included — see below.
## What
`ChannelGuideGoldenTests` drives the real `GetChannelGuideHandler` against a Testably fake filesystem (seeded `channels.xml` + per-channel fragments) and a SQLite-backed `IDbContextFactory<TvContext>`, then snapshots `ChannelGuide.ToXml()` to goldens under `Iptv/Goldens/guide-*.xml`. Same `[CallerFilePath]` + `ETV_UPDATE_GOLDENS` harness as the M3U goldens.
Locks the surfaces a guide regression would hit:
- **`{RequestBase}` host substitution** — the XMLTV counterpart to the #1 regression net.
- `{AccessTokenUri}` — with and without an access token.
- **etv:-tag stripping** — both paired and self-closing forms.
- **hidden-channel exclusion** — `ShowInEpg=false` channel keeps its `<channel>` def but drops its programme.
- **decimal fragment ordering** — channels `2` and `10` prove the sort is decimal, not string.
- external icon URL passthrough.
The volatile `?v={mtime}` cache-buster is normalized; output is OS-independent (static time literals, single-line, LF, BOM stripped).
## Adversarial-review fixes folded in
Removed a dead/leaking `TvContext.IsSqlite` static; made decimal ordering actually exercised (was vacuous with one fragment); canonicalized a trailing newline so the goldens satisfy `.editorconfig`; included `channels.xml` in the `ListFiles` mock to hit the skip branch; switched seeding to `EnsureCreatedAsync` (suite back to ~2s).
## Deliberately deferred
Channel-logo image test — `ChannelLogoGenerator` loads its font from a global `ResourcesCacheFolder` path and its overlay from a hardcoded relative path, and SkiaSharp isn't byte-reproducible; a clean test needs a small DI refactor. Tracked as **#39**. (#28's text pre-authorized skipping it.)
## Verification
Full `ErsatzTV.Core.Tests`: 484 passed, 0 failed (`TZ=UTC`).
refs #28
Drive the real GetChannelGuideHandler against a Testably fake filesystem
(seeded channels.xml + per-channel fragments) and a SQLite-backed
IDbContextFactory with one visible + one ShowInEpg=false channel, then
snapshot ChannelGuide.ToXml(). Covers the {RequestBase}/{AccessTokenUri}
substitution (the #1 regression surface), etv:-tag stripping, hidden-channel
exclusion, and assembly — with/without access token and with a base URL.
The volatile ?v={mtime} cache-buster is normalized. Same [CallerFilePath]
Goldens + ETV_UPDATE_GOLDENS harness as the M3U goldens (#11).
Core.Tests now references ErsatzTV.Application (handler lives there).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
timothy
merged commit 38e743d3cf into main2026-06-27 14:11:20 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes the XMLTV-guide half of #28 (follow-up to #11's M3U goldens). The channel-logo image test is deliberately not included — see below.
What
ChannelGuideGoldenTestsdrives the realGetChannelGuideHandleragainst a Testably fake filesystem (seededchannels.xml+ per-channel fragments) and a SQLite-backedIDbContextFactory<TvContext>, then snapshotsChannelGuide.ToXml()to goldens underIptv/Goldens/guide-*.xml. Same[CallerFilePath]+ETV_UPDATE_GOLDENSharness as the M3U goldens.Locks the surfaces a guide regression would hit:
{RequestBase}host substitution — the XMLTV counterpart to the #1 regression net.{AccessTokenUri}— with and without an access token.ShowInEpg=falsechannel keeps its<channel>def but drops its programme.2and10prove the sort is decimal, not string.The volatile
?v={mtime}cache-buster is normalized; output is OS-independent (static time literals, single-line, LF, BOM stripped).Adversarial-review fixes folded in
Removed a dead/leaking
TvContext.IsSqlitestatic; made decimal ordering actually exercised (was vacuous with one fragment); canonicalized a trailing newline so the goldens satisfy.editorconfig; includedchannels.xmlin theListFilesmock to hit the skip branch; switched seeding toEnsureCreatedAsync(suite back to ~2s).Deliberately deferred
Channel-logo image test —
ChannelLogoGeneratorloads its font from a globalResourcesCacheFolderpath and its overlay from a hardcoded relative path, and SkiaSharp isn't byte-reproducible; a clean test needs a small DI refactor. Tracked as #39. (#28's text pre-authorized skipping it.)Verification
Full
ErsatzTV.Core.Tests: 484 passed, 0 failed (TZ=UTC).refs #28
Drive the real GetChannelGuideHandler against a Testably fake filesystem (seeded channels.xml + per-channel fragments) and a SQLite-backed IDbContextFactory with one visible + one ShowInEpg=false channel, then snapshot ChannelGuide.ToXml(). Covers the {RequestBase}/{AccessTokenUri} substitution (the #1 regression surface), etv:-tag stripping, hidden-channel exclusion, and assembly — with/without access token and with a base URL. The volatile ?v={mtime} cache-buster is normalized. Same [CallerFilePath] Goldens + ETV_UPDATE_GOLDENS harness as the M3U goldens (#11). Core.Tests now references ErsatzTV.Application (handler lives there). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>