539 lines
13 KiB
Go
539 lines
13 KiB
Go
package timestamp
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
// Test with no arguments
|
|
ts := New[int]()
|
|
if ts == nil {
|
|
t.Fatal("New() returned nil")
|
|
}
|
|
if ts.V != 0 {
|
|
t.Errorf("New() with no args: expected V=0, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test with one argument
|
|
ts = New(int64(1234567890))
|
|
if ts.V != 1234567890 {
|
|
t.Errorf("New(1234567890): expected V=1234567890, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test with different integer types
|
|
ts = New(int32(123))
|
|
if ts.V != 123 {
|
|
t.Errorf("New(int32(123)): expected V=123, got V=%d", ts.V)
|
|
}
|
|
|
|
ts = New(uint64(456))
|
|
if ts.V != 456 {
|
|
t.Errorf("New(uint64(456)): expected V=456, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test with multiple arguments (should only use first)
|
|
ts = New(100, 200, 300)
|
|
if ts.V != 100 {
|
|
t.Errorf("New(100, 200, 300): expected V=100, got V=%d", ts.V)
|
|
}
|
|
}
|
|
|
|
func TestNow(t *testing.T) {
|
|
before := time.Now().Unix()
|
|
ts := Now()
|
|
after := time.Now().Unix()
|
|
|
|
if ts == nil {
|
|
t.Fatal("Now() returned nil")
|
|
}
|
|
|
|
if ts.V < before || ts.V > after {
|
|
t.Errorf("Now(): timestamp %d not between %d and %d", ts.V, before, after)
|
|
}
|
|
}
|
|
|
|
func TestU64(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 1234567890}
|
|
result := ts.U64()
|
|
if result != 1234567890 {
|
|
t.Errorf("U64(): expected 1234567890, got %d", result)
|
|
}
|
|
|
|
// Test negative value
|
|
ts = &T{V: -123}
|
|
result = ts.U64()
|
|
expected := uint64(ts.V) // This will wrap around
|
|
if result != expected {
|
|
t.Errorf("U64() with negative: expected %d, got %d", expected, result)
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.U64()
|
|
if result != 0 {
|
|
t.Errorf("U64() on nil: expected 0, got %d", result)
|
|
}
|
|
}
|
|
|
|
func TestI64(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 1234567890}
|
|
result := ts.I64()
|
|
if result != 1234567890 {
|
|
t.Errorf("I64(): expected 1234567890, got %d", result)
|
|
}
|
|
|
|
// Test negative value
|
|
ts = &T{V: -123}
|
|
result = ts.I64()
|
|
if result != -123 {
|
|
t.Errorf("I64() with negative: expected -123, got %d", result)
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.I64()
|
|
if result != 0 {
|
|
t.Errorf("I64() on nil: expected 0, got %d", result)
|
|
}
|
|
}
|
|
|
|
func TestTime(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 1234567890}
|
|
result := ts.Time()
|
|
expected := time.Unix(1234567890, 0)
|
|
if !result.Equal(expected) {
|
|
t.Errorf("Time(): expected %v, got %v", expected, result)
|
|
}
|
|
|
|
// Test zero
|
|
ts = &T{V: 0}
|
|
result = ts.Time()
|
|
expected = time.Unix(0, 0)
|
|
if !result.Equal(expected) {
|
|
t.Errorf("Time() with zero: expected %v, got %v", expected, result)
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.Time()
|
|
expected = time.Unix(0, 0)
|
|
if !result.Equal(expected) {
|
|
t.Errorf("Time() on nil: expected %v, got %v", expected, result)
|
|
}
|
|
}
|
|
|
|
func TestInt(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 123}
|
|
result := ts.Int()
|
|
if result != 123 {
|
|
t.Errorf("Int(): expected 123, got %d", result)
|
|
}
|
|
|
|
// Test large value that might overflow int
|
|
ts = &T{V: math.MaxInt64}
|
|
result = ts.Int()
|
|
if result != int(math.MaxInt64) {
|
|
t.Errorf("Int() with MaxInt64: expected %d, got %d", int(math.MaxInt64), result)
|
|
}
|
|
|
|
// Test nil receiver
|
|
var nilTs *T
|
|
result = nilTs.Int()
|
|
if result != 0 {
|
|
t.Errorf("Int() on nil: expected 0, got %d", result)
|
|
}
|
|
}
|
|
|
|
func TestBytes(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 1234567890}
|
|
result := ts.Bytes()
|
|
if len(result) != 8 {
|
|
t.Errorf("Bytes(): expected length 8, got %d", len(result))
|
|
}
|
|
|
|
// Verify the bytes are correct
|
|
expected := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(expected, uint64(1234567890))
|
|
for i, b := range result {
|
|
if b != expected[i] {
|
|
t.Errorf("Bytes(): byte %d expected %d, got %d", i, expected[i], b)
|
|
}
|
|
}
|
|
|
|
// Test zero
|
|
ts = &T{V: 0}
|
|
result = ts.Bytes()
|
|
for i, b := range result {
|
|
if b != 0 {
|
|
t.Errorf("Bytes() with zero: byte %d expected 0, got %d", i, b)
|
|
}
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.Bytes()
|
|
if len(result) != 8 {
|
|
t.Errorf("Bytes() on nil: expected length 8, got %d", len(result))
|
|
}
|
|
for i, b := range result {
|
|
if b != 0 {
|
|
t.Errorf("Bytes() on nil: byte %d expected 0, got %d", i, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFromTime(t *testing.T) {
|
|
// Test normal case
|
|
tm := time.Unix(1234567890, 0)
|
|
ts := FromTime(tm)
|
|
if ts == nil {
|
|
t.Fatal("FromTime() returned nil")
|
|
}
|
|
if ts.V != 1234567890 {
|
|
t.Errorf("FromTime(): expected V=1234567890, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test zero time
|
|
tm = time.Unix(0, 0)
|
|
ts = FromTime(tm)
|
|
if ts.V != 0 {
|
|
t.Errorf("FromTime() with zero: expected V=0, got V=%d", ts.V)
|
|
}
|
|
}
|
|
|
|
func TestFromUnix(t *testing.T) {
|
|
// Test normal case
|
|
ts := FromUnix(1234567890)
|
|
if ts == nil {
|
|
t.Fatal("FromUnix() returned nil")
|
|
}
|
|
if ts.V != 1234567890 {
|
|
t.Errorf("FromUnix(1234567890): expected V=1234567890, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test negative
|
|
ts = FromUnix(-123)
|
|
if ts.V != -123 {
|
|
t.Errorf("FromUnix(-123): expected V=-123, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test zero
|
|
ts = FromUnix(0)
|
|
if ts.V != 0 {
|
|
t.Errorf("FromUnix(0): expected V=0, got V=%d", ts.V)
|
|
}
|
|
}
|
|
|
|
func TestFromInt(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{}
|
|
ts.FromInt(123)
|
|
if ts.V != 123 {
|
|
t.Errorf("FromInt(123): expected V=123, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test negative
|
|
ts.FromInt(-456)
|
|
if ts.V != -456 {
|
|
t.Errorf("FromInt(-456): expected V=-456, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test zero
|
|
ts.FromInt(0)
|
|
if ts.V != 0 {
|
|
t.Errorf("FromInt(0): expected V=0, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test nil receiver (should panic)
|
|
var nilTs *T
|
|
defer func() {
|
|
if r := recover(); r == nil {
|
|
t.Error("FromInt() on nil receiver should panic")
|
|
}
|
|
}()
|
|
nilTs.FromInt(123)
|
|
}
|
|
|
|
func TestFromBytes(t *testing.T) {
|
|
// Test normal case
|
|
b := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(b, uint64(1234567890))
|
|
ts := FromBytes(b)
|
|
if ts == nil {
|
|
t.Fatal("FromBytes() returned nil")
|
|
}
|
|
if ts.V != 1234567890 {
|
|
t.Errorf("FromBytes(): expected V=1234567890, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test zero bytes
|
|
b = make([]byte, 8)
|
|
ts = FromBytes(b)
|
|
if ts.V != 0 {
|
|
t.Errorf("FromBytes() with zero bytes: expected V=0, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test insufficient bytes (should panic or handle gracefully)
|
|
defer func() {
|
|
if r := recover(); r == nil {
|
|
t.Error("FromBytes() with insufficient bytes should panic or handle error")
|
|
}
|
|
}()
|
|
FromBytes([]byte{1, 2, 3}) // Only 3 bytes instead of 8
|
|
}
|
|
|
|
func TestFromVarint(t *testing.T) {
|
|
// Test normal case
|
|
b := make([]byte, 10)
|
|
n := binary.PutVarint(b, 1234567890)
|
|
ts, rem, err := FromVarint(b[:n])
|
|
if err != nil {
|
|
t.Errorf("FromVarint(): unexpected error: %v", err)
|
|
}
|
|
if ts == nil {
|
|
t.Fatal("FromVarint() returned nil timestamp")
|
|
}
|
|
if ts.V != 1234567890 {
|
|
t.Errorf("FromVarint(): expected V=1234567890, got V=%d", ts.V)
|
|
}
|
|
// The remainder should be the bytes after the varint
|
|
expectedRemLen := len(b[:n]) - n
|
|
if len(rem) != expectedRemLen {
|
|
t.Errorf("FromVarint(): expected rem length %d, got %d", expectedRemLen, len(rem))
|
|
}
|
|
|
|
// Test zero
|
|
b = make([]byte, 10)
|
|
n = binary.PutVarint(b, 0)
|
|
ts, rem, err = FromVarint(b[:n])
|
|
if err != nil {
|
|
t.Errorf("FromVarint() with zero: unexpected error: %v", err)
|
|
}
|
|
if ts.V != 0 {
|
|
t.Errorf("FromVarint() with zero: expected V=0, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test negative
|
|
b = make([]byte, 10)
|
|
n = binary.PutVarint(b, -123)
|
|
ts, rem, err = FromVarint(b[:n])
|
|
if err != nil {
|
|
t.Errorf("FromVarint() with negative: unexpected error: %v", err)
|
|
}
|
|
if ts.V != -123 {
|
|
t.Errorf("FromVarint() with negative: expected V=-123, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test invalid varint
|
|
_, _, err = FromVarint([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
|
|
if err == nil {
|
|
t.Error("FromVarint() with invalid varint should return error")
|
|
}
|
|
|
|
// Test empty bytes
|
|
_, _, err = FromVarint([]byte{})
|
|
if err == nil {
|
|
t.Error("FromVarint() with empty bytes should return error")
|
|
}
|
|
}
|
|
|
|
func TestString(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 123}
|
|
result := ts.String()
|
|
if result != "123" {
|
|
t.Errorf("String(): expected '123', got '%s'", result)
|
|
}
|
|
|
|
// Test zero
|
|
ts = &T{V: 0}
|
|
result = ts.String()
|
|
if result != "0" {
|
|
t.Errorf("String() with zero: expected '0', got '%s'", result)
|
|
}
|
|
|
|
// Test large number
|
|
ts = &T{V: 1234567890}
|
|
result = ts.String()
|
|
if result != "1234567890" {
|
|
t.Errorf("String() with large number: expected '1234567890', got '%s'", result)
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.String()
|
|
if result != "0" {
|
|
t.Errorf("String() on nil: expected '0', got '%s'", result)
|
|
}
|
|
}
|
|
|
|
func TestMarshal(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 123}
|
|
dst := make([]byte, 0, 10)
|
|
result := ts.Marshal(dst)
|
|
expected := "123"
|
|
if string(result) != expected {
|
|
t.Errorf("Marshal(): expected '%s', got '%s'", expected, string(result))
|
|
}
|
|
|
|
// Test with existing data in dst
|
|
dst = []byte("prefix")
|
|
result = ts.Marshal(dst)
|
|
expected = "prefix123"
|
|
if string(result) != expected {
|
|
t.Errorf("Marshal() with prefix: expected '%s', got '%s'", expected, string(result))
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result = nilTs.Marshal(nil)
|
|
expected = "0"
|
|
if string(result) != expected {
|
|
t.Errorf("Marshal() on nil: expected '%s', got '%s'", expected, string(result))
|
|
}
|
|
}
|
|
|
|
func TestUnmarshal(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{}
|
|
input := []byte("123abc")
|
|
rem, err := ts.Unmarshal(input)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal(): unexpected error: %v", err)
|
|
}
|
|
if ts.V != 123 {
|
|
t.Errorf("Unmarshal(): expected V=123, got V=%d", ts.V)
|
|
}
|
|
if string(rem) != "abc" {
|
|
t.Errorf("Unmarshal(): expected remainder 'abc', got '%s'", string(rem))
|
|
}
|
|
|
|
// Test with leading non-numeric characters
|
|
ts = &T{}
|
|
input = []byte("abc123def")
|
|
rem, err = ts.Unmarshal(input)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal() with prefix: unexpected error: %v", err)
|
|
}
|
|
if ts.V != 123 {
|
|
t.Errorf("Unmarshal() with prefix: expected V=123, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test zero
|
|
ts = &T{}
|
|
input = []byte("0")
|
|
rem, err = ts.Unmarshal(input)
|
|
if err != nil {
|
|
t.Errorf("Unmarshal() with zero: unexpected error: %v", err)
|
|
}
|
|
if ts.V != 0 {
|
|
t.Errorf("Unmarshal() with zero: expected V=0, got V=%d", ts.V)
|
|
}
|
|
|
|
// Test empty input
|
|
ts = &T{}
|
|
_, err = ts.Unmarshal([]byte{})
|
|
if err == nil {
|
|
t.Error("Unmarshal() with empty input should return error")
|
|
}
|
|
|
|
// Test nil receiver (now returns error)
|
|
var nilTs *T
|
|
_, err = nilTs.Unmarshal([]byte("123"))
|
|
if err == nil {
|
|
t.Error("Unmarshal() on nil receiver should return error")
|
|
}
|
|
}
|
|
|
|
func TestMarshalJSON(t *testing.T) {
|
|
// Test normal case
|
|
ts := &T{V: 123}
|
|
result, err := ts.MarshalJSON()
|
|
if err != nil {
|
|
t.Errorf("MarshalJSON(): unexpected error: %v", err)
|
|
}
|
|
if string(result) != "123" {
|
|
t.Errorf("MarshalJSON(): expected '123', got '%s'", string(result))
|
|
}
|
|
|
|
// Test zero
|
|
ts = &T{V: 0}
|
|
result, err = ts.MarshalJSON()
|
|
if err != nil {
|
|
t.Errorf("MarshalJSON() with zero: unexpected error: %v", err)
|
|
}
|
|
if string(result) != "0" {
|
|
t.Errorf("MarshalJSON() with zero: expected '0', got '%s'", string(result))
|
|
}
|
|
|
|
// Test integration with json package
|
|
ts = &T{V: 456}
|
|
jsonData, err := json.Marshal(ts)
|
|
if err != nil {
|
|
t.Errorf("json.Marshal(): unexpected error: %v", err)
|
|
}
|
|
// The result should be the custom MarshalJSON output since T implements json.Marshaler
|
|
expected := `456`
|
|
if string(jsonData) != expected {
|
|
t.Errorf("json.Marshal(): expected '%s', got '%s'", expected, string(jsonData))
|
|
}
|
|
|
|
// Test nil receiver (now handled gracefully)
|
|
var nilTs *T
|
|
result, err = nilTs.MarshalJSON()
|
|
if err != nil {
|
|
t.Errorf("MarshalJSON() on nil: unexpected error: %v", err)
|
|
}
|
|
if string(result) != "0" {
|
|
t.Errorf("MarshalJSON() on nil: expected '0', got '%s'", string(result))
|
|
}
|
|
}
|
|
|
|
func TestConstants(t *testing.T) {
|
|
// Test Len constant
|
|
if Len != 8 {
|
|
t.Errorf("Len constant: expected 8, got %d", Len)
|
|
}
|
|
}
|
|
|
|
// Test edge cases and integration
|
|
func TestIntegration(t *testing.T) {
|
|
// Test round-trip with Time
|
|
originalTime := time.Now()
|
|
ts := FromTime(originalTime)
|
|
convertedTime := ts.Time()
|
|
if convertedTime.Unix() != originalTime.Unix() {
|
|
t.Errorf("Time round-trip: expected %d, got %d", originalTime.Unix(), convertedTime.Unix())
|
|
}
|
|
|
|
// Test round-trip with Bytes
|
|
original := &T{V: 1234567890}
|
|
bytes := original.Bytes()
|
|
converted := FromBytes(bytes)
|
|
if converted.V != original.V {
|
|
t.Errorf("Bytes round-trip: expected %d, got %d", original.V, converted.V)
|
|
}
|
|
|
|
// Test round-trip with Marshal/Unmarshal
|
|
original = &T{V: 987654321}
|
|
marshaled := original.Marshal(nil)
|
|
converted = &T{}
|
|
_, err := converted.Unmarshal(marshaled)
|
|
if err != nil {
|
|
t.Errorf("Marshal/Unmarshal round-trip: unexpected error: %v", err)
|
|
}
|
|
if converted.V != original.V {
|
|
t.Errorf("Marshal/Unmarshal round-trip: expected %d, got %d", original.V, converted.V)
|
|
}
|
|
}
|