initial commit
This commit is contained in:
346
builder_test.go
Normal file
346
builder_test.go
Normal file
@@ -0,0 +1,346 @@
|
||||
package timefmt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBuilder_BasicFormats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
builder func() *Builder
|
||||
wantGo string
|
||||
wantLDML string
|
||||
}{
|
||||
{
|
||||
name: "ISO 8601 date",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
Year4().Dash().MonthNumeric2().Dash().DayNumeric2()
|
||||
},
|
||||
wantGo: "2006-01-02",
|
||||
wantLDML: "yyyy-MM-dd",
|
||||
},
|
||||
{
|
||||
name: "24-hour time",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
Hour24().Colon().Minute().Colon().Second()
|
||||
},
|
||||
wantGo: "15:04:05",
|
||||
wantLDML: "HH:mm:ss",
|
||||
},
|
||||
{
|
||||
name: "Full datetime",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
Year4().Dash().MonthNumeric2().Dash().DayNumeric2().
|
||||
Space().
|
||||
Hour24().Colon().Minute().Colon().Second()
|
||||
},
|
||||
wantGo: "2006-01-02 15:04:05",
|
||||
wantLDML: "yyyy-MM-dd HH:mm:ss",
|
||||
},
|
||||
{
|
||||
name: "12-hour with AM/PM",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
Hour12().Colon().Minute().Space().AMPM()
|
||||
},
|
||||
wantGo: "3:04 PM",
|
||||
wantLDML: "h:mm a",
|
||||
},
|
||||
{
|
||||
name: "US date format",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
MonthNumeric2().Slash().DayNumeric2().Slash().Year4()
|
||||
},
|
||||
wantGo: "01/02/2006",
|
||||
wantLDML: "MM/dd/yyyy",
|
||||
},
|
||||
{
|
||||
name: "European date format",
|
||||
builder: func() *Builder {
|
||||
return NewBuilder().
|
||||
DayNumeric2().Slash().MonthNumeric2().Slash().Year4()
|
||||
},
|
||||
wantGo: "02/01/2006",
|
||||
wantLDML: "dd/MM/yyyy",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
format := tt.builder().Build()
|
||||
|
||||
gotGo := format.GoFormat()
|
||||
if gotGo != tt.wantGo {
|
||||
t.Errorf("GoFormat() = %q, want %q", gotGo, tt.wantGo)
|
||||
}
|
||||
|
||||
gotLDML := format.LDML()
|
||||
if gotLDML != tt.wantLDML {
|
||||
t.Errorf("LDML() = %q, want %q", gotLDML, tt.wantLDML)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ChainableMethods(t *testing.T) {
|
||||
// Test that all methods return *Builder for chaining
|
||||
builder := NewBuilder()
|
||||
|
||||
result := builder.
|
||||
Year4().Year2().
|
||||
MonthNumeric().MonthNumeric2().MonthShort().MonthFull().
|
||||
DayNumeric().DayNumeric2().DaySpacePadded().DayOfYear().
|
||||
WeekdayShort().WeekdayFull().
|
||||
Hour24().Hour12().Hour12Padded().
|
||||
Minute().MinuteUnpadded().
|
||||
Second().SecondUnpadded().
|
||||
Millisecond().Microsecond().Nanosecond().
|
||||
AMPM().AMPMLower().
|
||||
TimezoneOffset().TimezoneOffsetColon().TimezoneName().
|
||||
Literal("test").Dash().Slash().Colon().Space().T().Comma().Period()
|
||||
|
||||
if result == nil {
|
||||
t.Error("Builder methods should return *Builder for chaining")
|
||||
}
|
||||
|
||||
// Verify it's the same builder instance (mutable pattern)
|
||||
if result != builder {
|
||||
t.Error("Builder methods should return the same builder instance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_LiteralShortcuts(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
builder func() *Builder
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Dash",
|
||||
builder: func() *Builder { return NewBuilder().Dash() },
|
||||
want: "-",
|
||||
},
|
||||
{
|
||||
name: "Slash",
|
||||
builder: func() *Builder { return NewBuilder().Slash() },
|
||||
want: "/",
|
||||
},
|
||||
{
|
||||
name: "Colon",
|
||||
builder: func() *Builder { return NewBuilder().Colon() },
|
||||
want: ":",
|
||||
},
|
||||
{
|
||||
name: "Space",
|
||||
builder: func() *Builder { return NewBuilder().Space() },
|
||||
want: " ",
|
||||
},
|
||||
{
|
||||
name: "T",
|
||||
builder: func() *Builder { return NewBuilder().T() },
|
||||
want: "T",
|
||||
},
|
||||
{
|
||||
name: "Comma",
|
||||
builder: func() *Builder { return NewBuilder().Comma() },
|
||||
want: ", ",
|
||||
},
|
||||
{
|
||||
name: "Period",
|
||||
builder: func() *Builder { return NewBuilder().Period() },
|
||||
want: ".",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
format := tt.builder().Build()
|
||||
got := format.GoFormat()
|
||||
if got != tt.want {
|
||||
t.Errorf("GoFormat() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_ComplexFormat(t *testing.T) {
|
||||
// Build a complex format with multiple components
|
||||
format := NewBuilder().
|
||||
WeekdayFull().Comma().
|
||||
MonthFull().Space().DayNumeric().Comma().Year4().
|
||||
Space().Literal("at").Space().
|
||||
Hour12().Colon().Minute().Space().AMPM().
|
||||
Space().Literal("(").TimezoneName().Literal(")").
|
||||
Build()
|
||||
|
||||
wantGo := "Monday, January 2, 2006 at 3:04 PM (MST)"
|
||||
gotGo := format.GoFormat()
|
||||
if gotGo != wantGo {
|
||||
t.Errorf("GoFormat() = %q, want %q", gotGo, wantGo)
|
||||
}
|
||||
|
||||
// Test that it actually formats correctly
|
||||
testTime := time.Date(2026, time.February, 8, 15, 4, 5, 0, time.FixedZone("MST", -7*3600))
|
||||
formatted := format.Format(testTime)
|
||||
expected := "Sunday, February 8, 2026 at 3:04 PM (MST)"
|
||||
if formatted != expected {
|
||||
t.Errorf("Format() = %q, want %q", formatted, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrebuiltFormats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
format *Format
|
||||
wantGo string
|
||||
}{
|
||||
{
|
||||
name: "ISO8601",
|
||||
format: ISO8601,
|
||||
wantGo: "2006-01-02T15:04:05Z07:00",
|
||||
},
|
||||
{
|
||||
name: "RFC3339",
|
||||
format: RFC3339,
|
||||
wantGo: "2006-01-02T15:04:05Z07:00",
|
||||
},
|
||||
{
|
||||
name: "RFC3339Nano",
|
||||
format: RFC3339Nano,
|
||||
wantGo: "2006-01-02T15:04:05.999999999Z07:00",
|
||||
},
|
||||
{
|
||||
name: "DateOnly",
|
||||
format: DateOnly,
|
||||
wantGo: "2006-01-02",
|
||||
},
|
||||
{
|
||||
name: "TimeOnly",
|
||||
format: TimeOnly,
|
||||
wantGo: "15:04:05",
|
||||
},
|
||||
{
|
||||
name: "DateTime",
|
||||
format: DateTime,
|
||||
wantGo: "2006-01-02 15:04:05",
|
||||
},
|
||||
{
|
||||
name: "DateTimeWithMillis",
|
||||
format: DateTimeWithMillis,
|
||||
wantGo: "2006-01-02 15:04:05.000",
|
||||
},
|
||||
{
|
||||
name: "DateUS",
|
||||
format: DateUS,
|
||||
wantGo: "01/02/2006",
|
||||
},
|
||||
{
|
||||
name: "DateEU",
|
||||
format: DateEU,
|
||||
wantGo: "02/01/2006",
|
||||
},
|
||||
{
|
||||
name: "DateTimeUS",
|
||||
format: DateTimeUS,
|
||||
wantGo: "01/02/2006 3:04:05 PM",
|
||||
},
|
||||
{
|
||||
name: "DateTimeEU",
|
||||
format: DateTimeEU,
|
||||
wantGo: "02/01/2006 15:04:05",
|
||||
},
|
||||
{
|
||||
name: "Kitchen",
|
||||
format: Kitchen,
|
||||
wantGo: "3:04 PM",
|
||||
},
|
||||
{
|
||||
name: "Stamp",
|
||||
format: Stamp,
|
||||
wantGo: "Jan _2 15:04:05",
|
||||
},
|
||||
{
|
||||
name: "StampMilli",
|
||||
format: StampMilli,
|
||||
wantGo: "Jan _2 15:04:05.000",
|
||||
},
|
||||
{
|
||||
name: "StampMicro",
|
||||
format: StampMicro,
|
||||
wantGo: "Jan _2 15:04:05.000000",
|
||||
},
|
||||
{
|
||||
name: "StampNano",
|
||||
format: StampNano,
|
||||
wantGo: "Jan _2 15:04:05.000000000",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.format == nil {
|
||||
t.Fatal("Format is nil")
|
||||
}
|
||||
|
||||
gotGo := tt.format.GoFormat()
|
||||
if gotGo != tt.wantGo {
|
||||
t.Errorf("GoFormat() = %q, want %q", gotGo, tt.wantGo)
|
||||
}
|
||||
|
||||
// Verify LDML and Description don't panic
|
||||
_ = tt.format.LDML()
|
||||
_ = tt.format.Description()
|
||||
_ = tt.format.Example()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrebuiltFormats_Formatting(t *testing.T) {
|
||||
testTime := time.Date(2026, time.February, 8, 15, 4, 5, 123456789, time.UTC)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
format *Format
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "DateOnly",
|
||||
format: DateOnly,
|
||||
want: "2026-02-08",
|
||||
},
|
||||
{
|
||||
name: "TimeOnly",
|
||||
format: TimeOnly,
|
||||
want: "15:04:05",
|
||||
},
|
||||
{
|
||||
name: "DateTime",
|
||||
format: DateTime,
|
||||
want: "2026-02-08 15:04:05",
|
||||
},
|
||||
{
|
||||
name: "DateUS",
|
||||
format: DateUS,
|
||||
want: "02/08/2026",
|
||||
},
|
||||
{
|
||||
name: "DateEU",
|
||||
format: DateEU,
|
||||
want: "08/02/2026",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.format.Format(testTime)
|
||||
if got != tt.want {
|
||||
t.Errorf("Format() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user