package scheduler import ( "testing" "time" "veola/internal/models" ) func bestItem(best, target float64) models.Item { bp := best it := models.Item{BestPrice: &bp} if target > 0 { t := target it.TargetPrice = &t } return it } func TestPickBadgeAllTimeLow(t *testing.T) { now := time.Now() hist := []models.PricePoint{ {Price: 100, PolledAt: now.Add(-40 * 24 * time.Hour)}, {Price: 80, PolledAt: now.Add(-10 * 24 * time.Hour)}, {Price: 60, PolledAt: now.Add(-1 * 24 * time.Hour)}, } it := bestItem(50, 0) got := PickBadge(it, hist, now) if got.Label != "All-time low" { t.Errorf("expected all-time low, got %q", got.Label) } } func TestPickBadgeBelowAverage(t *testing.T) { now := time.Now() hist := []models.PricePoint{ {Price: 100, PolledAt: now.Add(-25 * 24 * time.Hour)}, {Price: 100, PolledAt: now.Add(-10 * 24 * time.Hour)}, {Price: 100, PolledAt: now.Add(-5 * 24 * time.Hour)}, } it := bestItem(80, 0) // 20% below 100 avg, not lowest because there's no lower in history but best is below points // add an older lower point so all-time-low is NOT triggered hist = append(hist, models.PricePoint{Price: 70, PolledAt: now.Add(-90 * 24 * time.Hour)}) got := PickBadge(it, hist, now) if got.Label != "20% below 30-day avg" { t.Errorf("expected 20%% below 30-day avg, got %q", got.Label) } } func TestPickBadgeBelowTarget(t *testing.T) { now := time.Now() // 30-day window mean equals best (50) so avg badge does not fire. // An older lower point disables the all-time-low badge. hist := []models.PricePoint{ {Price: 50, PolledAt: now.Add(-2 * 24 * time.Hour)}, {Price: 50, PolledAt: now.Add(-1 * 24 * time.Hour)}, {Price: 40, PolledAt: now.Add(-90 * 24 * time.Hour)}, } it := bestItem(50, 100) // 50% below target got := PickBadge(it, hist, now) if got.Label != "50% below target" { t.Errorf("expected 50%% below target, got %q", got.Label) } } func TestPickBadgeNone(t *testing.T) { now := time.Now() // best matches recent avg, no target, and an older lower point exists - // no badge should fire. hist := []models.PricePoint{ {Price: 50, PolledAt: now.Add(-1 * 24 * time.Hour)}, {Price: 40, PolledAt: now.Add(-90 * 24 * time.Hour)}, } it := bestItem(50, 0) got := PickBadge(it, hist, now) if got.Label != "" { t.Errorf("expected no badge, got %q", got.Label) } } func TestPickBadgeIgnoresShortAvgGap(t *testing.T) { now := time.Now() hist := []models.PricePoint{ {Price: 100, PolledAt: now.Add(-1 * 24 * time.Hour)}, {Price: 95, PolledAt: now.Add(-2 * 24 * time.Hour)}, } // best 92 is only ~5.6% below avg 97.5 — under the 10% floor older := models.PricePoint{Price: 80, PolledAt: now.Add(-90 * 24 * time.Hour)} hist = append(hist, older) it := bestItem(92, 0) got := PickBadge(it, hist, now) if got.Label != "" { t.Errorf("expected no badge for <10%% gap, got %q", got.Label) } }