123 lines
4.6 KiB
Go
123 lines
4.6 KiB
Go
package analytics
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestJalaliGregorianRoundTrip(t *testing.T) {
|
||
t.Parallel()
|
||
tests := []struct {
|
||
name string
|
||
jy, jm, jd int
|
||
gy, gm, gd int
|
||
}{
|
||
{name: "Nowruz 1405", jy: 1405, jm: 1, jd: 1, gy: 2026, gm: 3, gd: 21},
|
||
{name: "leap Esfand", jy: 1399, jm: 12, jd: 30, gy: 2021, gm: 3, gd: 20},
|
||
{name: "Tir boundary", jy: 1405, jm: 4, jd: 1, gy: 2026, gm: 6, gd: 22},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
gy, gm, gd := jalaliToGregorian(tt.jy, tt.jm, tt.jd)
|
||
if gy != tt.gy || gm != tt.gm || gd != tt.gd {
|
||
t.Fatalf("jalaliToGregorian(%d,%d,%d) = %04d-%02d-%02d, want %04d-%02d-%02d", tt.jy, tt.jm, tt.jd, gy, gm, gd, tt.gy, tt.gm, tt.gd)
|
||
}
|
||
jy, jm, jd := gregorianToJalali(tt.gy, tt.gm, tt.gd)
|
||
if jy != tt.jy || jm != tt.jm || jd != tt.jd {
|
||
t.Fatalf("gregorianToJalali(%04d-%02d-%02d) = %d-%02d-%02d, want %d-%02d-%02d", tt.gy, tt.gm, tt.gd, jy, jm, jd, tt.jy, tt.jm, tt.jd)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestCompletePeriods(t *testing.T) {
|
||
t.Parallel()
|
||
location, err := time.LoadLocation("Asia/Tehran")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
datasetStart := time.Date(2026, time.January, 1, 0, 0, 0, 0, location)
|
||
datasetMax := time.Date(2026, time.June, 30, 23, 59, 0, 0, location)
|
||
|
||
periods := completePeriods(datasetStart, datasetMax, location)
|
||
if len(periods) != 212 {
|
||
t.Fatalf("completePeriods() returned %d periods, want 212", len(periods))
|
||
}
|
||
|
||
want := []struct {
|
||
index int
|
||
id, kind, start, end string
|
||
isDefault bool
|
||
}{
|
||
{index: 0, id: "d-2026-06-30", kind: "DAY", start: "2026-06-30", end: "2026-07-01"},
|
||
{index: 180, id: "d-2026-01-01", kind: "DAY", start: "2026-01-01", end: "2026-01-02"},
|
||
{index: 181, id: "w-2026-06-20", kind: "WEEK", start: "2026-06-20", end: "2026-06-27"},
|
||
{index: 205, id: "w-2026-01-03", kind: "WEEK", start: "2026-01-03", end: "2026-01-10"},
|
||
{index: 206, id: "jm-1405-03", kind: "JALALI_MONTH", start: "2026-05-22", end: "2026-06-22", isDefault: true},
|
||
{index: 210, id: "jm-1404-11", kind: "JALALI_MONTH", start: "2026-01-21", end: "2026-02-20"},
|
||
{index: 211, id: "ps-1405-01", kind: "PERSIAN_SEASON", start: "2026-03-21", end: "2026-06-22"},
|
||
}
|
||
|
||
for _, expected := range want {
|
||
period := periods[expected.index]
|
||
if period.PeriodID != expected.id || period.PeriodType != expected.kind {
|
||
t.Errorf("period[%d] identity = %s/%s, want %s/%s", expected.index, period.PeriodID, period.PeriodType, expected.id, expected.kind)
|
||
}
|
||
if got := period.LocalStartAt.Format(time.DateOnly); got != expected.start {
|
||
t.Errorf("period[%d] start = %s, want %s", expected.index, got, expected.start)
|
||
}
|
||
if got := period.LocalEndAt.Format(time.DateOnly); got != expected.end {
|
||
t.Errorf("period[%d] end = %s, want %s", expected.index, got, expected.end)
|
||
}
|
||
if period.IsDefault != expected.isDefault {
|
||
t.Errorf("period[%d] IsDefault = %v, want %v", expected.index, period.IsDefault, expected.isDefault)
|
||
}
|
||
if period.StartAt.Location() != time.UTC || period.EndAt.Location() != time.UTC {
|
||
t.Errorf("period[%d] UTC boundaries do not use UTC", expected.index)
|
||
}
|
||
}
|
||
|
||
defaultCount := 0
|
||
for _, period := range periods {
|
||
if !period.IsComplete {
|
||
t.Errorf("period %s is not complete", period.PeriodID)
|
||
}
|
||
if period.LocalStartAt.Before(datasetStart) || period.LocalEndAt.After(datasetMax.Add(time.Minute)) {
|
||
t.Errorf("period %s lies outside dataset coverage", period.PeriodID)
|
||
}
|
||
if period.IsDefault {
|
||
defaultCount++
|
||
}
|
||
}
|
||
if defaultCount != 1 {
|
||
t.Fatalf("completePeriods() returned %d defaults, want 1", defaultCount)
|
||
}
|
||
}
|
||
|
||
func TestPrecedingPeriodLabelUsesExactJalaliPeriod(t *testing.T) {
|
||
location, err := time.LoadLocation("Asia/Tehran")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
periodType string
|
||
start time.Time
|
||
want string
|
||
}{
|
||
{name: "day", periodType: "DAY", start: time.Date(2026, 7, 23, 0, 0, 0, 0, location), want: "روز ۳۱ تیر ۱۴۰۵"},
|
||
{name: "week", periodType: "WEEK", start: time.Date(2026, 8, 15, 0, 0, 0, 0, location), want: "هفته ۱۷ مرداد تا ۲۳ مرداد ۱۴۰۵"},
|
||
{name: "month", periodType: "JALALI_MONTH", start: time.Date(2026, 7, 23, 0, 0, 0, 0, location), want: "تیر ۱۴۰۵"},
|
||
{name: "season", periodType: "PERSIAN_SEASON", start: time.Date(2026, 6, 22, 0, 0, 0, 0, location), want: "بهار ۱۴۰۵"},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
got, ok := PrecedingPeriodLabel(tt.periodType, tt.start)
|
||
if !ok || got != tt.want {
|
||
t.Fatalf("PrecedingPeriodLabel() = %q, %v; want %q, true", got, ok, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|