package creator import ( "testing" "time" ) func TestComputeWorkGrowth(t *testing.T) { now := time.Date(2026, 9, 27, 12, 0, 0, 0, time.UTC) likes := func(at time.Time, value int64) MetricPoint { return MetricPoint{CollectedAt: at, Likes: &value} } tooOld := now.Add(-72 * time.Hour) t.Run("full baseline inside window", func(t *testing.T) { points := []MetricPoint{ likes(tooOld, 100), likes(now.Add(-25*time.Hour), 200), // 窗口起点前最近点 → 基线 likes(now.Add(-2*time.Hour), 500), } growth := computeWorkGrowth(points, now, 24) if growth.Likes == nil || *growth.Likes != 300 || growth.Coverage != "full" { t.Fatalf("unexpected growth: %+v", growth) } }) t.Run("partial when only one point", func(t *testing.T) { points := []MetricPoint{likes(now.Add(-2*time.Hour), 500)} growth := computeWorkGrowth(points, now, 24) if growth.Likes == nil || *growth.Likes != 0 || growth.Coverage != "partial" { t.Fatalf("unexpected growth: %+v", growth) } }) t.Run("partial falls back to first point", func(t *testing.T) { points := []MetricPoint{likes(now.Add(-20*time.Hour), 100), likes(now.Add(-2*time.Hour), 500)} growth := computeWorkGrowth(points, now, 24) // 两个点都在窗口内、窗口前无基线 → 以首点近似,partial。 if growth.Likes == nil || *growth.Likes != 400 || growth.Coverage != "partial" { t.Fatalf("unexpected growth: %+v likes=%v", growth, *growth.Likes) } }) t.Run("old pre-window baseline counts as full", func(t *testing.T) { points := []MetricPoint{likes(tooOld, 100), likes(now.Add(-2*time.Hour), 500)} growth := computeWorkGrowth(points, now, 24) // 窗口前存在真实基线(72h 前)→ full;增量跨 72h 但可比。 if growth.Likes == nil || *growth.Likes != 400 || growth.Coverage != "full" { t.Fatalf("unexpected growth: %+v", growth) } }) t.Run("no points", func(t *testing.T) { if growth := (WorkGrowth{}); computeWorkGrowth(nil, now, 24) != growth { t.Fatal("empty points must yield zero growth") } }) } func TestApplyWorkGrowthFilterSortsAndFilters(t *testing.T) { mk := func(id string, growth int64) (Work, WorkGrowth) { value := growth return Work{ID: id}, WorkGrowth{Likes: &value, Coverage: "full"} } w1, g1 := mk("a", 100) w2, g2 := mk("b", 900) w3, _ := mk("c", 0) // 无采样点:不附加增速 works := []Work{w1, w2, w3} growth := map[string]WorkGrowth{"a": g1, "b": g2} min := int64(50) filtered, err := ApplyWorkGrowthFilter(works, growth, WorkGrowthFilter{Hours: 24, MinLikes: &min}) if err != nil { t.Fatal(err) } if len(filtered) != 2 || filtered[0].ID != "b" || filtered[1].ID != "a" { t.Fatalf("unexpected filter/sort result: %+v", filtered) } if filtered[0].LikesGrowth == nil || *filtered[0].LikesGrowth != 900 { t.Fatalf("growth not attached: %+v", filtered[0]) } }