yao/openapi/utils/convert_test.go
Max 1a5e1db2ec refactor(time): enhance timestamp handling with utility functions
- Introduced NanoToTime and TimeToNano functions for converting between UnixNano and time.Time, improving clarity and consistency in timestamp management.
- Updated Assistant model to utilize the new utility functions for created_at and updated_at fields.
- Refactored Xun store methods to ensure UTC compatibility for timestamp serialization across different database drivers.
- Added unit tests for the new conversion functions to validate their correctness and behavior.
2026-04-06 11:21:12 +08:00

173 lines
4.9 KiB
Go

package utils
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestDBTimestampToUnix(t *testing.T) {
ref := time.Date(2024, 6, 15, 10, 30, 45, 0, time.UTC)
refUnix := ref.Unix()
tests := []struct {
name string
input interface{}
expect interface{}
}{
{"nil", nil, nil},
{"empty string", "", nil},
{"MySQL DATETIME", "2024-06-15 10:30:45", refUnix},
{"PG with fractional seconds", "2024-06-15 10:30:45.123456", refUnix},
{"PG with +00 offset", "2024-06-15 10:30:45.123456+00", refUnix},
{"PG with -07 offset", "2024-06-15 03:30:45.123456-07", refUnix},
{"ISO Z suffix", "2024-06-15T10:30:45Z", refUnix},
{"RFC3339", "2024-06-15T10:30:45+00:00", refUnix},
{"RFC3339Nano", "2024-06-15T10:30:45.123456789+00:00", refUnix},
{"*string nil", (*string)(nil), nil},
{"*string valid", strPtr("2024-06-15 10:30:45"), refUnix},
{"*string empty", strPtr(""), nil},
{"non-string type", 12345, nil},
{"unparseable string", "not-a-date", nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := DBTimestampToUnix(tt.input)
assert.Equal(t, tt.expect, result)
})
}
}
func TestUnixToDBTimestamp(t *testing.T) {
refUnix := int64(1718444445)
expected := time.Unix(refUnix, 0).UTC().Format("2006-01-02 15:04:05")
tests := []struct {
name string
input interface{}
expect interface{}
}{
{"nil", nil, nil},
{"int64", refUnix, expected},
{"*int64 valid", int64Ptr(refUnix), expected},
{"*int64 nil", (*int64)(nil), nil},
{"int", int(refUnix), expected},
{"float64", float64(refUnix), expected},
{"unknown type", "not-a-number", nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := UnixToDBTimestamp(tt.input)
assert.Equal(t, tt.expect, result)
})
}
}
func TestToUnixTimestamp(t *testing.T) {
refUnix := int64(1718444445)
tests := []struct {
name string
input interface{}
expect interface{}
}{
{"nil", nil, nil},
{"int64", refUnix, refUnix},
{"*int64 valid", int64Ptr(refUnix), refUnix},
{"*int64 nil", (*int64)(nil), nil},
{"int", int(refUnix), refUnix},
{"float64", float64(refUnix), refUnix},
{"string MySQL", "2024-06-15 10:00:45", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()},
{"string PG fractional", "2024-06-15 10:00:45.123456", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()},
{"string RFC3339", "2024-06-15T10:00:45Z", time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()},
{"*string valid", strPtr("2024-06-15 10:00:45"), time.Date(2024, 6, 15, 10, 0, 45, 0, time.UTC).Unix()},
{"*string nil", (*string)(nil), nil},
{"string empty", "", nil},
{"unknown type", struct{}{}, nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ToUnixTimestamp(tt.input)
assert.Equal(t, tt.expect, result)
})
}
}
func TestToTimeStringWithPGFormats(t *testing.T) {
tests := []struct {
name string
input interface{}
expect string
}{
{"PG fractional", "2024-06-15 10:30:45.123456", "2024-06-15T10:30:45Z"},
{"PG +00 offset", "2024-06-15 10:30:45.123456+00", "2024-06-15T10:30:45Z"},
{"PG -07 offset", "2024-06-15 03:30:45.123456-07", "2024-06-15T03:30:45-07:00"},
{"MySQL format", "2024-06-15 10:30:45", "2024-06-15T10:30:45Z"},
{"RFC3339Nano", "2024-06-15T10:30:45.123456789+00:00", "2024-06-15T10:30:45Z"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ToTimeString(tt.input)
assert.Equal(t, tt.expect, result)
})
}
}
func TestNanoToTime(t *testing.T) {
t.Run("Zero", func(t *testing.T) {
assert.True(t, NanoToTime(0).IsZero())
})
t.Run("ValidTimestamp", func(t *testing.T) {
ns := int64(1609459200000000000) // 2021-01-01 00:00:00 UTC
got := NanoToTime(ns)
assert.Equal(t, 2021, got.Year())
assert.Equal(t, time.January, got.Month())
assert.Equal(t, 1, got.Day())
assert.Equal(t, 0, got.Hour())
assert.Equal(t, time.UTC, got.Location())
})
t.Run("PreservesNanoseconds", func(t *testing.T) {
ns := int64(1609459200123456789)
got := NanoToTime(ns)
assert.Equal(t, 123456789, got.Nanosecond())
})
t.Run("Negative", func(t *testing.T) {
got := NanoToTime(-1)
assert.False(t, got.IsZero())
assert.Equal(t, time.UTC, got.Location())
})
}
func TestTimeToNano(t *testing.T) {
t.Run("Zero", func(t *testing.T) {
assert.Equal(t, int64(0), TimeToNano(time.Time{}))
})
t.Run("ValidTime", func(t *testing.T) {
ts := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
assert.Equal(t, int64(1609459200000000000), TimeToNano(ts))
})
t.Run("WithNanoseconds", func(t *testing.T) {
ts := time.Date(2021, 1, 1, 0, 0, 0, 123456789, time.UTC)
assert.Equal(t, int64(1609459200123456789), TimeToNano(ts))
})
t.Run("RoundTrip", func(t *testing.T) {
original := time.Date(2026, 3, 26, 15, 30, 45, 123456789, time.UTC)
ns := TimeToNano(original)
restored := NanoToTime(ns)
assert.True(t, original.Equal(restored))
})
}
func strPtr(s string) *string { return &s }
func int64Ptr(i int64) *int64 { return &i }