package schedule import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestParseRejectsBadExpr(t *testing.T) { _, err := Parse("") assert.Error(t, err) _, err = Parse("0 0 31 2 *") // valid syntactically but never fires; cronutil accepts it // cronutil only validates syntax; an impossible date is still parsed. // We assert by separately rejecting clearly invalid syntax: _, err = Parse("not-a-cron") assert.Error(t, err) _, err = Parse("0 18 * *") // four fields assert.Error(t, err) _, err = Parse("0 0 * * * *") // six fields assert.Error(t, err) } func TestNextNoSkip(t *testing.T) { // Fires every day at 18:00 UTC. sched, err := Parse("0 18 * * *") require.NoError(t, err) after := time.Date(2026, 4, 27, 12, 0, 0, 0, time.UTC) got, skipped := sched.Next(after, false) assert.False(t, skipped) assert.Equal(t, time.Date(2026, 4, 27, 18, 0, 0, 0, time.UTC), got) assert.Equal(t, time.UTC, got.Location()) } func TestNextWithSkipAdvancesOneStep(t *testing.T) { sched, err := Parse("0 18 * * *") require.NoError(t, err) after := time.Date(2026, 4, 27, 12, 0, 0, 0, time.UTC) got, skipped := sched.Next(after, true) assert.True(t, skipped) // First slot would be 2026-04-27 18:00 UTC; the skip rule advances // to 2026-04-28 18:00 UTC. assert.Equal(t, time.Date(2026, 4, 28, 18, 0, 0, 0, time.UTC), got) } func TestNextNormalisesNonUTCInput(t *testing.T) { sched, err := Parse("*/15 * * * *") require.NoError(t, err) moscow := time.FixedZone("MSK", 3*60*60) // 2026-04-27 15:30 MSK = 2026-04-27 12:30 UTC; next 15-minute slot // in UTC is 12:45. after := time.Date(2026, 4, 27, 15, 30, 0, 0, moscow) got, skipped := sched.Next(after, false) assert.False(t, skipped) assert.Equal(t, time.Date(2026, 4, 27, 12, 45, 0, 0, time.UTC), got) assert.Equal(t, time.UTC, got.Location()) }