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) } }) } }