1
2
3
4
5 package json_test
6
7 import (
8 "math"
9 "strings"
10 "testing"
11
12 "github.com/google/go-cmp/cmp"
13 "github.com/google/go-cmp/cmp/cmpopts"
14
15 "google.golang.org/protobuf/internal/detrand"
16 "google.golang.org/protobuf/internal/encoding/json"
17 )
18
19
20 func init() { detrand.Disable() }
21
22
23 var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
24 return strings.Split(s, "\n")
25 })
26
27 func TestEncoder(t *testing.T) {
28 tests := []struct {
29 desc string
30 write func(*json.Encoder)
31 wantOut string
32 wantOutIndent string
33 }{
34 {
35 desc: "null",
36 write: func(e *json.Encoder) {
37 e.WriteNull()
38 },
39 wantOut: `null`,
40 },
41 {
42 desc: "true",
43 write: func(e *json.Encoder) {
44 e.WriteBool(true)
45 },
46 wantOut: `true`,
47 },
48 {
49 desc: "false",
50 write: func(e *json.Encoder) {
51 e.WriteBool(false)
52 },
53 wantOut: `false`,
54 },
55 {
56 desc: "string",
57 write: func(e *json.Encoder) {
58 e.WriteString("hello world")
59 },
60 wantOut: `"hello world"`,
61 },
62 {
63 desc: "string contains escaped characters",
64 write: func(e *json.Encoder) {
65 e.WriteString("\u0000\"\\/\b\f\n\r\t")
66 },
67 wantOut: `"\u0000\"\\/\b\f\n\r\t"`,
68 },
69 {
70 desc: "float64",
71 write: func(e *json.Encoder) {
72 e.WriteFloat(1.0199999809265137, 64)
73 },
74 wantOut: `1.0199999809265137`,
75 },
76 {
77 desc: "float64 max value",
78 write: func(e *json.Encoder) {
79 e.WriteFloat(math.MaxFloat64, 64)
80 },
81 wantOut: `1.7976931348623157e+308`,
82 },
83 {
84 desc: "float64 min value",
85 write: func(e *json.Encoder) {
86 e.WriteFloat(-math.MaxFloat64, 64)
87 },
88 wantOut: `-1.7976931348623157e+308`,
89 },
90 {
91 desc: "float64 NaN",
92 write: func(e *json.Encoder) {
93 e.WriteFloat(math.NaN(), 64)
94 },
95 wantOut: `"NaN"`,
96 },
97 {
98 desc: "float64 Infinity",
99 write: func(e *json.Encoder) {
100 e.WriteFloat(math.Inf(+1), 64)
101 },
102 wantOut: `"Infinity"`,
103 },
104 {
105 desc: "float64 -Infinity",
106 write: func(e *json.Encoder) {
107 e.WriteFloat(math.Inf(-1), 64)
108 },
109 wantOut: `"-Infinity"`,
110 },
111 {
112 desc: "float64 negative zero",
113 write: func(e *json.Encoder) {
114 e.WriteFloat(math.Copysign(0, -1), 64)
115 },
116 wantOut: `-0`,
117 },
118 {
119 desc: "float32",
120 write: func(e *json.Encoder) {
121 e.WriteFloat(1.02, 32)
122 },
123 wantOut: `1.02`,
124 },
125 {
126 desc: "float32 max value",
127 write: func(e *json.Encoder) {
128 e.WriteFloat(math.MaxFloat32, 32)
129 },
130 wantOut: `3.4028235e+38`,
131 },
132 {
133 desc: "float32 min value",
134 write: func(e *json.Encoder) {
135 e.WriteFloat(-math.MaxFloat32, 32)
136 },
137 wantOut: `-3.4028235e+38`,
138 },
139 {
140 desc: "float32 negative zero",
141 write: func(e *json.Encoder) {
142 e.WriteFloat(math.Copysign(0, -1), 32)
143 },
144 wantOut: `-0`,
145 },
146 {
147 desc: "int",
148 write: func(e *json.Encoder) {
149 e.WriteInt(-math.MaxInt64)
150 },
151 wantOut: `-9223372036854775807`,
152 },
153 {
154 desc: "uint",
155 write: func(e *json.Encoder) {
156 e.WriteUint(math.MaxUint64)
157 },
158 wantOut: `18446744073709551615`,
159 },
160 {
161 desc: "empty object",
162 write: func(e *json.Encoder) {
163 e.StartObject()
164 e.EndObject()
165 },
166 wantOut: `{}`,
167 },
168 {
169 desc: "empty array",
170 write: func(e *json.Encoder) {
171 e.StartArray()
172 e.EndArray()
173 },
174 wantOut: `[]`,
175 },
176 {
177 desc: "object with one member",
178 write: func(e *json.Encoder) {
179 e.StartObject()
180 e.WriteName("hello")
181 e.WriteString("world")
182 e.EndObject()
183 },
184 wantOut: `{"hello":"world"}`,
185 wantOutIndent: `{
186 "hello": "world"
187 }`,
188 },
189 {
190 desc: "array with one member",
191 write: func(e *json.Encoder) {
192 e.StartArray()
193 e.WriteNull()
194 e.EndArray()
195 },
196 wantOut: `[null]`,
197 wantOutIndent: `[
198 null
199 ]`,
200 },
201 {
202 desc: "simple object",
203 write: func(e *json.Encoder) {
204 e.StartObject()
205 {
206 e.WriteName("null")
207 e.WriteNull()
208 }
209 {
210 e.WriteName("bool")
211 e.WriteBool(true)
212 }
213 {
214 e.WriteName("string")
215 e.WriteString("hello")
216 }
217 {
218 e.WriteName("float")
219 e.WriteFloat(6.28318, 64)
220 }
221 {
222 e.WriteName("int")
223 e.WriteInt(42)
224 }
225 {
226 e.WriteName("uint")
227 e.WriteUint(47)
228 }
229 e.EndObject()
230 },
231 wantOut: `{"null":null,"bool":true,"string":"hello","float":6.28318,"int":42,"uint":47}`,
232 wantOutIndent: `{
233 "null": null,
234 "bool": true,
235 "string": "hello",
236 "float": 6.28318,
237 "int": 42,
238 "uint": 47
239 }`,
240 },
241 {
242 desc: "simple array",
243 write: func(e *json.Encoder) {
244 e.StartArray()
245 {
246 e.WriteString("hello")
247 e.WriteFloat(6.28318, 32)
248 e.WriteInt(42)
249 e.WriteUint(47)
250 e.WriteBool(true)
251 e.WriteNull()
252 }
253 e.EndArray()
254 },
255 wantOut: `["hello",6.28318,42,47,true,null]`,
256 wantOutIndent: `[
257 "hello",
258 6.28318,
259 42,
260 47,
261 true,
262 null
263 ]`,
264 },
265 {
266 desc: "fancy object",
267 write: func(e *json.Encoder) {
268 e.StartObject()
269 {
270 e.WriteName("object0")
271 e.StartObject()
272 e.EndObject()
273 }
274 {
275 e.WriteName("array0")
276 e.StartArray()
277 e.EndArray()
278 }
279 {
280 e.WriteName("object1")
281 e.StartObject()
282 {
283 e.WriteName("null")
284 e.WriteNull()
285 }
286 {
287 e.WriteName("object1-1")
288 e.StartObject()
289 {
290 e.WriteName("bool")
291 e.WriteBool(false)
292 }
293 {
294 e.WriteName("float")
295 e.WriteFloat(3.14159, 32)
296 }
297 e.EndObject()
298 }
299 e.EndObject()
300 }
301 {
302 e.WriteName("array1")
303 e.StartArray()
304 {
305 e.WriteNull()
306 e.StartObject()
307 e.EndObject()
308 e.StartObject()
309 {
310 e.WriteName("hello")
311 e.WriteString("world")
312 }
313 {
314 e.WriteName("hola")
315 e.WriteString("mundo")
316 }
317 e.EndObject()
318 e.StartArray()
319 {
320 e.WriteUint(1)
321 e.WriteUint(0)
322 e.WriteUint(1)
323 }
324 e.EndArray()
325 }
326 e.EndArray()
327 }
328 e.EndObject()
329 },
330 wantOutIndent: `{
331 "object0": {},
332 "array0": [],
333 "object1": {
334 "null": null,
335 "object1-1": {
336 "bool": false,
337 "float": 3.14159
338 }
339 },
340 "array1": [
341 null,
342 {},
343 {
344 "hello": "world",
345 "hola": "mundo"
346 },
347 [
348 1,
349 0,
350 1
351 ]
352 ]
353 }`,
354 }}
355
356 for _, tc := range tests {
357 t.Run(tc.desc, func(t *testing.T) {
358 if tc.wantOut != "" {
359 enc, err := json.NewEncoder(nil, "")
360 if err != nil {
361 t.Fatalf("NewEncoder() returned error: %v", err)
362 }
363 tc.write(enc)
364 got := string(enc.Bytes())
365 if got != tc.wantOut {
366 t.Errorf("%s:\n<got>:\n%v\n<want>\n%v\n", tc.desc, got, tc.wantOut)
367 }
368 }
369 if tc.wantOutIndent != "" {
370 enc, err := json.NewEncoder(nil, "\t")
371 if err != nil {
372 t.Fatalf("NewEncoder() returned error: %v", err)
373 }
374 tc.write(enc)
375 got, want := string(enc.Bytes()), tc.wantOutIndent
376 if got != want {
377 t.Errorf("%s(indent):\n<got>:\n%v\n<want>\n%v\n<diff -want +got>\n%v\n",
378 tc.desc, got, want, cmp.Diff(want, got, splitLines))
379 }
380 }
381 })
382 }
383 }
384
385 func TestWriteStringError(t *testing.T) {
386 tests := []string{"abc\xff"}
387
388 for _, in := range tests {
389 t.Run(in, func(t *testing.T) {
390 enc, err := json.NewEncoder(nil, "")
391 if err != nil {
392 t.Fatalf("NewEncoder() returned error: %v", err)
393 }
394 if err := enc.WriteString(in); err == nil {
395 t.Errorf("WriteString(%v): got nil error, want error", in)
396 }
397 })
398 }
399 }
400
View as plain text