[🤖] Add Unit-Tests
Build Docker and Deploy / Run goext test-suite (push) Successful in 1m34s

This commit is contained in:
2026-04-27 10:46:08 +02:00
parent dad0e3240d
commit 02d6894ec6
116 changed files with 18795 additions and 1 deletions
+196
View File
@@ -0,0 +1,196 @@
package rfctime
import (
"encoding/json"
"testing"
"time"
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
)
func TestDateString(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 7}
tst.AssertEqual(t, d.String(), "2023-05-07")
tst.AssertEqual(t, d.Serialize(), "2023-05-07")
tst.AssertEqual(t, d.GoString(), "rfctime.Date{Year: 2023, Month: 5, Day: 7}")
tst.AssertEqual(t, d.FormatStr(), "2006-01-02")
}
func TestDateIsZero(t *testing.T) {
tst.AssertEqual(t, Date{}.IsZero(), true)
tst.AssertEqual(t, Date{Year: 1, Month: 1, Day: 1}.IsZero(), false)
}
func TestDateNew(t *testing.T) {
tm := time.Date(2023, 5, 7, 12, 30, 0, 0, time.UTC)
d := NewDate(tm)
tst.AssertEqual(t, d.Year, 2023)
tst.AssertEqual(t, d.Month, 5)
tst.AssertEqual(t, d.Day, 7)
}
func TestDateTimeConversions(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 7}
utc := d.TimeUTC()
tst.AssertEqual(t, utc.Year(), 2023)
tst.AssertEqual(t, utc.Month(), time.May)
tst.AssertEqual(t, utc.Day(), 7)
tst.AssertEqual(t, utc.Location(), time.UTC)
loc := d.TimeLocal()
tst.AssertEqual(t, loc.Location(), time.Local)
custom := d.Time(time.UTC)
tst.AssertEqual(t, custom.Hour(), 0)
tst.AssertEqual(t, custom.Location(), time.UTC)
}
func TestDateJSON(t *testing.T) {
type Wrap struct {
D Date `json:"d"`
}
w1 := Wrap{D: Date{Year: 2023, Month: 5, Day: 7}}
b, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), `{"d":"2023-05-07"}`)
var w2 Wrap
if err := json.Unmarshal(b, &w2); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, w2.D, w1.D)
}
func TestDateJSONInvalid(t *testing.T) {
var d Date
if err := d.UnmarshalJSON([]byte(`"not-a-date"`)); err == nil {
t.Errorf("expected parse error")
}
if err := d.UnmarshalJSON([]byte(`123`)); err == nil {
t.Errorf("expected json error for number")
}
}
func TestDateText(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 7}
b, err := d.MarshalText()
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), "2023-05-07")
var d2 Date
if err := d2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, d2, d)
if err := d2.UnmarshalText([]byte("garbage")); err == nil {
t.Errorf("expected error")
}
}
func TestDateBinaryGob(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 7}
bin, err := d.MarshalBinary()
if err != nil {
t.Fatal(err)
}
var d2 Date
if err := d2.UnmarshalBinary(bin); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, d2, d)
gob, err := d.GobEncode()
if err != nil {
t.Fatal(err)
}
var d3 Date
if err := d3.GobDecode(gob); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, d3, d)
}
func TestDateAccessors(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 17}
y, m, day := d.Date()
tst.AssertEqual(t, y, 2023)
tst.AssertEqual(t, m, time.May)
tst.AssertEqual(t, day, 17)
tst.AssertEqual(t, d.Weekday(), time.Wednesday)
wy, ww := d.ISOWeek()
ey, ew := d.TimeUTC().ISOWeek()
tst.AssertEqual(t, wy, ey)
tst.AssertEqual(t, ww, ew)
tst.AssertEqual(t, d.YearDay(), d.TimeUTC().YearDay())
tst.AssertEqual(t, d.Unix(), d.TimeUTC().Unix())
tst.AssertEqual(t, d.UnixMilli(), d.TimeUTC().UnixMilli())
tst.AssertEqual(t, d.UnixMicro(), d.TimeUTC().UnixMicro())
tst.AssertEqual(t, d.UnixNano(), d.TimeUTC().UnixNano())
tst.AssertEqual(t, d.Format("2006/01/02"), "2023/05/17")
}
func TestDateAddDate(t *testing.T) {
d := Date{Year: 2023, Month: 5, Day: 17}
d2 := d.AddDate(1, 2, 3)
tst.AssertEqual(t, d2.Year, 2024)
tst.AssertEqual(t, d2.Month, 7)
tst.AssertEqual(t, d2.Day, 20)
}
func TestDateParseString(t *testing.T) {
tests := []struct {
input string
ok bool
expected Date
}{
{"2023-05-07", true, Date{2023, 5, 7}},
{"0001-01-01", true, Date{1, 1, 1}},
{"2023-13-01", false, Date{}}, // bad month
{"2023-12-32", false, Date{}}, // bad day
{"2023-00-15", false, Date{}}, // month 0
{"2023-05", false, Date{}}, // bad format
{"2023-05-07-extra", false, Date{}},
{"abcd-ef-gh", false, Date{}},
{"-1-05-07", false, Date{}}, // negative year
}
for _, tc := range tests {
var d Date
err := d.ParseString(tc.input)
if tc.ok {
if err != nil {
t.Errorf("ParseString(%q) failed: %v", tc.input, err)
continue
}
tst.AssertEqual(t, d, tc.expected)
} else if err == nil {
t.Errorf("ParseString(%q) should have failed", tc.input)
}
}
}
func TestNowDate(t *testing.T) {
now := time.Now().UTC()
d := NowDate(time.UTC)
tst.AssertEqual(t, d.Year, now.Year())
tst.AssertEqual(t, d.Month, int(now.Month()))
tst.AssertEqual(t, d.Day, now.Day())
dl := NowDateLoc()
if dl.Year < 1970 {
t.Errorf("NowDateLoc returned implausible year: %d", dl.Year)
}
du := NowDateUTC()
if du.Year < 1970 {
t.Errorf("NowDateUTC returned implausible year: %d", du.Year)
}
}
+197
View File
@@ -0,0 +1,197 @@
package rfctime
import (
"encoding/json"
"testing"
"time"
"git.blackforestbytes.com/BlackForestBytes/goext/timeext"
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
)
func TestRFC3339TimeRoundtripJSON(t *testing.T) {
type Wrap struct {
Value RFC3339Time `json:"v"`
}
val := NewRFC3339(time.Unix(1675951556, 0).In(timeext.TimezoneBerlin))
w1 := Wrap{val}
jstr1, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
if string(jstr1) != "{\"v\":\"2023-02-09T15:05:56+01:00\"}" {
t.Errorf("unexpected json: %s", string(jstr1))
}
w2 := Wrap{}
if err := json.Unmarshal(jstr1, &w2); err != nil {
t.Fatal(err)
}
jstr2, err := json.Marshal(w2)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(jstr1), string(jstr2))
if !w1.Value.EqualAny(w2.Value) {
t.Errorf("time differs after roundtrip")
}
}
func TestRFC3339TimeUnmarshalJSONInvalid(t *testing.T) {
var v RFC3339Time
if err := v.UnmarshalJSON([]byte(`"not-a-date"`)); err == nil {
t.Errorf("expected error parsing invalid date")
}
if err := v.UnmarshalJSON([]byte(`12345`)); err == nil {
t.Errorf("expected error for non-string json")
}
}
func TestRFC3339TimeText(t *testing.T) {
val := NewRFC3339(time.Date(2023, 2, 9, 15, 5, 56, 0, time.UTC))
b, err := val.MarshalText()
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), "2023-02-09T15:05:56Z")
var v2 RFC3339Time
if err := v2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
if !v2.Equal(val) {
t.Errorf("text roundtrip mismatch")
}
if err := v2.UnmarshalText([]byte("garbage")); err == nil {
t.Errorf("expected error on bad text")
}
}
func TestRFC3339TimeBinaryAndGob(t *testing.T) {
val := NewRFC3339(time.Date(2023, 2, 9, 15, 5, 56, 123, time.UTC))
bin, err := val.MarshalBinary()
if err != nil {
t.Fatal(err)
}
var v2 RFC3339Time
if err := v2.UnmarshalBinary(bin); err != nil {
t.Fatal(err)
}
if !v2.Equal(val) {
t.Errorf("binary roundtrip mismatch")
}
gob, err := val.GobEncode()
if err != nil {
t.Fatal(err)
}
var v3 RFC3339Time
if err := v3.GobDecode(gob); err != nil {
t.Fatal(err)
}
if !v3.Equal(val) {
t.Errorf("gob roundtrip mismatch")
}
}
func TestRFC3339TimeAccessors(t *testing.T) {
loc, _ := time.LoadLocation("UTC")
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, loc)
val := NewRFC3339(tm)
tst.AssertEqual(t, val.Year(), 2023)
tst.AssertEqual(t, val.Month(), time.May)
tst.AssertEqual(t, val.Day(), 17)
tst.AssertEqual(t, val.Hour(), 14)
tst.AssertEqual(t, val.Minute(), 30)
tst.AssertEqual(t, val.Second(), 45)
tst.AssertEqual(t, val.Nanosecond(), 123456789)
tst.AssertEqual(t, val.Weekday(), time.Wednesday)
tst.AssertEqual(t, val.YearDay(), tm.YearDay())
tst.AssertEqual(t, val.Unix(), tm.Unix())
tst.AssertEqual(t, val.UnixMilli(), tm.UnixMilli())
tst.AssertEqual(t, val.UnixMicro(), tm.UnixMicro())
tst.AssertEqual(t, val.UnixNano(), tm.UnixNano())
tst.AssertEqual(t, val.Location(), loc)
tst.AssertEqual(t, val.Format(time.RFC3339), tm.Format(time.RFC3339))
tst.AssertEqual(t, val.GoString(), tm.GoString())
tst.AssertEqual(t, val.String(), tm.String())
tst.AssertEqual(t, val.Serialize(), tm.Format(time.RFC3339))
tst.AssertEqual(t, val.FormatStr(), time.RFC3339)
y, mo, d := val.Date()
tst.AssertEqual(t, y, 2023)
tst.AssertEqual(t, mo, time.May)
tst.AssertEqual(t, d, 17)
wy, ww := val.ISOWeek()
ey, ew := tm.ISOWeek()
tst.AssertEqual(t, wy, ey)
tst.AssertEqual(t, ww, ew)
h, m, s := val.Clock()
tst.AssertEqual(t, h, 14)
tst.AssertEqual(t, m, 30)
tst.AssertEqual(t, s, 45)
tst.AssertEqual(t, val.IsZero(), false)
tst.AssertEqual(t, RFC3339Time{}.IsZero(), true)
}
func TestRFC3339TimeAddSub(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
a := NewRFC3339(tm)
b := a.Add(2 * time.Hour)
tst.AssertEqual(t, b.Sub(a), 2*time.Hour)
tst.AssertEqual(t, b.After(a), true)
tst.AssertEqual(t, a.Before(b), true)
tst.AssertEqual(t, a.After(b), false)
tst.AssertEqual(t, b.Before(a), false)
c := a.AddDate(1, 2, 3)
tst.AssertEqual(t, c.Year(), 2024)
tst.AssertEqual(t, c.Month(), time.July)
tst.AssertEqual(t, c.Day(), 20)
}
func TestRFC3339TimeEqual(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
a := NewRFC3339(tm)
b := NewRFC3339(tm)
c := NewRFC3339(tm.Add(time.Second))
tst.AssertEqual(t, a.Equal(b), true)
tst.AssertEqual(t, a.Equal(c), false)
tst.AssertEqual(t, a.EqualAny(b), true)
tst.AssertEqual(t, a.EqualAny(c), false)
tst.AssertEqual(t, a.EqualAny(nil), false)
// Cross-type comparison via tt()
tst.AssertEqual(t, a.EqualAny(NewRFC3339Nano(tm)), true)
tst.AssertEqual(t, a.EqualAny(tm), true)
}
func TestRFC3339TimeToNano(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 12345, time.UTC)
a := NewRFC3339(tm)
n := a.ToNano()
tst.AssertEqual(t, n.UnixNano(), tm.UnixNano())
}
func TestNowRFC3339(t *testing.T) {
before := time.Now()
v := NowRFC3339()
after := time.Now()
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
t.Errorf("NowRFC3339 not within expected range")
}
}
+50
View File
@@ -0,0 +1,50 @@
package rfctime
import (
"encoding/json"
"math"
"testing"
"time"
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
)
func TestSecondsF64Basics(t *testing.T) {
d := NewSecondsF64(2*time.Second + 500*time.Millisecond)
tst.AssertEqual(t, d.Duration(), 2500*time.Millisecond)
tst.AssertEqual(t, d.Seconds(), 2.5)
tst.AssertEqual(t, d.Milliseconds(), int64(2500))
tst.AssertEqual(t, d.Microseconds(), int64(2500000))
tst.AssertEqual(t, d.Nanoseconds(), int64(2500000000))
tst.AssertEqual(t, d.Minutes(), 2.5/60.0)
tst.AssertEqual(t, d.Hours(), 2.5/3600.0)
tst.AssertEqual(t, d.String(), (2500 * time.Millisecond).String())
}
func TestSecondsF64JSON(t *testing.T) {
type Wrap struct {
D SecondsF64 `json:"d"`
}
w1 := Wrap{D: NewSecondsF64(2500 * time.Millisecond)}
b, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), `{"d":2.5}`)
var w2 Wrap
if err := json.Unmarshal(b, &w2); err != nil {
t.Fatal(err)
}
if math.Abs(float64(w2.D.Duration()-w1.D.Duration())) > float64(time.Microsecond) {
t.Errorf("roundtrip mismatch: %v vs %v", w1.D, w2.D)
}
}
func TestSecondsF64UnmarshalJSONInvalid(t *testing.T) {
var d SecondsF64
if err := d.UnmarshalJSON([]byte(`"not-a-number"`)); err == nil {
t.Errorf("expected error")
}
}
+100
View File
@@ -0,0 +1,100 @@
package rfctime
import (
"testing"
"time"
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
)
func TestTimeNew(t *testing.T) {
v := NewTime(14, 30, 45, 123)
tst.AssertEqual(t, v.Hour, 14)
tst.AssertEqual(t, v.Minute, 30)
tst.AssertEqual(t, v.Second, 45)
tst.AssertEqual(t, v.NanoSecond, 123)
}
func TestTimeFromTS(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, time.UTC)
v := NewTimeFromTS(tm)
tst.AssertEqual(t, v.Hour, 14)
tst.AssertEqual(t, v.Minute, 30)
tst.AssertEqual(t, v.Second, 45)
tst.AssertEqual(t, v.NanoSecond, 123456789)
}
func TestTimeSerialize(t *testing.T) {
v := NewTime(14, 30, 45, 123456789)
tst.AssertEqual(t, v.Serialize(), "0014:30:45.123456789")
tst.AssertEqual(t, v.String(), "0014:30:45.123456789")
tst.AssertEqual(t, v.GoString(), "rfctime.NewTime(14, 30, 45, 123456789)")
tst.AssertEqual(t, v.FormatStr(), "15:04:05.999999999")
}
func TestTimeSerializeShort(t *testing.T) {
tst.AssertEqual(t, NewTime(14, 30, 0, 0).SerializeShort(), "14:30")
tst.AssertEqual(t, NewTime(14, 30, 45, 0).SerializeShort(), "14:30:45")
tst.AssertEqual(t, NewTime(14, 30, 45, 123).SerializeShort(), "14:30:45.000000123")
tst.AssertEqual(t, NewTime(0, 0, 0, 0).SerializeShort(), "00:00")
}
func TestTimeDeserialize(t *testing.T) {
tests := []struct {
input string
ok bool
expected Time
}{
{"14:30", true, Time{Hour: 14, Minute: 30, Second: 0, NanoSecond: 0}},
{"14:30:45", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 0}},
{"14:30:45.123", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 123000000}},
{"14:30:45.123456789", true, Time{Hour: 14, Minute: 30, Second: 45, NanoSecond: 123456789}},
{"00:00:00.000000000", true, Time{Hour: 0, Minute: 0, Second: 0, NanoSecond: 0}},
{"14", false, Time{}},
{"14:30:45.123:extra", false, Time{}},
{"ab:cd", false, Time{}},
{"14:bb", false, Time{}},
{"14:30:cc", false, Time{}},
{"14:30:45.zz", false, Time{}},
}
for _, tc := range tests {
var v Time
err := v.Deserialize(tc.input)
if tc.ok {
if err != nil {
t.Errorf("Deserialize(%q) failed: %v", tc.input, err)
continue
}
tst.AssertEqual(t, v, tc.expected)
} else if err == nil {
t.Errorf("Deserialize(%q) should have failed", tc.input)
}
}
}
func TestNowTime(t *testing.T) {
now := time.Now().UTC()
v := NowTime(time.UTC)
// Within a couple of seconds
if abs(v.Hour-now.Hour()) > 1 && !(now.Hour() == 23 && v.Hour == 0) {
t.Errorf("NowTime hour mismatch: %d vs %d", v.Hour, now.Hour())
}
vl := NowTimeLoc()
if vl.Hour < 0 || vl.Hour > 23 {
t.Errorf("NowTimeLoc invalid hour: %d", vl.Hour)
}
vu := NowTimeUTC()
if vu.Hour < 0 || vu.Hour > 23 {
t.Errorf("NowTimeUTC invalid hour: %d", vu.Hour)
}
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
+330
View File
@@ -0,0 +1,330 @@
package rfctime
import (
"encoding/json"
"strconv"
"testing"
"time"
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
)
func TestUnixTimeRoundtripJSON(t *testing.T) {
type Wrap struct {
Value UnixTime `json:"v"`
}
val := NewUnix(time.Unix(1675951556, 0).UTC())
w1 := Wrap{val}
jstr1, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556"}`)
w2 := Wrap{}
if err := json.Unmarshal(jstr1, &w2); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, w2.Value.Unix(), val.Unix())
}
func TestUnixTimeUnmarshalJSONInvalid(t *testing.T) {
var v UnixTime
if err := v.UnmarshalJSON([]byte(`"not-a-number"`)); err == nil {
t.Errorf("expected parse error")
}
if err := v.UnmarshalJSON([]byte(`{}`)); err == nil {
t.Errorf("expected json error on object")
}
}
func TestUnixTimeText(t *testing.T) {
val := NewUnix(time.Unix(1675951556, 0))
b, err := val.MarshalText()
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), "1675951556")
var v2 UnixTime
if err := v2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, v2.Unix(), val.Unix())
if err := v2.UnmarshalText([]byte("garbage")); err == nil {
t.Errorf("expected error")
}
}
func TestUnixTimeBinaryGob(t *testing.T) {
val := NewUnix(time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC))
bin, err := val.MarshalBinary()
if err != nil {
t.Fatal(err)
}
var v2 UnixTime
if err := v2.UnmarshalBinary(bin); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, v2.Unix(), val.Unix())
gob, err := val.GobEncode()
if err != nil {
t.Fatal(err)
}
var v3 UnixTime
if err := v3.GobDecode(gob); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, v3.Unix(), val.Unix())
}
func TestUnixTimeAccessors(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 12345, time.UTC)
val := NewUnix(tm)
tst.AssertEqual(t, val.Year(), 2023)
tst.AssertEqual(t, val.Month(), time.May)
tst.AssertEqual(t, val.Day(), 17)
tst.AssertEqual(t, val.Hour(), 14)
tst.AssertEqual(t, val.Minute(), 30)
tst.AssertEqual(t, val.Second(), 45)
tst.AssertEqual(t, val.Nanosecond(), 12345)
tst.AssertEqual(t, val.Weekday(), time.Wednesday)
tst.AssertEqual(t, val.Unix(), tm.Unix())
tst.AssertEqual(t, val.UnixMilli(), tm.UnixMilli())
tst.AssertEqual(t, val.UnixMicro(), tm.UnixMicro())
tst.AssertEqual(t, val.UnixNano(), tm.UnixNano())
tst.AssertEqual(t, val.Format(time.RFC3339), tm.Format(time.RFC3339))
tst.AssertEqual(t, val.GoString(), tm.GoString())
tst.AssertEqual(t, val.String(), tm.String())
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.Unix(), 10))
tst.AssertEqual(t, val.IsZero(), false)
tst.AssertEqual(t, UnixTime{}.IsZero(), true)
y, mo, d := val.Date()
tst.AssertEqual(t, y, 2023)
tst.AssertEqual(t, mo, time.May)
tst.AssertEqual(t, d, 17)
wy, ww := val.ISOWeek()
ey, ew := tm.ISOWeek()
tst.AssertEqual(t, wy, ey)
tst.AssertEqual(t, ww, ew)
h, m, s := val.Clock()
tst.AssertEqual(t, h, 14)
tst.AssertEqual(t, m, 30)
tst.AssertEqual(t, s, 45)
tst.AssertEqual(t, val.YearDay(), tm.YearDay())
}
func TestUnixTimeAddSubCompare(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
a := NewUnix(tm)
b := a.Add(time.Hour)
tst.AssertEqual(t, b.Sub(a), time.Hour)
tst.AssertEqual(t, b.After(a), true)
tst.AssertEqual(t, a.Before(b), true)
c := a.AddDate(0, 1, 0)
tst.AssertEqual(t, c.Month(), time.June)
d := NewUnix(tm)
tst.AssertEqual(t, a.Equal(d), true)
tst.AssertEqual(t, a.EqualAny(d), true)
tst.AssertEqual(t, a.EqualAny(b), false)
tst.AssertEqual(t, a.EqualAny(nil), false)
}
func TestNowUnix(t *testing.T) {
before := time.Now()
v := NowUnix()
after := time.Now()
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
t.Errorf("NowUnix not within expected range")
}
}
// ---------- UnixMilliTime ----------
func TestUnixMilliTimeRoundtripJSON(t *testing.T) {
type Wrap struct {
Value UnixMilliTime `json:"v"`
}
val := NewUnixMilli(time.UnixMilli(1675951556789).UTC())
w1 := Wrap{val}
jstr1, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556789"}`)
w2 := Wrap{}
if err := json.Unmarshal(jstr1, &w2); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, w2.Value.UnixMilli(), val.UnixMilli())
}
func TestUnixMilliTimeText(t *testing.T) {
val := NewUnixMilli(time.UnixMilli(1675951556789))
b, err := val.MarshalText()
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), "1675951556789")
var v2 UnixMilliTime
if err := v2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, v2.UnixMilli(), val.UnixMilli())
}
func TestUnixMilliTimeUnmarshalJSONInvalid(t *testing.T) {
var v UnixMilliTime
if err := v.UnmarshalJSON([]byte(`"abc"`)); err == nil {
t.Errorf("expected error")
}
if err := v.UnmarshalJSON([]byte(`[]`)); err == nil {
t.Errorf("expected error on array")
}
}
func TestUnixMilliTimeAccessors(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 1000000, time.UTC)
val := NewUnixMilli(tm)
tst.AssertEqual(t, val.Year(), 2023)
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.UnixMilli(), 10))
tst.AssertEqual(t, val.IsZero(), false)
tst.AssertEqual(t, UnixMilliTime{}.IsZero(), true)
a := val.Add(time.Hour)
tst.AssertEqual(t, a.Sub(val), time.Hour)
tst.AssertEqual(t, a.After(val), true)
tst.AssertEqual(t, val.Before(a), true)
d := NewUnixMilli(tm)
tst.AssertEqual(t, val.Equal(d), true)
tst.AssertEqual(t, val.EqualAny(d), true)
tst.AssertEqual(t, val.EqualAny(nil), false)
}
func TestNowUnixMilli(t *testing.T) {
before := time.Now()
v := NowUnixMilli()
after := time.Now()
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
t.Errorf("NowUnixMilli not within expected range")
}
}
// ---------- UnixNanoTime ----------
func TestUnixNanoTimeRoundtripJSON(t *testing.T) {
type Wrap struct {
Value UnixNanoTime `json:"v"`
}
val := NewUnixNano(time.Unix(0, 1675951556820915171).UTC())
w1 := Wrap{val}
jstr1, err := json.Marshal(w1)
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(jstr1), `{"v":"1675951556820915171"}`)
w2 := Wrap{}
if err := json.Unmarshal(jstr1, &w2); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, w2.Value.UnixNano(), val.UnixNano())
}
func TestUnixNanoTimeText(t *testing.T) {
val := NewUnixNano(time.Unix(0, 1675951556820915171))
b, err := val.MarshalText()
if err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, string(b), "1675951556820915171")
var v2 UnixNanoTime
if err := v2.UnmarshalText(b); err != nil {
t.Fatal(err)
}
tst.AssertEqual(t, v2.UnixNano(), val.UnixNano())
if err := v2.UnmarshalText([]byte("xyz")); err == nil {
t.Errorf("expected error")
}
}
func TestUnixNanoTimeUnmarshalJSONInvalid(t *testing.T) {
var v UnixNanoTime
if err := v.UnmarshalJSON([]byte(`"abc"`)); err == nil {
t.Errorf("expected error")
}
}
func TestUnixNanoTimeAccessors(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 123456789, time.UTC)
val := NewUnixNano(tm)
tst.AssertEqual(t, val.Year(), 2023)
tst.AssertEqual(t, val.Nanosecond(), 123456789)
tst.AssertEqual(t, val.Serialize(), strconv.FormatInt(tm.UnixNano(), 10))
tst.AssertEqual(t, val.IsZero(), false)
tst.AssertEqual(t, UnixNanoTime{}.IsZero(), true)
a := val.Add(2 * time.Second)
tst.AssertEqual(t, a.Sub(val), 2*time.Second)
tst.AssertEqual(t, a.After(val), true)
tst.AssertEqual(t, val.Before(a), true)
c := val.AddDate(0, 0, 1)
tst.AssertEqual(t, c.Day(), 18)
d := NewUnixNano(tm)
tst.AssertEqual(t, val.Equal(d), true)
tst.AssertEqual(t, val.EqualAny(d), true)
tst.AssertEqual(t, val.EqualAny(nil), false)
}
func TestNowUnixNano(t *testing.T) {
before := time.Now()
v := NowUnixNano()
after := time.Now()
if v.Time().Before(before.Add(-time.Second)) || v.Time().After(after.Add(time.Second)) {
t.Errorf("NowUnixNano not within expected range")
}
}
func TestUnixCrossTypeEqualAny(t *testing.T) {
tm := time.Date(2023, 5, 17, 14, 30, 45, 0, time.UTC)
u := NewUnix(tm)
um := NewUnixMilli(tm)
un := NewUnixNano(tm)
r := NewRFC3339(tm)
rn := NewRFC3339Nano(tm)
tst.AssertEqual(t, u.EqualAny(um), true)
tst.AssertEqual(t, u.EqualAny(un), true)
tst.AssertEqual(t, u.EqualAny(r), true)
tst.AssertEqual(t, u.EqualAny(rn), true)
tst.AssertEqual(t, u.EqualAny(tm), true)
}