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 package toml
26
27 import (
28 "encoding/json"
29 "reflect"
30 "testing"
31 "time"
32 )
33
34 func cmpEqual(x, y interface{}) bool {
35 return reflect.DeepEqual(x, y)
36 }
37
38 func TestDates(t *testing.T) {
39 for _, test := range []struct {
40 date LocalDate
41 loc *time.Location
42 wantStr string
43 wantTime time.Time
44 }{
45 {
46 date: LocalDate{2014, 7, 29},
47 loc: time.Local,
48 wantStr: "2014-07-29",
49 wantTime: time.Date(2014, time.July, 29, 0, 0, 0, 0, time.Local),
50 },
51 {
52 date: LocalDateOf(time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local)),
53 loc: time.UTC,
54 wantStr: "2014-08-20",
55 wantTime: time.Date(2014, 8, 20, 0, 0, 0, 0, time.UTC),
56 },
57 {
58 date: LocalDateOf(time.Date(999, time.January, 26, 0, 0, 0, 0, time.Local)),
59 loc: time.UTC,
60 wantStr: "0999-01-26",
61 wantTime: time.Date(999, 1, 26, 0, 0, 0, 0, time.UTC),
62 },
63 } {
64 if got := test.date.String(); got != test.wantStr {
65 t.Errorf("%#v.String() = %q, want %q", test.date, got, test.wantStr)
66 }
67 if got := test.date.In(test.loc); !got.Equal(test.wantTime) {
68 t.Errorf("%#v.In(%v) = %v, want %v", test.date, test.loc, got, test.wantTime)
69 }
70 }
71 }
72
73 func TestDateIsValid(t *testing.T) {
74 for _, test := range []struct {
75 date LocalDate
76 want bool
77 }{
78 {LocalDate{2014, 7, 29}, true},
79 {LocalDate{2000, 2, 29}, true},
80 {LocalDate{10000, 12, 31}, true},
81 {LocalDate{1, 1, 1}, true},
82 {LocalDate{0, 1, 1}, true},
83 {LocalDate{-1, 1, 1}, true},
84 {LocalDate{1, 0, 1}, false},
85 {LocalDate{1, 1, 0}, false},
86 {LocalDate{2016, 1, 32}, false},
87 {LocalDate{2016, 13, 1}, false},
88 {LocalDate{1, -1, 1}, false},
89 {LocalDate{1, 1, -1}, false},
90 } {
91 got := test.date.IsValid()
92 if got != test.want {
93 t.Errorf("%#v: got %t, want %t", test.date, got, test.want)
94 }
95 }
96 }
97
98 func TestParseDate(t *testing.T) {
99 for _, test := range []struct {
100 str string
101 want LocalDate
102 }{
103 {"2016-01-02", LocalDate{2016, 1, 2}},
104 {"2016-12-31", LocalDate{2016, 12, 31}},
105 {"0003-02-04", LocalDate{3, 2, 4}},
106 {"999-01-26", LocalDate{}},
107 {"", LocalDate{}},
108 {"2016-01-02x", LocalDate{}},
109 } {
110 got, err := ParseLocalDate(test.str)
111 if got != test.want {
112 t.Errorf("ParseLocalDate(%q) = %+v, want %+v", test.str, got, test.want)
113 }
114 if err != nil && test.want != (LocalDate{}) {
115 t.Errorf("Unexpected error %v from ParseLocalDate(%q)", err, test.str)
116 }
117 }
118 }
119
120 func TestDateArithmetic(t *testing.T) {
121 for _, test := range []struct {
122 desc string
123 start LocalDate
124 end LocalDate
125 days int
126 }{
127 {
128 desc: "zero days noop",
129 start: LocalDate{2014, 5, 9},
130 end: LocalDate{2014, 5, 9},
131 days: 0,
132 },
133 {
134 desc: "crossing a year boundary",
135 start: LocalDate{2014, 12, 31},
136 end: LocalDate{2015, 1, 1},
137 days: 1,
138 },
139 {
140 desc: "negative number of days",
141 start: LocalDate{2015, 1, 1},
142 end: LocalDate{2014, 12, 31},
143 days: -1,
144 },
145 {
146 desc: "full leap year",
147 start: LocalDate{2004, 1, 1},
148 end: LocalDate{2005, 1, 1},
149 days: 366,
150 },
151 {
152 desc: "full non-leap year",
153 start: LocalDate{2001, 1, 1},
154 end: LocalDate{2002, 1, 1},
155 days: 365,
156 },
157 {
158 desc: "crossing a leap second",
159 start: LocalDate{1972, 6, 30},
160 end: LocalDate{1972, 7, 1},
161 days: 1,
162 },
163 {
164 desc: "dates before the unix epoch",
165 start: LocalDate{101, 1, 1},
166 end: LocalDate{102, 1, 1},
167 days: 365,
168 },
169 } {
170 if got := test.start.AddDays(test.days); got != test.end {
171 t.Errorf("[%s] %#v.AddDays(%v) = %#v, want %#v", test.desc, test.start, test.days, got, test.end)
172 }
173 if got := test.end.DaysSince(test.start); got != test.days {
174 t.Errorf("[%s] %#v.Sub(%#v) = %v, want %v", test.desc, test.end, test.start, got, test.days)
175 }
176 }
177 }
178
179 func TestDateBefore(t *testing.T) {
180 for _, test := range []struct {
181 d1, d2 LocalDate
182 want bool
183 }{
184 {LocalDate{2016, 12, 31}, LocalDate{2017, 1, 1}, true},
185 {LocalDate{2016, 1, 1}, LocalDate{2016, 1, 1}, false},
186 {LocalDate{2016, 12, 30}, LocalDate{2016, 12, 31}, true},
187 {LocalDate{2016, 1, 30}, LocalDate{2016, 12, 31}, true},
188 } {
189 if got := test.d1.Before(test.d2); got != test.want {
190 t.Errorf("%v.Before(%v): got %t, want %t", test.d1, test.d2, got, test.want)
191 }
192 }
193 }
194
195 func TestDateAfter(t *testing.T) {
196 for _, test := range []struct {
197 d1, d2 LocalDate
198 want bool
199 }{
200 {LocalDate{2016, 12, 31}, LocalDate{2017, 1, 1}, false},
201 {LocalDate{2016, 1, 1}, LocalDate{2016, 1, 1}, false},
202 {LocalDate{2016, 12, 30}, LocalDate{2016, 12, 31}, false},
203 } {
204 if got := test.d1.After(test.d2); got != test.want {
205 t.Errorf("%v.After(%v): got %t, want %t", test.d1, test.d2, got, test.want)
206 }
207 }
208 }
209
210 func TestTimeToString(t *testing.T) {
211 for _, test := range []struct {
212 str string
213 time LocalTime
214 roundTrip bool
215 }{
216 {"13:26:33", LocalTime{13, 26, 33, 0}, true},
217 {"01:02:03.000023456", LocalTime{1, 2, 3, 23456}, true},
218 {"00:00:00.000000001", LocalTime{0, 0, 0, 1}, true},
219 {"13:26:03.1", LocalTime{13, 26, 3, 100000000}, false},
220 {"13:26:33.0000003", LocalTime{13, 26, 33, 300}, false},
221 } {
222 gotTime, err := ParseLocalTime(test.str)
223 if err != nil {
224 t.Errorf("ParseLocalTime(%q): got error: %v", test.str, err)
225 continue
226 }
227 if gotTime != test.time {
228 t.Errorf("ParseLocalTime(%q) = %+v, want %+v", test.str, gotTime, test.time)
229 }
230 if test.roundTrip {
231 gotStr := test.time.String()
232 if gotStr != test.str {
233 t.Errorf("%#v.String() = %q, want %q", test.time, gotStr, test.str)
234 }
235 }
236 }
237 }
238
239 func TestTimeOf(t *testing.T) {
240 for _, test := range []struct {
241 time time.Time
242 want LocalTime
243 }{
244 {time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local), LocalTime{15, 8, 43, 1}},
245 {time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), LocalTime{0, 0, 0, 0}},
246 } {
247 if got := LocalTimeOf(test.time); got != test.want {
248 t.Errorf("LocalTimeOf(%v) = %+v, want %+v", test.time, got, test.want)
249 }
250 }
251 }
252
253 func TestTimeIsValid(t *testing.T) {
254 for _, test := range []struct {
255 time LocalTime
256 want bool
257 }{
258 {LocalTime{0, 0, 0, 0}, true},
259 {LocalTime{23, 0, 0, 0}, true},
260 {LocalTime{23, 59, 59, 999999999}, true},
261 {LocalTime{24, 59, 59, 999999999}, false},
262 {LocalTime{23, 60, 59, 999999999}, false},
263 {LocalTime{23, 59, 60, 999999999}, false},
264 {LocalTime{23, 59, 59, 1000000000}, false},
265 {LocalTime{-1, 0, 0, 0}, false},
266 {LocalTime{0, -1, 0, 0}, false},
267 {LocalTime{0, 0, -1, 0}, false},
268 {LocalTime{0, 0, 0, -1}, false},
269 } {
270 got := test.time.IsValid()
271 if got != test.want {
272 t.Errorf("%#v: got %t, want %t", test.time, got, test.want)
273 }
274 }
275 }
276
277 func TestDateTimeToString(t *testing.T) {
278 for _, test := range []struct {
279 str string
280 dateTime LocalDateTime
281 roundTrip bool
282 }{
283 {"2016-03-22T13:26:33", LocalDateTime{LocalDate{2016, 03, 22}, LocalTime{13, 26, 33, 0}}, true},
284 {"2016-03-22T13:26:33.000000600", LocalDateTime{LocalDate{2016, 03, 22}, LocalTime{13, 26, 33, 600}}, true},
285 {"2016-03-22t13:26:33", LocalDateTime{LocalDate{2016, 03, 22}, LocalTime{13, 26, 33, 0}}, false},
286 } {
287 gotDateTime, err := ParseLocalDateTime(test.str)
288 if err != nil {
289 t.Errorf("ParseLocalDateTime(%q): got error: %v", test.str, err)
290 continue
291 }
292 if gotDateTime != test.dateTime {
293 t.Errorf("ParseLocalDateTime(%q) = %+v, want %+v", test.str, gotDateTime, test.dateTime)
294 }
295 if test.roundTrip {
296 gotStr := test.dateTime.String()
297 if gotStr != test.str {
298 t.Errorf("%#v.String() = %q, want %q", test.dateTime, gotStr, test.str)
299 }
300 }
301 }
302 }
303
304 func TestParseDateTimeErrors(t *testing.T) {
305 for _, str := range []string{
306 "",
307 "2016-03-22",
308 "13:26:33",
309 "2016-03-22 13:26:33",
310 "2016-03-22T13:26:33x",
311 } {
312 if _, err := ParseLocalDateTime(str); err == nil {
313 t.Errorf("ParseLocalDateTime(%q) succeeded, want error", str)
314 }
315 }
316 }
317
318 func TestDateTimeOf(t *testing.T) {
319 for _, test := range []struct {
320 time time.Time
321 want LocalDateTime
322 }{
323 {time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local),
324 LocalDateTime{LocalDate{2014, 8, 20}, LocalTime{15, 8, 43, 1}}},
325 {time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC),
326 LocalDateTime{LocalDate{1, 1, 1}, LocalTime{0, 0, 0, 0}}},
327 } {
328 if got := LocalDateTimeOf(test.time); got != test.want {
329 t.Errorf("LocalDateTimeOf(%v) = %+v, want %+v", test.time, got, test.want)
330 }
331 }
332 }
333
334 func TestDateTimeIsValid(t *testing.T) {
335
336 for _, test := range []struct {
337 dt LocalDateTime
338 want bool
339 }{
340 {LocalDateTime{LocalDate{2016, 3, 20}, LocalTime{0, 0, 0, 0}}, true},
341 {LocalDateTime{LocalDate{2016, -3, 20}, LocalTime{0, 0, 0, 0}}, false},
342 {LocalDateTime{LocalDate{2016, 3, 20}, LocalTime{24, 0, 0, 0}}, false},
343 } {
344 got := test.dt.IsValid()
345 if got != test.want {
346 t.Errorf("%#v: got %t, want %t", test.dt, got, test.want)
347 }
348 }
349 }
350
351 func TestDateTimeIn(t *testing.T) {
352 dt := LocalDateTime{LocalDate{2016, 1, 2}, LocalTime{3, 4, 5, 6}}
353 got := dt.In(time.UTC)
354 want := time.Date(2016, 1, 2, 3, 4, 5, 6, time.UTC)
355 if !got.Equal(want) {
356 t.Errorf("got %v, want %v", got, want)
357 }
358 }
359
360 func TestDateTimeBefore(t *testing.T) {
361 d1 := LocalDate{2016, 12, 31}
362 d2 := LocalDate{2017, 1, 1}
363 t1 := LocalTime{5, 6, 7, 8}
364 t2 := LocalTime{5, 6, 7, 9}
365 for _, test := range []struct {
366 dt1, dt2 LocalDateTime
367 want bool
368 }{
369 {LocalDateTime{d1, t1}, LocalDateTime{d2, t1}, true},
370 {LocalDateTime{d1, t1}, LocalDateTime{d1, t2}, true},
371 {LocalDateTime{d2, t1}, LocalDateTime{d1, t1}, false},
372 {LocalDateTime{d2, t1}, LocalDateTime{d2, t1}, false},
373 } {
374 if got := test.dt1.Before(test.dt2); got != test.want {
375 t.Errorf("%v.Before(%v): got %t, want %t", test.dt1, test.dt2, got, test.want)
376 }
377 }
378 }
379
380 func TestDateTimeAfter(t *testing.T) {
381 d1 := LocalDate{2016, 12, 31}
382 d2 := LocalDate{2017, 1, 1}
383 t1 := LocalTime{5, 6, 7, 8}
384 t2 := LocalTime{5, 6, 7, 9}
385 for _, test := range []struct {
386 dt1, dt2 LocalDateTime
387 want bool
388 }{
389 {LocalDateTime{d1, t1}, LocalDateTime{d2, t1}, false},
390 {LocalDateTime{d1, t1}, LocalDateTime{d1, t2}, false},
391 {LocalDateTime{d2, t1}, LocalDateTime{d1, t1}, true},
392 {LocalDateTime{d2, t1}, LocalDateTime{d2, t1}, false},
393 } {
394 if got := test.dt1.After(test.dt2); got != test.want {
395 t.Errorf("%v.After(%v): got %t, want %t", test.dt1, test.dt2, got, test.want)
396 }
397 }
398 }
399
400 func TestMarshalJSON(t *testing.T) {
401 for _, test := range []struct {
402 value interface{}
403 want string
404 }{
405 {LocalDate{1987, 4, 15}, `"1987-04-15"`},
406 {LocalTime{18, 54, 2, 0}, `"18:54:02"`},
407 {LocalDateTime{LocalDate{1987, 4, 15}, LocalTime{18, 54, 2, 0}}, `"1987-04-15T18:54:02"`},
408 } {
409 bgot, err := json.Marshal(test.value)
410 if err != nil {
411 t.Fatal(err)
412 }
413 if got := string(bgot); got != test.want {
414 t.Errorf("%#v: got %s, want %s", test.value, got, test.want)
415 }
416 }
417 }
418
419 func TestUnmarshalJSON(t *testing.T) {
420 var d LocalDate
421 var tm LocalTime
422 var dt LocalDateTime
423 for _, test := range []struct {
424 data string
425 ptr interface{}
426 want interface{}
427 }{
428 {`"1987-04-15"`, &d, &LocalDate{1987, 4, 15}},
429 {`"1987-04-\u0031\u0035"`, &d, &LocalDate{1987, 4, 15}},
430 {`"18:54:02"`, &tm, &LocalTime{18, 54, 2, 0}},
431 {`"1987-04-15T18:54:02"`, &dt, &LocalDateTime{LocalDate{1987, 4, 15}, LocalTime{18, 54, 2, 0}}},
432 } {
433 if err := json.Unmarshal([]byte(test.data), test.ptr); err != nil {
434 t.Fatalf("%s: %v", test.data, err)
435 }
436 if !cmpEqual(test.ptr, test.want) {
437 t.Errorf("%s: got %#v, want %#v", test.data, test.ptr, test.want)
438 }
439 }
440
441 for _, bad := range []string{"", `""`, `"bad"`, `"1987-04-15x"`,
442 `19870415`,
443 `11987-04-15x`,
444
445 } {
446 if json.Unmarshal([]byte(bad), &d) == nil {
447 t.Errorf("%q, LocalDate: got nil, want error", bad)
448 }
449 if json.Unmarshal([]byte(bad), &tm) == nil {
450 t.Errorf("%q, LocalTime: got nil, want error", bad)
451 }
452 if json.Unmarshal([]byte(bad), &dt) == nil {
453 t.Errorf("%q, LocalDateTime: got nil, want error", bad)
454 }
455 }
456 }
457
View as plain text