gogcli/internal/timeparse/parse_test.go
2026-04-20 14:03:01 +01:00

210 lines
6.4 KiB
Go

package timeparse
import (
"testing"
"time"
)
//nolint:wsl_v5
func TestParseDate(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
value string
wantErr bool
}{
{name: "valid", value: "2026-02-13"},
{name: "trimmed", value: " 2026-02-13 "},
{name: "invalid separator", value: "2026/02/13", wantErr: true},
{name: "empty", value: "", wantErr: true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := ParseDate(tc.value)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error")
}
return
}
if err != nil {
t.Fatalf("ParseDate: %v", err)
}
if got.Format("2006-01-02") != "2026-02-13" {
t.Fatalf("unexpected date: %s", got.Format("2006-01-02"))
}
})
}
}
//nolint:wsl_v5
func TestParseDateTimeOrDate(t *testing.T) {
t.Parallel()
loc := time.FixedZone("Offset", -8*3600)
testCases := []struct {
name string
value string
wantErr bool
wantHasTime bool
wantHour int
wantMin int
wantOffset int
}{
{name: "rfc3339", value: "2026-02-13T10:20:30Z", wantHasTime: true, wantHour: 10, wantMin: 20, wantOffset: 0},
{name: "rfc3339 nano", value: "2026-02-13T10:20:30.123456789Z", wantHasTime: true, wantHour: 10, wantMin: 20, wantOffset: 0},
{name: "iso tz no colon", value: "2026-02-13T10:20:30-0800", wantHasTime: true, wantHour: 10, wantMin: 20, wantOffset: -8 * 3600},
{name: "date only", value: "2026-02-13", wantHasTime: false, wantHour: 0, wantMin: 0, wantOffset: -8 * 3600},
{name: "local datetime seconds", value: "2026-02-13T10:20:30", wantHasTime: true, wantHour: 10, wantMin: 20, wantOffset: -8 * 3600},
{name: "local datetime minutes", value: "2026-02-13 10:20", wantHasTime: true, wantHour: 10, wantMin: 20, wantOffset: -8 * 3600},
{name: "invalid", value: "nope", wantErr: true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := ParseDateTimeOrDate(tc.value, loc)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error")
}
return
}
if err != nil {
t.Fatalf("ParseDateTimeOrDate: %v", err)
}
if got.HasTime != tc.wantHasTime {
t.Fatalf("HasTime=%v want %v", got.HasTime, tc.wantHasTime)
}
if got.Time.Hour() != tc.wantHour || got.Time.Minute() != tc.wantMin {
t.Fatalf("unexpected time: %v", got.Time)
}
_, offset := got.Time.Zone()
if offset != tc.wantOffset {
t.Fatalf("offset=%d want %d", offset, tc.wantOffset)
}
})
}
}
//nolint:wsl_v5
func TestParseRangeExpr(t *testing.T) {
t.Parallel()
now := time.Date(2026, 2, 13, 15, 45, 0, 0, time.UTC)
loc := time.FixedZone("Offset", -5*3600)
testCases := []struct {
name string
value string
wantErr bool
wantDay int
wantMonth time.Month
wantHour int
wantWeek time.Weekday
}{
{name: "now", value: "now", wantDay: 13, wantMonth: time.February, wantHour: 15, wantWeek: time.Friday},
{name: "today", value: "today", wantDay: 13, wantMonth: time.February, wantHour: 0, wantWeek: time.Friday},
{name: "tomorrow", value: "tomorrow", wantDay: 14, wantMonth: time.February, wantHour: 0, wantWeek: time.Saturday},
{name: "weekday", value: "monday", wantDay: 16, wantMonth: time.February, wantHour: 0, wantWeek: time.Monday},
{name: "tuesday alias", value: "tues", wantDay: 17, wantMonth: time.February, wantHour: 0, wantWeek: time.Tuesday},
{name: "thursday alias short", value: "thur", wantDay: 19, wantMonth: time.February, wantHour: 0, wantWeek: time.Thursday},
{name: "thursday alias common", value: "thurs", wantDay: 19, wantMonth: time.February, wantHour: 0, wantWeek: time.Thursday},
{name: "next weekday", value: "next friday", wantDay: 20, wantMonth: time.February, wantHour: 0, wantWeek: time.Friday},
{name: "date", value: "2026-02-01", wantDay: 1, wantMonth: time.February, wantHour: 0, wantWeek: time.Sunday},
{name: "datetime", value: "2026-02-01T10:30:00", wantDay: 1, wantMonth: time.February, wantHour: 10, wantWeek: time.Sunday},
{name: "invalid", value: "yolo", wantErr: true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := ParseRangeExpr(tc.value, now, loc)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error")
}
return
}
if err != nil {
t.Fatalf("ParseRangeExpr: %v", err)
}
if got.Day() != tc.wantDay || got.Month() != tc.wantMonth || got.Hour() != tc.wantHour || got.Weekday() != tc.wantWeek {
t.Fatalf("unexpected parsed range: %v", got)
}
})
}
}
func TestParseWeekdayName(t *testing.T) {
t.Parallel()
testCases := []struct {
value string
want time.Weekday
}{
{value: "tue", want: time.Tuesday},
{value: "tues", want: time.Tuesday},
{value: "thurs", want: time.Thursday},
{value: " Thursday ", want: time.Thursday},
}
for _, tc := range testCases {
t.Run(tc.value, func(t *testing.T) {
t.Parallel()
got, ok := ParseWeekdayName(tc.value)
if !ok || got != tc.want {
t.Fatalf("ParseWeekdayName(%q) = %v ok=%v, want %v true", tc.value, got, ok, tc.want)
}
})
}
}
//nolint:wsl_v5
func TestParseSince(t *testing.T) {
t.Parallel()
now := time.Date(2026, 2, 13, 15, 45, 0, 0, time.UTC)
loc := time.FixedZone("Offset", -8*3600)
testCases := []struct {
name string
value string
wantErr bool
want time.Time
wantNano bool
}{
{name: "duration", value: "24h", want: now.Add(-24 * time.Hour).UTC()},
{name: "date", value: "2026-02-01", want: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC)},
{name: "rfc3339", value: "2026-02-01T10:20:30Z", want: time.Date(2026, 2, 1, 10, 20, 30, 0, time.UTC)},
{name: "rfc3339nano", value: "2026-02-01T10:20:30.123456789Z", want: time.Date(2026, 2, 1, 10, 20, 30, 123456789, time.UTC), wantNano: true},
{name: "local datetime", value: "2026-02-01 10:20", want: time.Date(2026, 2, 1, 18, 20, 0, 0, time.UTC)},
{name: "invalid", value: "nope", wantErr: true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := ParseSince(tc.value, now, loc)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error")
}
return
}
if err != nil {
t.Fatalf("ParseSince: %v", err)
}
if !got.Time.Equal(tc.want) {
t.Fatalf("time=%v want %v", got.Time, tc.want)
}
if got.UseRFC3339Nano != tc.wantNano {
t.Fatalf("UseRFC3339Nano=%v want %v", got.UseRFC3339Nano, tc.wantNano)
}
})
}
}