1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package day
import (
"reflect"
"testing"
"time"
)
func at(h, m int) time.Time {
return time.Date(2026, 7, 29, h, m, 0, 0, time.UTC)
}
func TestParseTarget(t *testing.T) {
cases := []struct {
name string
arg string
blockSize int
now time.Time
want []int
wantErr bool
}{
{"empty is current slot", "", 30, at(14, 47), []int{29}, false},
{"single time", "14:30", 30, at(0, 0), []int{29}, false},
{"snap down", "14:47", 30, at(0, 0), []int{29}, false},
{"single digit hour", "9:00", 30, at(0, 0), []int{18}, false},
{"leading zero", "09:00", 30, at(0, 0), []int{18}, false},
{"range end exclusive", "13:00-15:00", 30, at(0, 0), []int{26, 27, 28, 29}, false},
{"range at 15min blocks", "13:00-14:00", 15, at(0, 0), []int{52, 53, 54, 55}, false},
{"range at 60min blocks", "13:30-15:00", 60, at(0, 0), []int{13, 14}, false},
{"midnight slot", "0:00", 30, at(0, 0), []int{0}, false},
{"last slot", "23:30", 30, at(0, 0), []int{47}, false},
{"end before start", "15:00-13:00", 30, at(0, 0), nil, true},
{"end equals start", "13:00-13:00", 30, at(0, 0), nil, true},
{"hour out of range", "24:00", 30, at(0, 0), nil, true},
{"minute out of range", "12:60", 30, at(0, 0), nil, true},
{"garbage", "archer", 30, at(0, 0), nil, true},
{"single digit minute", "1:5", 30, at(0, 0), nil, true},
{"three digit hour", "007:00", 30, at(0, 0), nil, true},
{"leading space", " 9:00", 30, at(0, 0), nil, true},
{"incomplete range end", "9:00-", 30, at(0, 0), nil, true},
{"hyphen prefix", "-9:00", 30, at(0, 0), nil, true},
{"double hyphen in range", "9:00--15:00", 30, at(0, 0), nil, true},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got, err := ParseTarget(c.arg, c.blockSize, c.now)
if c.wantErr != (err != nil) {
t.Fatalf("err = %v, wantErr %v", err, c.wantErr)
}
if !c.wantErr && !reflect.DeepEqual(got, c.want) {
t.Fatalf("got %v, want %v", got, c.want)
}
})
}
}
func TestIsTimeSyntax(t *testing.T) {
yes := []string{"14:30", "9:00", "09:00", "13:00-15:00"}
no := []string{"archer", "", "14", "14:3", "a-b", "14:30ish", "1:5", " 9:00", "9:00-"}
for _, s := range yes {
if !IsTimeSyntax(s) {
t.Errorf("IsTimeSyntax(%q) = false, want true", s)
}
}
for _, s := range no {
if IsTimeSyntax(s) {
t.Errorf("IsTimeSyntax(%q) = true, want false", s)
}
}
}
func TestSlotLabel(t *testing.T) {
if got := SlotLabel(29, 30); got != "14:30" {
t.Fatalf("got %q", got)
}
if got := SlotLabel(0, 30); got != "0:00" {
t.Fatalf("got %q", got)
}
if got := SlotLabel(55, 15); got != "13:45" {
t.Fatalf("got %q", got)
}
}
|