This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
package timeext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFromNanoseconds(t *testing.T) {
|
||||
if got := FromNanoseconds(0); got != 0 {
|
||||
t.Errorf("expected 0, got %v", got)
|
||||
}
|
||||
if got := FromNanoseconds(1); got != time.Nanosecond {
|
||||
t.Errorf("expected 1ns, got %v", got)
|
||||
}
|
||||
if got := FromNanoseconds(1000); got != 1000*time.Nanosecond {
|
||||
t.Errorf("expected 1000ns, got %v", got)
|
||||
}
|
||||
if got := FromNanoseconds(int64(123456789)); got != time.Duration(123456789) {
|
||||
t.Errorf("expected 123456789ns, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromMicroseconds(t *testing.T) {
|
||||
if got := FromMicroseconds(1); got != time.Microsecond {
|
||||
t.Errorf("expected 1us, got %v", got)
|
||||
}
|
||||
if got := FromMicroseconds(1000); got != time.Millisecond {
|
||||
t.Errorf("expected 1ms, got %v", got)
|
||||
}
|
||||
if got := FromMicroseconds(2.5); got != time.Microsecond*2+time.Nanosecond*500 {
|
||||
t.Errorf("expected 2.5us, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromMilliseconds(t *testing.T) {
|
||||
if got := FromMilliseconds(1); got != time.Millisecond {
|
||||
t.Errorf("expected 1ms, got %v", got)
|
||||
}
|
||||
if got := FromMilliseconds(1000); got != time.Second {
|
||||
t.Errorf("expected 1s, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromSeconds(t *testing.T) {
|
||||
if got := FromSeconds(1); got != time.Second {
|
||||
t.Errorf("expected 1s, got %v", got)
|
||||
}
|
||||
if got := FromSeconds(60); got != time.Minute {
|
||||
t.Errorf("expected 1min, got %v", got)
|
||||
}
|
||||
if got := FromSeconds(0.5); got != 500*time.Millisecond {
|
||||
t.Errorf("expected 0.5s, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromMinutes(t *testing.T) {
|
||||
if got := FromMinutes(1); got != time.Minute {
|
||||
t.Errorf("expected 1min, got %v", got)
|
||||
}
|
||||
if got := FromMinutes(60); got != time.Hour {
|
||||
t.Errorf("expected 1h, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromHours(t *testing.T) {
|
||||
if got := FromHours(1); got != time.Hour {
|
||||
t.Errorf("expected 1h, got %v", got)
|
||||
}
|
||||
if got := FromHours(24); got != 24*time.Hour {
|
||||
t.Errorf("expected 24h, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromDays(t *testing.T) {
|
||||
if got := FromDays(1); got != 24*time.Hour {
|
||||
t.Errorf("expected 1d, got %v", got)
|
||||
}
|
||||
if got := FromDays(7); got != 7*24*time.Hour {
|
||||
t.Errorf("expected 7d, got %v", got)
|
||||
}
|
||||
if got := FromDays(0); got != 0 {
|
||||
t.Errorf("expected 0, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNaturalDurationEnglish(t *testing.T) {
|
||||
tests := []struct {
|
||||
dur time.Duration
|
||||
want string
|
||||
}{
|
||||
{time.Second, "1 second ago"},
|
||||
{2 * time.Second, "2 seconds ago"},
|
||||
{30 * time.Second, "30 seconds ago"},
|
||||
{179 * time.Second, "179 seconds ago"},
|
||||
{180 * time.Second, "3 minutes ago"},
|
||||
{30 * time.Minute, "30 minutes ago"},
|
||||
{179 * time.Minute, "179 minutes ago"},
|
||||
{180 * time.Minute, "3 hours ago"},
|
||||
{24 * time.Hour, "24 hours ago"},
|
||||
{71 * time.Hour, "71 hours ago"},
|
||||
{72 * time.Hour, "3 days ago"},
|
||||
{20 * 24 * time.Hour, "20 days ago"},
|
||||
{21 * 24 * time.Hour, "3 weeks ago"},
|
||||
{11 * 7 * 24 * time.Hour, "11 weeks ago"},
|
||||
// The months tier divides hours by (24*7*30); the actual boundaries are unusual
|
||||
// but we capture the current observable behavior:
|
||||
{12 * 7 * 24 * time.Hour, "0 months ago"},
|
||||
{90 * 7 * 24 * time.Hour, "3 months ago"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := FormatNaturalDurationEnglish(tt.dur)
|
||||
if got != tt.want {
|
||||
t.Errorf("FormatNaturalDurationEnglish(%v) = %q; want %q", tt.dur, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatDurationGerman(t *testing.T) {
|
||||
tests := []struct {
|
||||
dur time.Duration
|
||||
want string
|
||||
}{
|
||||
{time.Second, "1s"},
|
||||
{30 * time.Second, "30s"},
|
||||
{179 * time.Second, "179s"},
|
||||
{180 * time.Second, "3min"},
|
||||
{30 * time.Minute, "30min"},
|
||||
{179 * time.Minute, "179min"},
|
||||
{180 * time.Minute, "3h"},
|
||||
{24 * time.Hour, "24h"},
|
||||
{71 * time.Hour, "71h"},
|
||||
{72 * time.Hour, "3 Tage"},
|
||||
{20 * 24 * time.Hour, "20 Tage"},
|
||||
{21 * 24 * time.Hour, "3 Wochen"},
|
||||
{11 * 7 * 24 * time.Hour, "11 Wochen"},
|
||||
{12 * 7 * 24 * time.Hour, "0 Monate"},
|
||||
{90 * 7 * 24 * time.Hour, "3 Monate"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := FormatDurationGerman(tt.dur)
|
||||
if got != tt.want {
|
||||
t.Errorf("FormatDurationGerman(%v) = %q; want %q", tt.dur, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package timeext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMonthNameGermanShort3(t *testing.T) {
|
||||
tests := []struct {
|
||||
m time.Month
|
||||
want string
|
||||
}{
|
||||
{time.January, "Jan"},
|
||||
{time.February, "Feb"},
|
||||
{time.March, "Mär"},
|
||||
{time.April, "Apr"},
|
||||
{time.May, "Mai"},
|
||||
{time.June, "Jun"},
|
||||
{time.July, "Jul"},
|
||||
{time.August, "Aug"},
|
||||
{time.September, "Sep"},
|
||||
{time.October, "Okt"},
|
||||
{time.November, "Nov"},
|
||||
{time.December, "Dez"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := MonthNameGermanShort3(tt.m)
|
||||
if got != tt.want {
|
||||
t.Errorf("MonthNameGermanShort3(%v) = %q; want %q", tt.m, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthNameGermanShort3_Invalid(t *testing.T) {
|
||||
got := MonthNameGermanShort3(time.Month(13))
|
||||
want := "%!Month(13)"
|
||||
if got != want {
|
||||
t.Errorf("MonthNameGermanShort3(13) = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthNameGermanLong(t *testing.T) {
|
||||
tests := []struct {
|
||||
m time.Month
|
||||
want string
|
||||
}{
|
||||
{time.January, "Januar"},
|
||||
{time.February, "Februar"},
|
||||
{time.March, "März"},
|
||||
{time.April, "April"},
|
||||
{time.May, "Mai"},
|
||||
{time.June, "Juni"},
|
||||
{time.July, "Juli"},
|
||||
{time.August, "August"},
|
||||
{time.September, "September"},
|
||||
{time.October, "Oktober"},
|
||||
{time.November, "November"},
|
||||
{time.December, "Dezember"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := MonthNameGermanLong(tt.m)
|
||||
if got != tt.want {
|
||||
t.Errorf("MonthNameGermanLong(%v) = %q; want %q", tt.m, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthNameGermanLong_Invalid(t *testing.T) {
|
||||
got := MonthNameGermanLong(time.Month(0))
|
||||
want := "%!Month(0)"
|
||||
if got != want {
|
||||
t.Errorf("MonthNameGermanLong(0) = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package timeext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOpenTimeRange_String_Empty(t *testing.T) {
|
||||
r := OpenTimeRange{}
|
||||
if got := r.String(); got != "[]" {
|
||||
t.Errorf("expected [], got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_String_FromOnly(t *testing.T) {
|
||||
tm := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &tm}
|
||||
got := r.String()
|
||||
if got == "" || got[0] != '[' || got[len(got)-1] != ']' {
|
||||
t.Errorf("unexpected format: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_String_ToOnly(t *testing.T) {
|
||||
tm := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{To: &tm}
|
||||
got := r.String()
|
||||
if got == "" || got[0] != '[' || got[len(got)-1] != ']' {
|
||||
t.Errorf("unexpected format: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_String_Both(t *testing.T) {
|
||||
t1 := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
t2 := time.Date(2022, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &t1, To: &t2}
|
||||
got := r.String()
|
||||
if got == "" || got[0] != '[' || got[len(got)-1] != ']' {
|
||||
t.Errorf("unexpected format: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_Contains_Empty(t *testing.T) {
|
||||
r := OpenTimeRange{}
|
||||
if !r.Contains(time.Now()) {
|
||||
t.Errorf("empty range should contain anything")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_Contains_FromOnly(t *testing.T) {
|
||||
from := time.Date(2022, 6, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &from}
|
||||
|
||||
if r.Contains(time.Date(2022, 5, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should not contain time before From")
|
||||
}
|
||||
if !r.Contains(from) {
|
||||
t.Errorf("should contain From itself")
|
||||
}
|
||||
if !r.Contains(time.Date(2022, 7, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should contain time after From")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_Contains_ToOnly(t *testing.T) {
|
||||
to := time.Date(2022, 6, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{To: &to}
|
||||
|
||||
if !r.Contains(time.Date(2022, 5, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should contain time before To")
|
||||
}
|
||||
if r.Contains(to) {
|
||||
t.Errorf("should not contain To itself (exclusive)")
|
||||
}
|
||||
if r.Contains(time.Date(2022, 7, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should not contain time after To")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_Contains_Both(t *testing.T) {
|
||||
from := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
to := time.Date(2022, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &from, To: &to}
|
||||
|
||||
if r.Contains(time.Date(2021, 12, 31, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should not contain time before From")
|
||||
}
|
||||
if !r.Contains(time.Date(2022, 6, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should contain time within range")
|
||||
}
|
||||
if r.Contains(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
t.Errorf("should not contain time after To")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOpenTimeRange_Nil(t *testing.T) {
|
||||
if NewOpenTimeRange(nil, nil) != nil {
|
||||
t.Errorf("expected nil for both nil inputs")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOpenTimeRange_FromOnly(t *testing.T) {
|
||||
tm := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := NewOpenTimeRange(&tm, nil)
|
||||
if r == nil || r.From == nil || !r.From.Equal(tm) || r.To != nil {
|
||||
t.Errorf("unexpected result: %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOpenTimeRange_ToOnly(t *testing.T) {
|
||||
tm := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := NewOpenTimeRange(nil, &tm)
|
||||
if r == nil || r.To == nil || !r.To.Equal(tm) || r.From != nil {
|
||||
t.Errorf("unexpected result: %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOpenTimeRange_Both(t *testing.T) {
|
||||
from := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
to := time.Date(2022, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
r := NewOpenTimeRange(&from, &to)
|
||||
if r == nil || !r.From.Equal(from) || !r.To.Equal(to) {
|
||||
t.Errorf("unexpected result: %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_ToMongoPipeline_Empty(t *testing.T) {
|
||||
r := OpenTimeRange{}
|
||||
pipeline := r.ToMongoPipeline("ts")
|
||||
if len(pipeline) != 0 {
|
||||
t.Errorf("expected empty pipeline, got %v", pipeline)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_ToMongoPipeline_FromOnly(t *testing.T) {
|
||||
from := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &from}
|
||||
pipeline := r.ToMongoPipeline("ts")
|
||||
if len(pipeline) != 1 {
|
||||
t.Errorf("expected 1 stage, got %d", len(pipeline))
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_ToMongoPipeline_ToOnly(t *testing.T) {
|
||||
to := time.Date(2022, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{To: &to}
|
||||
pipeline := r.ToMongoPipeline("ts")
|
||||
if len(pipeline) != 1 {
|
||||
t.Errorf("expected 1 stage, got %d", len(pipeline))
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_ToMongoPipeline_Both(t *testing.T) {
|
||||
from := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
to := time.Date(2022, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
r := OpenTimeRange{From: &from, To: &to}
|
||||
pipeline := r.ToMongoPipeline("ts")
|
||||
if len(pipeline) != 2 {
|
||||
t.Errorf("expected 2 stages, got %d", len(pipeline))
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_AppendToMongoPipeline_Nil(t *testing.T) {
|
||||
var r *OpenTimeRange
|
||||
existing := []any{"existing"}
|
||||
got := r.AppendToMongoPipeline(existing, "ts")
|
||||
if len(got) != 1 {
|
||||
t.Errorf("expected unchanged pipeline, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenTimeRange_AppendToMongoPipeline_NonNil(t *testing.T) {
|
||||
from := time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
r := &OpenTimeRange{From: &from}
|
||||
existing := []any{"existing"}
|
||||
got := r.AppendToMongoPipeline(existing, "ts")
|
||||
if len(got) != 2 {
|
||||
t.Errorf("expected pipeline with 2 entries, got %v", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package timeext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWeekdayNameGerman(t *testing.T) {
|
||||
tests := []struct {
|
||||
d time.Weekday
|
||||
want string
|
||||
}{
|
||||
{time.Sunday, "Sonntag"},
|
||||
{time.Monday, "Montag"},
|
||||
{time.Tuesday, "Dienstag"},
|
||||
{time.Wednesday, "Mittwoch"},
|
||||
{time.Thursday, "Donnerstag"},
|
||||
{time.Friday, "Freitag"},
|
||||
{time.Saturday, "Samstag"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := WeekdayNameGerman(tt.d)
|
||||
if got != tt.want {
|
||||
t.Errorf("WeekdayNameGerman(%v) = %q; want %q", tt.d, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeekdayNameGerman_Invalid(t *testing.T) {
|
||||
got := WeekdayNameGerman(time.Weekday(8))
|
||||
want := "%!Weekday(8)"
|
||||
if got != want {
|
||||
t.Errorf("WeekdayNameGerman(8) = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeekdayNameGerman_Negative(t *testing.T) {
|
||||
got := WeekdayNameGerman(time.Weekday(-1))
|
||||
want := "%!Weekday(-1)"
|
||||
if got != want {
|
||||
t.Errorf("WeekdayNameGerman(-1) = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package timeext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGetIsoWeekCount(t *testing.T) {
|
||||
// The implementation subtracts 1 from the ISO week numbers internally,
|
||||
// so for a 53-week year it returns 52, and for a 52-week year it returns 51.
|
||||
tests := []struct {
|
||||
year int
|
||||
want int
|
||||
}{
|
||||
{2020, 52}, // 2020 is a 53-week ISO year
|
||||
{2021, 51},
|
||||
{2022, 51},
|
||||
{2023, 51},
|
||||
{2024, 51},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := GetIsoWeekCount(tt.year)
|
||||
if got != tt.want {
|
||||
t.Errorf("GetIsoWeekCount(%d) = %d; want %d", tt.year, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAggregateIsoWeekCount_Year1900(t *testing.T) {
|
||||
got := GetAggregateIsoWeekCount(1900)
|
||||
if got != 0 {
|
||||
t.Errorf("GetAggregateIsoWeekCount(1900) = %d; want 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAggregateIsoWeekCount_Monotonic(t *testing.T) {
|
||||
// The aggregate count must be strictly monotonically increasing year over year (for years > 1900)
|
||||
prev := GetAggregateIsoWeekCount(1900)
|
||||
for y := 1901; y <= 2030; y++ {
|
||||
cur := GetAggregateIsoWeekCount(y)
|
||||
if cur <= prev {
|
||||
t.Errorf("GetAggregateIsoWeekCount(%d)=%d not greater than GetAggregateIsoWeekCount(%d)=%d", y, cur, y-1, prev)
|
||||
}
|
||||
prev = cur
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAggregateIsoWeekCount_BeforeBaseline(t *testing.T) {
|
||||
// for years < 1900 the aggregate is negative
|
||||
got := GetAggregateIsoWeekCount(1899)
|
||||
if got >= 0 {
|
||||
t.Errorf("GetAggregateIsoWeekCount(1899) = %d; want < 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGlobalWeeknumber_Monotonic(t *testing.T) {
|
||||
// Walking forward by one week should never decrease the global week number
|
||||
t0 := time.Date(2020, 1, 6, 0, 0, 0, 0, TimezoneBerlin) // Monday, ISO week 2 of 2020
|
||||
prev := GetGlobalWeeknumber(t0)
|
||||
for i := 1; i < 200; i++ {
|
||||
ti := t0.AddDate(0, 0, i*7)
|
||||
cur := GetGlobalWeeknumber(ti)
|
||||
if cur < prev {
|
||||
t.Errorf("week number decreased at offset %d weeks: %d -> %d", i, prev, cur)
|
||||
}
|
||||
prev = cur
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGlobalWeeknumber_DifferentYearsDiffer(t *testing.T) {
|
||||
w2020 := GetGlobalWeeknumber(time.Date(2020, 6, 1, 0, 0, 0, 0, TimezoneBerlin))
|
||||
w2021 := GetGlobalWeeknumber(time.Date(2021, 6, 1, 0, 0, 0, 0, TimezoneBerlin))
|
||||
if w2021 <= w2020 {
|
||||
t.Errorf("expected w2021 > w2020, got %d and %d", w2021, w2020)
|
||||
}
|
||||
// Approximately 52 weeks apart
|
||||
delta := w2021 - w2020
|
||||
if delta < 50 || delta > 54 {
|
||||
t.Errorf("expected ~52 week difference, got %d", delta)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user