package abono_test import ( "testing" "time" "amadan.net/rastrillo/abono" ) func TestDescribe(t *testing.T) { now := t0 end := now.Add(10 * day) past := now.Add(-5 * day) ptr := func(v time.Time) *time.Time { return &v } for _, c := range []struct { name string h abono.Holding key string tone string date *time.Time }{ {"active, no date known", abono.Holding{Source: abono.SourceSubscription, Status: "active"}, "abono.status.active", "positive", nil}, {"renews", abono.Holding{Source: abono.SourceSubscription, Status: "active", Until: &end}, "abono.status.renews", "positive", &end}, {"trialing renews", abono.Holding{Source: abono.SourceSubscription, Status: "trialing", Until: &end}, "abono.status.renews", "positive", &end}, {"cancelling", abono.Holding{Source: abono.SourceSubscription, Status: "active", Until: &end, CancelAtPeriodEnd: true}, "abono.status.cancelling", "warning", &end}, // failing (ruling R21): access stops 30 days after the unpaid // period started, whatever its end says. {"failing, before the period start", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: &end, Until: ptr(end.AddDate(1, 0, 0))}, "abono.status.failing", "warning", ptr(end.Add(30 * day))}, {"failing, held by the backstop", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: &past, Until: ptr(past.AddDate(1, 0, 0))}, "abono.status.failing", "warning", ptr(past.Add(30 * day))}, {"failing and cancelling reads as failing", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: &past, Until: ptr(past.AddDate(1, 0, 0)), CancelAtPeriodEnd: true}, "abono.status.failing", "warning", ptr(past.Add(30 * day))}, // R30: with no period start the 30 days count from the period end. {"failing with no period start counts from the period end", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", Until: &end}, "abono.status.failing", "warning", ptr(end.Add(30 * day))}, {"failing and cancelling stops at the period end when that is sooner", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: ptr(end.Add(-20 * day)), Until: &end, CancelAtPeriodEnd: true}, "abono.status.failing", "warning", &end}, {"ended, past_due with no period at all", abono.Holding{Source: abono.SourceSubscription, Status: "past_due"}, "abono.status.ended", "neutral", nil}, {"failing one second before start+30d", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: ptr(now.Add(-30*day + time.Second)), Until: ptr(now.AddDate(1, 0, 0))}, "abono.status.failing", "warning", ptr(now.Add(time.Second))}, {"ended, past_due at exactly start+30d", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: ptr(now.Add(-30 * day)), Until: ptr(now.AddDate(1, 0, 0))}, "abono.status.ended", "neutral", nil}, {"ended, cancelling and its period is over", abono.Holding{Source: abono.SourceSubscription, Status: "active", Until: &past, CancelAtPeriodEnd: true}, "abono.status.ended", "neutral", nil}, {"ended, cancelling trial at its period end", abono.Holding{Source: abono.SourceSubscription, Status: "trialing", Until: &now, CancelAtPeriodEnd: true}, "abono.status.ended", "neutral", nil}, {"ended, canceled", abono.Holding{Source: abono.SourceSubscription, Status: "canceled", Until: &past}, "abono.status.ended", "neutral", nil}, {"ended, past_due beyond the backstop", abono.Holding{Source: abono.SourceSubscription, Status: "past_due", PeriodStart: ptr(now.Add(-31 * day)), Until: ptr(now.AddDate(1, 0, 0))}, "abono.status.ended", "neutral", nil}, {"ended, a comp past its end", abono.Holding{Source: abono.SourceComp, Status: "active", Until: &past}, "abono.status.ended", "neutral", nil}, {"ended, a canceled comp", abono.Holding{Source: abono.SourceComp, Status: "canceled"}, "abono.status.ended", "neutral", nil}, {"comp", abono.Holding{Source: abono.SourceComp, Status: "active"}, "abono.status.comp", "positive", nil}, {"comp until", abono.Holding{Source: abono.SourceComp, Status: "active", Until: &end}, "abono.status.comp_until", "positive", &end}, } { t.Run(c.name, func(t *testing.T) { got := abono.Describe(c.h, now) if got.Key != c.key || got.Tone != c.tone { t.Errorf("Describe = %s/%s, want %s/%s", got.Key, got.Tone, c.key, c.tone) } if (got.Date == nil) != (c.date == nil) || (got.Date != nil && !got.Date.Equal(*c.date)) { t.Errorf("Date = %v, want %v", got.Date, c.date) } }) } }