Source file
src/encoding/json/v2/arshal_time_test.go
1
2
3
4
5
6
7 package json
8
9 import (
10 "fmt"
11 "math"
12 "testing"
13 "time"
14
15 "encoding/json/internal/jsonwire"
16 )
17
18 func baseLabel(base uint64) string {
19 if log10 := math.Log10(float64(base)); log10 == float64(int64(log10)) {
20 return fmt.Sprintf("1e%d", int(log10))
21 }
22 return fmt.Sprint(base)
23 }
24
25 var formatDurationTestdata = []struct {
26 td time.Duration
27 base10Sec string
28 base10Milli string
29 base10Micro string
30 base10Nano string
31 }{
32 {math.MaxInt64, "9223372036.854775807", "9223372036854.775807", "9223372036854775.807", "9223372036854775807"},
33 {1e12 + 1e12, "2000", "2000000", "2000000000", "2000000000000"},
34 {1e12 + 1e11, "1100", "1100000", "1100000000", "1100000000000"},
35 {1e12 + 1e10, "1010", "1010000", "1010000000", "1010000000000"},
36 {1e12 + 1e9, "1001", "1001000", "1001000000", "1001000000000"},
37 {1e12 + 1e8, "1000.1", "1000100", "1000100000", "1000100000000"},
38 {1e12 + 1e7, "1000.01", "1000010", "1000010000", "1000010000000"},
39 {1e12 + 1e6, "1000.001", "1000001", "1000001000", "1000001000000"},
40 {1e12 + 1e5, "1000.0001", "1000000.1", "1000000100", "1000000100000"},
41 {1e12 + 1e4, "1000.00001", "1000000.01", "1000000010", "1000000010000"},
42 {1e12 + 1e3, "1000.000001", "1000000.001", "1000000001", "1000000001000"},
43 {1e12 + 1e2, "1000.0000001", "1000000.0001", "1000000000.1", "1000000000100"},
44 {1e12 + 1e1, "1000.00000001", "1000000.00001", "1000000000.01", "1000000000010"},
45 {1e12 + 1e0, "1000.000000001", "1000000.000001", "1000000000.001", "1000000000001"},
46 {+(1e9 + 1), "1.000000001", "1000.000001", "1000000.001", "1000000001"},
47 {+(1e9), "1", "1000", "1000000", "1000000000"},
48 {+(1e9 - 1), "0.999999999", "999.999999", "999999.999", "999999999"},
49 {+100000000, "0.1", "100", "100000", "100000000"},
50 {+120000000, "0.12", "120", "120000", "120000000"},
51 {+123000000, "0.123", "123", "123000", "123000000"},
52 {+123400000, "0.1234", "123.4", "123400", "123400000"},
53 {+123450000, "0.12345", "123.45", "123450", "123450000"},
54 {+123456000, "0.123456", "123.456", "123456", "123456000"},
55 {+123456700, "0.1234567", "123.4567", "123456.7", "123456700"},
56 {+123456780, "0.12345678", "123.45678", "123456.78", "123456780"},
57 {+123456789, "0.123456789", "123.456789", "123456.789", "123456789"},
58 {+12345678, "0.012345678", "12.345678", "12345.678", "12345678"},
59 {+1234567, "0.001234567", "1.234567", "1234.567", "1234567"},
60 {+123456, "0.000123456", "0.123456", "123.456", "123456"},
61 {+12345, "0.000012345", "0.012345", "12.345", "12345"},
62 {+1234, "0.000001234", "0.001234", "1.234", "1234"},
63 {+123, "0.000000123", "0.000123", "0.123", "123"},
64 {+12, "0.000000012", "0.000012", "0.012", "12"},
65 {+1, "0.000000001", "0.000001", "0.001", "1"},
66 {0, "0", "0", "0", "0"},
67 {-1, "-0.000000001", "-0.000001", "-0.001", "-1"},
68 {-12, "-0.000000012", "-0.000012", "-0.012", "-12"},
69 {-123, "-0.000000123", "-0.000123", "-0.123", "-123"},
70 {-1234, "-0.000001234", "-0.001234", "-1.234", "-1234"},
71 {-12345, "-0.000012345", "-0.012345", "-12.345", "-12345"},
72 {-123456, "-0.000123456", "-0.123456", "-123.456", "-123456"},
73 {-1234567, "-0.001234567", "-1.234567", "-1234.567", "-1234567"},
74 {-12345678, "-0.012345678", "-12.345678", "-12345.678", "-12345678"},
75 {-123456789, "-0.123456789", "-123.456789", "-123456.789", "-123456789"},
76 {-123456780, "-0.12345678", "-123.45678", "-123456.78", "-123456780"},
77 {-123456700, "-0.1234567", "-123.4567", "-123456.7", "-123456700"},
78 {-123456000, "-0.123456", "-123.456", "-123456", "-123456000"},
79 {-123450000, "-0.12345", "-123.45", "-123450", "-123450000"},
80 {-123400000, "-0.1234", "-123.4", "-123400", "-123400000"},
81 {-123000000, "-0.123", "-123", "-123000", "-123000000"},
82 {-120000000, "-0.12", "-120", "-120000", "-120000000"},
83 {-100000000, "-0.1", "-100", "-100000", "-100000000"},
84 {-(1e9 - 1), "-0.999999999", "-999.999999", "-999999.999", "-999999999"},
85 {-(1e9), "-1", "-1000", "-1000000", "-1000000000"},
86 {-(1e9 + 1), "-1.000000001", "-1000.000001", "-1000000.001", "-1000000001"},
87 {math.MinInt64, "-9223372036.854775808", "-9223372036854.775808", "-9223372036854775.808", "-9223372036854775808"},
88 }
89
90 func TestFormatDuration(t *testing.T) {
91 var gotBuf []byte
92 check := func(td time.Duration, s string, base uint64) {
93 a := durationArshaler{td, base}
94 gotBuf, _ = a.appendMarshal(gotBuf[:0])
95 if string(gotBuf) != s {
96 t.Errorf("formatDuration(%d, %s) = %q, want %q", td, baseLabel(base), string(gotBuf), s)
97 }
98 if err := a.unmarshal(gotBuf); err != nil {
99 t.Errorf("parseDuration(%q, %s) error: %v", gotBuf, baseLabel(base), err)
100 }
101 if a.td != td {
102 t.Errorf("parseDuration(%q, %s) = %d, want %d", gotBuf, baseLabel(base), a.td, td)
103 }
104 }
105 for _, tt := range formatDurationTestdata {
106 check(tt.td, tt.base10Sec, 1e9)
107 check(tt.td, tt.base10Milli, 1e6)
108 check(tt.td, tt.base10Micro, 1e3)
109 check(tt.td, tt.base10Nano, 1e0)
110 }
111 }
112
113 var parseDurationTestdata = []struct {
114 in string
115 base uint64
116 want time.Duration
117 wantErr bool
118 }{
119 {"0", 1e0, 0, false},
120 {"0.", 1e0, 0, true},
121 {"0.0", 1e0, 0, false},
122 {"0.00", 1e0, 0, false},
123 {"00.0", 1e0, 0, true},
124 {"+0", 1e0, 0, true},
125 {"1e0", 1e0, 0, true},
126 {"1.000000000x", 1e9, 0, true},
127 {"1.000000x", 1e6, 0, true},
128 {"1.000x", 1e3, 0, true},
129 {"1.x", 1e0, 0, true},
130 {"1.0000000009", 1e9, +time.Second, false},
131 {"1.0000009", 1e6, +time.Millisecond, false},
132 {"1.0009", 1e3, +time.Microsecond, false},
133 {"1.9", 1e0, +time.Nanosecond, false},
134 {"-9223372036854775809", 1e0, 0, true},
135 {"9223372036854775.808", 1e3, 0, true},
136 {"-9223372036854.775809", 1e6, 0, true},
137 {"9223372036.854775808", 1e9, 0, true},
138 {"-1.9", 1e0, -time.Nanosecond, false},
139 {"-1.0009", 1e3, -time.Microsecond, false},
140 {"-1.0000009", 1e6, -time.Millisecond, false},
141 {"-1.0000000009", 1e9, -time.Second, false},
142 }
143
144 func TestParseDuration(t *testing.T) {
145 for _, tt := range parseDurationTestdata {
146 a := durationArshaler{base: tt.base}
147 switch err := a.unmarshal([]byte(tt.in)); {
148 case a.td != tt.want:
149 t.Errorf("parseDuration(%q, %s) = %v, want %v", tt.in, baseLabel(tt.base), a.td, tt.want)
150 case (err == nil) && tt.wantErr:
151 t.Errorf("parseDuration(%q, %s) error is nil, want non-nil", tt.in, baseLabel(tt.base))
152 case (err != nil) && !tt.wantErr:
153 t.Errorf("parseDuration(%q, %s) error is non-nil, want nil", tt.in, baseLabel(tt.base))
154 }
155 }
156 }
157
158 func FuzzFormatDuration(f *testing.F) {
159 for _, tt := range formatDurationTestdata {
160 f.Add(int64(tt.td))
161 }
162 f.Fuzz(func(t *testing.T, want int64) {
163 var buf []byte
164 for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9} {
165 a := durationArshaler{td: time.Duration(want), base: base}
166 buf, _ = a.appendMarshal(buf[:0])
167 switch err := a.unmarshal(buf); {
168 case err != nil:
169 t.Fatalf("parseDuration(%q, %s) error: %v", buf, baseLabel(base), err)
170 case a.td != time.Duration(want):
171 t.Fatalf("parseDuration(%q, %s) = %v, want %v", buf, baseLabel(base), a.td, time.Duration(want))
172 }
173 }
174 })
175 }
176
177 func FuzzParseDuration(f *testing.F) {
178 for _, tt := range parseDurationTestdata {
179 f.Add([]byte(tt.in))
180 }
181 f.Fuzz(func(t *testing.T, in []byte) {
182 for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9, 60} {
183 a := durationArshaler{base: base}
184 if err := a.unmarshal(in); err == nil && base != 60 {
185 if n, err := jsonwire.ConsumeNumber(in); err != nil || n != len(in) {
186 t.Fatalf("parseDuration(%q) error is nil for invalid JSON number", in)
187 }
188 }
189 }
190 })
191 }
192
193 type formatTimeTestdataEntry struct {
194 ts time.Time
195 unixSec string
196 unixMilli string
197 unixMicro string
198 unixNano string
199 }
200
201 var formatTimeTestdata = func() []formatTimeTestdataEntry {
202 out := []formatTimeTestdataEntry{
203 {time.Unix(math.MaxInt64/int64(1e0), 1e9-1).UTC(), "9223372036854775807.999999999", "9223372036854775807999.999999", "9223372036854775807999999.999", "9223372036854775807999999999"},
204 {time.Unix(math.MaxInt64/int64(1e1), 1e9-1).UTC(), "922337203685477580.999999999", "922337203685477580999.999999", "922337203685477580999999.999", "922337203685477580999999999"},
205 {time.Unix(math.MaxInt64/int64(1e2), 1e9-1).UTC(), "92233720368547758.999999999", "92233720368547758999.999999", "92233720368547758999999.999", "92233720368547758999999999"},
206 {time.Unix(math.MinInt64, 1).UTC(), "-9223372036854775807.999999999", "-9223372036854775807999.999999", "-9223372036854775807999999.999", "-9223372036854775807999999999"},
207 {time.Unix(math.MinInt64, 0).UTC(), "-9223372036854775808", "-9223372036854775808000", "-9223372036854775808000000", "-9223372036854775808000000000"},
208 }
209 for _, tt := range formatDurationTestdata {
210 out = append(out, formatTimeTestdataEntry{time.Unix(0, int64(tt.td)).UTC(), tt.base10Sec, tt.base10Milli, tt.base10Micro, tt.base10Nano})
211 }
212 return out
213 }()
214
215 func TestFormatTime(t *testing.T) {
216 var gotBuf []byte
217 check := func(ts time.Time, s string, pow10 uint64) {
218 gotBuf = appendTimeUnix(gotBuf[:0], ts, pow10)
219 if string(gotBuf) != s {
220 t.Errorf("formatTime(time.Unix(%d, %d), %s) = %q, want %q", ts.Unix(), ts.Nanosecond(), baseLabel(pow10), string(gotBuf), s)
221 }
222 gotTS, err := parseTimeUnix(gotBuf, pow10)
223 if err != nil {
224 t.Errorf("parseTime(%q, %s) error: %v", gotBuf, baseLabel(pow10), err)
225 }
226 if !gotTS.Equal(ts) {
227 t.Errorf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", gotBuf, baseLabel(pow10), gotTS.Unix(), gotTS.Nanosecond(), ts.Unix(), ts.Nanosecond())
228 }
229 }
230 for _, tt := range formatTimeTestdata {
231 check(tt.ts, tt.unixSec, 1e0)
232 check(tt.ts, tt.unixMilli, 1e3)
233 check(tt.ts, tt.unixMicro, 1e6)
234 check(tt.ts, tt.unixNano, 1e9)
235 }
236 }
237
238 var parseTimeTestdata = []struct {
239 in string
240 base uint64
241 want time.Time
242 wantErr bool
243 }{
244 {"0", 1e0, time.Unix(0, 0).UTC(), false},
245 {"0.", 1e0, time.Time{}, true},
246 {"0.0", 1e0, time.Unix(0, 0).UTC(), false},
247 {"0.00", 1e0, time.Unix(0, 0).UTC(), false},
248 {"00.0", 1e0, time.Time{}, true},
249 {"+0", 1e0, time.Time{}, true},
250 {"1e0", 1e0, time.Time{}, true},
251 {"1234567890123456789012345678901234567890", 1e0, time.Time{}, true},
252 {"9223372036854775808000.000000", 1e3, time.Time{}, true},
253 {"9223372036854775807999999.9999", 1e6, time.Unix(math.MaxInt64, 1e9-1).UTC(), false},
254 {"9223372036854775807999999999.9", 1e9, time.Unix(math.MaxInt64, 1e9-1).UTC(), false},
255 {"9223372036854775807.999999999x", 1e0, time.Time{}, true},
256 {"9223372036854775807000000000", 1e9, time.Unix(math.MaxInt64, 0).UTC(), false},
257 {"-9223372036854775808", 1e0, time.Unix(math.MinInt64, 0).UTC(), false},
258 {"-9223372036854775808000.000001", 1e3, time.Time{}, true},
259 {"-9223372036854775808000000.0001", 1e6, time.Unix(math.MinInt64, 0).UTC(), false},
260 {"-9223372036854775808000000000.x", 1e9, time.Time{}, true},
261 {"-1234567890123456789012345678901234567890", 1e9, time.Time{}, true},
262 }
263
264 func TestParseTime(t *testing.T) {
265 for _, tt := range parseTimeTestdata {
266 a := timeArshaler{base: tt.base}
267 switch err := a.unmarshal([]byte(tt.in)); {
268 case a.tt != tt.want:
269 t.Errorf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", tt.in, baseLabel(tt.base), a.tt.Unix(), a.tt.Nanosecond(), tt.want.Unix(), tt.want.Nanosecond())
270 case (err == nil) && tt.wantErr:
271 t.Errorf("parseTime(%q, %s) = (time.Unix(%d, %d), nil), want non-nil error", tt.in, baseLabel(tt.base), a.tt.Unix(), a.tt.Nanosecond())
272 case (err != nil) && !tt.wantErr:
273 t.Errorf("parseTime(%q, %s) error is non-nil, want nil", tt.in, baseLabel(tt.base))
274 }
275 }
276 }
277
278 func FuzzFormatTime(f *testing.F) {
279 for _, tt := range formatTimeTestdata {
280 f.Add(tt.ts.Unix(), int64(tt.ts.Nanosecond()))
281 }
282 f.Fuzz(func(t *testing.T, wantSec, wantNano int64) {
283 want := time.Unix(wantSec, int64(uint64(wantNano)%1e9)).UTC()
284 var buf []byte
285 for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9} {
286 a := timeArshaler{tt: want, base: base}
287 buf, _ = a.appendMarshal(buf[:0])
288 switch err := a.unmarshal(buf); {
289 case err != nil:
290 t.Fatalf("parseTime(%q, %s) error: %v", buf, baseLabel(base), err)
291 case a.tt != want:
292 t.Fatalf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", buf, baseLabel(base), a.tt.Unix(), a.tt.Nanosecond(), want.Unix(), want.Nanosecond())
293 }
294 }
295 })
296 }
297
298 func FuzzParseTime(f *testing.F) {
299 for _, tt := range parseTimeTestdata {
300 f.Add([]byte(tt.in))
301 }
302 f.Fuzz(func(t *testing.T, in []byte) {
303 for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9} {
304 a := timeArshaler{base: base}
305 if err := a.unmarshal(in); err == nil {
306 if n, err := jsonwire.ConsumeNumber(in); err != nil || n != len(in) {
307 t.Fatalf("parseTime(%q) error is nil for invalid JSON number", in)
308 }
309 }
310 }
311 })
312 }
313
View as plain text