Files
grafana/pkg/storage/legacysql/time_test.go
T

135 lines
3.2 KiB
Go

package legacysql
import (
"fmt"
"testing"
"time"
)
func TestDBTime_ValueAndString_ZeroAndNonZero(t *testing.T) {
zero := NewDBTime(time.Time{})
if v, err := zero.Value(); err != nil {
t.Fatalf("unexpected error for zero Value: %v", err)
} else if v != nil {
t.Fatalf("expected nil driver.Value for zero time, got %#v", v)
}
if s := zero.String(); s != "" {
t.Fatalf("expected empty string for zero DBTime.String(), got %q", s)
}
tt := time.Date(2023, 10, 5, 13, 14, 15, 0, time.UTC)
dt := NewDBTime(tt)
val, err := dt.Value()
if err != nil {
t.Fatalf("unexpected error for non-zero Value: %v", err)
}
strVal, ok := val.(string)
if !ok {
t.Fatalf("expected Value to be string, got %T", val)
}
expected := tt.Format(time.DateTime)
if strVal != expected {
t.Fatalf("Value() = %q, want %q", strVal, expected)
}
if s := dt.String(); s != expected {
t.Fatalf("String() = %q, want %q", s, expected)
}
}
func TestDBTime_Scan_VariousInputs(t *testing.T) {
base := time.Date(2022, 12, 31, 23, 59, 59, 0, time.UTC)
layout := time.DateTime
formatted := base.Format(layout)
tests := []struct {
name string
input interface{}
wantTime time.Time
wantIsZero bool
expectError bool
}{
{"nil sets zero", nil, time.Time{}, true, false},
{"scan from string", formatted, base, false, false},
{"scan from []byte", []byte(formatted), base, false, false},
{"scan from time.Time", base, base, false, false},
{"invalid parse", "not-a-time", time.Time{}, true, true},
{"unsupported type", 12345, time.Time{}, true, true},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var dt DBTime
err := dt.Scan(tc.input)
if tc.expectError {
if err == nil {
t.Fatalf("expected error, got nil")
}
// when expecting error, no further checks
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tc.wantIsZero {
if !dt.IsZero() {
t.Fatalf("expected DBTime to be zero, got %v", dt.Time)
}
return
}
if dt.IsZero() {
t.Fatalf("expected non-zero time, got zero")
}
// Compare times using Equal to ignore monotonic clock bits
if !dt.Equal(tc.wantTime) {
t.Fatalf("scanned time = %v, want %v", dt.Time, tc.wantTime)
}
})
}
}
func TestDBTime_Scan_ParseErrorDetails(t *testing.T) {
var dt DBTime
err := dt.Scan("garbage")
if err == nil {
t.Fatalf("expected parse error, got nil")
}
// error message should mention parse
if !contains(err.Error(), "could not parse time") {
t.Fatalf("unexpected error message: %v", err)
}
}
func TestDBTime_Scan_UnsupportedTypeMessage(t *testing.T) {
var dt DBTime
typ := struct{}{}
err := dt.Scan(typ)
if err == nil {
t.Fatalf("expected unsupported-type error, got nil")
}
want := fmt.Sprintf("could not scan type %T into DBTime", typ)
if err.Error() != want {
t.Fatalf("error = %q, want %q", err.Error(), want)
}
}
// small helper to avoid importing strings for a single contains check
func contains(s, substr string) bool {
return len(substr) == 0 || (len(s) >= len(substr) && indexOf(s, substr) >= 0)
}
func indexOf(s, substr string) int {
n := len(s)
m := len(substr)
if m == 0 {
return 0
}
for i := 0; i <= n-m; i++ {
if s[i:i+m] == substr {
return i
}
}
return -1
}