Files
memby/server/internal/credits/window_test.go
T

139 lines
5.3 KiB
Go
Raw Normal View History

2026-08-15 09:23:26 +12:00
package credits
import (
"testing"
"time"
)
// The scan window is where the performance claim is kept or given away, so these tests are
// about size: how much of a file each source of evidence lets us avoid reading.
const bbRuntime = 44*60*1000 + 12*1000 // 44:12
func TestGenericTailIsBoundedBothWays(t *testing.T) {
// A short episode still gets a usable window.
short := GenericTailWindow(18 * 60 * 1000)
if short.DurationMs() < genericTailMinimum.Milliseconds() {
t.Fatalf("short episode window was %v, below the floor", short.DurationMs())
}
// A three-hour film does not turn into a thirty-six minute scan.
long := GenericTailWindow(3 * 60 * 60 * 1000)
if long.DurationMs() > genericTailMaximum.Milliseconds() {
t.Fatalf("film window was %v, past the ceiling", long.DurationMs())
}
if long.EndMs != 3*60*60*1000 {
t.Fatal("the window must run to the end of the file")
}
if long.Source != WindowGeneric {
t.Fatalf("source = %q, want %q", long.Source, WindowGeneric)
}
}
func TestNoRuntimeMeansNoWindow(t *testing.T) {
if GenericTailWindow(0).Valid() {
t.Fatal("a file with no runtime produced a scannable window")
}
}
// The optimisation the brief calls one of the most important: knowing where this show puts
// its credits should turn a ten-minute tail into a couple of minutes.
func TestSeasonHistoryNarrowsTheScan(t *testing.T) {
// Blue Bloods S06E0406, credits around 40:50 of a ~44 minute episode.
history := []Marker{
{CreditsStartMs: 40*60*1000 + 51*1000, Confidence: 0.92},
{CreditsStartMs: 40*60*1000 + 47*1000, Confidence: 0.90},
{CreditsStartMs: 40*60*1000 + 50*1000, Confidence: 0.94},
}
runtimeOf := func(Marker) int64 { return bbRuntime }
generic := GenericTailWindow(bbRuntime)
narrowed := NarrowWindow(bbRuntime, history, runtimeOf, BehaviourEvidence{})
if narrowed.Source != WindowSeason {
t.Fatalf("source = %q, want %q", narrowed.Source, WindowSeason)
}
if narrowed.DurationMs() >= generic.DurationMs() {
t.Fatalf("season history did not narrow anything: %v vs generic %v",
narrowed.DurationMs(), generic.DurationMs())
}
// The brief's example expects roughly 39:3042:00 for an expected 40:45.
expected := int64(40*60+50) * 1000
if narrowed.StartMs > expected || narrowed.EndMs < expected {
t.Fatalf("window %v%v does not contain the expected position %v",
narrowed.StartMs, narrowed.EndMs, expected)
}
}
// The rule that stops one wrong marker propagating through a whole season.
func TestASingleMarkerIsNotEnoughToNarrow(t *testing.T) {
history := []Marker{{CreditsStartMs: 40*60*1000 + 51*1000, Confidence: 0.95}}
window := NarrowWindow(bbRuntime, history, func(Marker) int64 { return bbRuntime },
BehaviourEvidence{})
if window.Source != WindowGeneric {
t.Fatalf("source = %q; one marker is an anecdote, not a pattern", window.Source)
}
}
func TestInconsistentSeasonFallsBackToTheGenericTail(t *testing.T) {
// A show whose known markers are minutes apart is telling us its episodes are not
// structurally alike, so their average points nowhere useful.
history := []Marker{
{CreditsStartMs: 36 * 60 * 1000, Confidence: 0.9},
{CreditsStartMs: 41 * 60 * 1000, Confidence: 0.9},
{CreditsStartMs: 39 * 60 * 1000, Confidence: 0.9},
}
window := NarrowWindow(bbRuntime, history, func(Marker) int64 { return bbRuntime },
BehaviourEvidence{})
if window.Source != WindowGeneric {
t.Fatalf("source = %q, want the generic fallback", window.Source)
}
}
func TestLowConfidenceHistoryDoesNotSteerAScan(t *testing.T) {
history := []Marker{
{CreditsStartMs: 40*60*1000 + 51*1000, Confidence: 0.4},
{CreditsStartMs: 40*60*1000 + 47*1000, Confidence: 0.3},
}
window := NarrowWindow(bbRuntime, history, func(Marker) int64 { return bbRuntime },
BehaviourEvidence{})
if window.Source != WindowGeneric {
t.Fatalf("source = %q; a doubtful marker must not decide where everything else looks",
window.Source)
}
}
// Behaviour is a direct observation of this episode, where season history is an inference
// from its neighbours, so it wins.
func TestBehaviourOutranksSeasonHistory(t *testing.T) {
history := []Marker{
{CreditsStartMs: 40*60*1000 + 51*1000, Confidence: 0.92},
{CreditsStartMs: 40*60*1000 + 47*1000, Confidence: 0.90},
}
evidence := BehaviourEvidence{
Found: true, StartMs: 41*60*1000 + 30*1000, UserCount: 3, SpreadMs: 3000,
}
window := NarrowWindow(bbRuntime, history, func(Marker) int64 { return bbRuntime }, evidence)
if window.Source != WindowBehaviour {
t.Fatalf("source = %q, want %q", window.Source, WindowBehaviour)
}
if window.StartMs > evidence.StartMs || window.EndMs < evidence.StartMs {
t.Fatal("the window does not contain the observed cluster")
}
}
func TestNarrowedWindowsCarryAMargin(t *testing.T) {
evidence := BehaviourEvidence{
Found: true, StartMs: 40 * 60 * 1000, UserCount: 3, SpreadMs: 2000,
}
window := NarrowWindow(bbRuntime, nil, nil, evidence)
// Nothing here is precise enough to scan a single instant, and being slightly early is
// the harmless direction — but the margin has to exist on both sides.
if window.StartMs >= evidence.StartMs || window.EndMs <= evidence.StartMs {
t.Fatalf("window %v%v has no margin around %v",
window.StartMs, window.EndMs, evidence.StartMs)
}
if window.DurationMs() > 2*narrowMargin.Milliseconds()+time.Second.Milliseconds() {
t.Fatalf("narrowed window is %v; wider than the margin allows", window.DurationMs())
}
}