decode_test.gno
17.85 Kb ยท 554 lines
1package json
2
3import (
4 "bytes"
5 "testing"
6)
7
8type testNode struct {
9 name string
10 input []byte
11 value []byte
12 _type ValueType
13}
14
15func simpleValid(test *testNode, t *testing.T) {
16 root, err := Unmarshal(test.input)
17 if err != nil {
18 t.Errorf("Error on Unmarshal(%s): %s", test.input, err.Error())
19 } else if root == nil {
20 t.Errorf("Error on Unmarshal(%s): root is nil", test.name)
21 } else if root.nodeType != test._type {
22 t.Errorf("Error on Unmarshal(%s): wrong type", test.name)
23 } else if !bytes.Equal(root.source(), test.value) {
24 t.Errorf("Error on Unmarshal(%s): %s != %s", test.name, root.source(), test.value)
25 }
26}
27
28func simpleInvalid(test *testNode, t *testing.T) {
29 root, err := Unmarshal(test.input)
30 if err == nil {
31 t.Errorf("Error on Unmarshal(%s): error expected, got '%s'", test.name, root.source())
32 } else if root != nil {
33 t.Errorf("Error on Unmarshal(%s): root is not nil", test.name)
34 }
35}
36
37func simpleCorrupted(name string) *testNode {
38 return &testNode{name: name, input: []byte(name)}
39}
40
41func TestUnmarshal_StringSimpleSuccess(t *testing.T) {
42 tests := []*testNode{
43 {name: "blank", input: []byte("\"\""), _type: String, value: []byte("\"\"")},
44 {name: "char", input: []byte("\"c\""), _type: String, value: []byte("\"c\"")},
45 {name: "word", input: []byte("\"cat\""), _type: String, value: []byte("\"cat\"")},
46 {name: "spaces", input: []byte(" \"good cat or dog\"\r\n "), _type: String, value: []byte("\"good cat or dog\"")},
47 {name: "backslash", input: []byte("\"good \\\"cat\\\"\""), _type: String, value: []byte("\"good \\\"cat\\\"\"")},
48 {name: "backslash 2", input: []byte("\"good \\\\\\\"cat\\\"\""), _type: String, value: []byte("\"good \\\\\\\"cat\\\"\"")},
49 }
50 for _, test := range tests {
51 t.Run(test.name, func(t *testing.T) {
52 simpleValid(test, t)
53 })
54 }
55}
56
57func TestUnmarshal_NumericSimpleSuccess(t *testing.T) {
58 tests := []*testNode{
59 {name: "1", input: []byte("1"), _type: Number, value: []byte("1")},
60 {name: "-1", input: []byte("-1"), _type: Number, value: []byte("-1")},
61
62 {name: "1234567890", input: []byte("1234567890"), _type: Number, value: []byte("1234567890")},
63 {name: "-123", input: []byte("-123"), _type: Number, value: []byte("-123")},
64
65 {name: "123.456", input: []byte("123.456"), _type: Number, value: []byte("123.456")},
66 {name: "-123.456", input: []byte("-123.456"), _type: Number, value: []byte("-123.456")},
67
68 {name: "1e3", input: []byte("1e3"), _type: Number, value: []byte("1e3")},
69 {name: "1e+3", input: []byte("1e+3"), _type: Number, value: []byte("1e+3")},
70 {name: "1e-3", input: []byte("1e-3"), _type: Number, value: []byte("1e-3")},
71 {name: "-1e3", input: []byte("-1e3"), _type: Number, value: []byte("-1e3")},
72 {name: "-1e-3", input: []byte("-1e-3"), _type: Number, value: []byte("-1e-3")},
73
74 {name: "1.123e3456", input: []byte("1.123e3456"), _type: Number, value: []byte("1.123e3456")},
75 {name: "1.123e-3456", input: []byte("1.123e-3456"), _type: Number, value: []byte("1.123e-3456")},
76 {name: "-1.123e3456", input: []byte("-1.123e3456"), _type: Number, value: []byte("-1.123e3456")},
77 {name: "-1.123e-3456", input: []byte("-1.123e-3456"), _type: Number, value: []byte("-1.123e-3456")},
78
79 {name: "1E3", input: []byte("1E3"), _type: Number, value: []byte("1E3")},
80 {name: "1E-3", input: []byte("1E-3"), _type: Number, value: []byte("1E-3")},
81 {name: "-1E3", input: []byte("-1E3"), _type: Number, value: []byte("-1E3")},
82 {name: "-1E-3", input: []byte("-1E-3"), _type: Number, value: []byte("-1E-3")},
83
84 {name: "1.123E3456", input: []byte("1.123E3456"), _type: Number, value: []byte("1.123E3456")},
85 {name: "1.123E-3456", input: []byte("1.123E-3456"), _type: Number, value: []byte("1.123E-3456")},
86 {name: "-1.123E3456", input: []byte("-1.123E3456"), _type: Number, value: []byte("-1.123E3456")},
87 {name: "-1.123E-3456", input: []byte("-1.123E-3456"), _type: Number, value: []byte("-1.123E-3456")},
88
89 {name: "-1.123E-3456 with spaces", input: []byte(" \r -1.123E-3456 \t\n"), _type: Number, value: []byte("-1.123E-3456")},
90 }
91 for _, test := range tests {
92 t.Run(test.name, func(t *testing.T) {
93 root, err := Unmarshal(test.input)
94 if err != nil {
95 t.Errorf("Error on Unmarshal(%s): %s", test.name, err.Error())
96 } else if root == nil {
97 t.Errorf("Error on Unmarshal(%s): root is nil", test.name)
98 } else if root.nodeType != test._type {
99 t.Errorf("Error on Unmarshal(%s): wrong type", test.name)
100 } else if !bytes.Equal(root.source(), test.value) {
101 t.Errorf("Error on Unmarshal(%s): %s != %s", test.name, root.source(), test.value)
102 }
103 })
104 }
105}
106
107func TestUnmarshal_StringSimpleCorrupted(t *testing.T) {
108 tests := []*testNode{
109 {name: "white NL", input: []byte("\"foo\nbar\"")},
110 {name: "white R", input: []byte("\"foo\rbar\"")},
111 {name: "white Tab", input: []byte("\"foo\tbar\"")},
112 {name: "wrong quotes", input: []byte("'cat'")},
113 {name: "double string", input: []byte("\"Hello\" \"World\"")},
114 {name: "quotes in quotes", input: []byte("\"good \"cat\"\"")},
115 }
116 for _, test := range tests {
117 t.Run(test.name, func(t *testing.T) {
118 simpleInvalid(test, t)
119 })
120 }
121}
122
123func TestUnmarshal_ObjectSimpleSuccess(t *testing.T) {
124 tests := []*testNode{
125 {name: "{}", input: []byte("{}"), _type: Object, value: []byte("{}")},
126 {name: `{ \r\n }`, input: []byte("{ \r\n }"), _type: Object, value: []byte("{ \r\n }")},
127 {name: `{"key":1}`, input: []byte(`{"key":1}`), _type: Object, value: []byte(`{"key":1}`)},
128 {name: `{"key":true}`, input: []byte(`{"key":true}`), _type: Object, value: []byte(`{"key":true}`)},
129 {name: `{"key":"value"}`, input: []byte(`{"key":"value"}`), _type: Object, value: []byte(`{"key":"value"}`)},
130 {name: `{"foo":"bar","baz":"foo"}`, input: []byte(`{"foo":"bar", "baz":"foo"}`), _type: Object, value: []byte(`{"foo":"bar", "baz":"foo"}`)},
131 {name: "spaces", input: []byte(` { "foo" : "bar" , "baz" : "foo" } `), _type: Object, value: []byte(`{ "foo" : "bar" , "baz" : "foo" }`)},
132 {name: "nested", input: []byte(`{"foo":{"bar":{"baz":{}}}}`), _type: Object, value: []byte(`{"foo":{"bar":{"baz":{}}}}`)},
133 {name: "array", input: []byte(`{"array":[{},{},{"foo":[{"bar":["baz"]}]}]}`), _type: Object, value: []byte(`{"array":[{},{},{"foo":[{"bar":["baz"]}]}]}`)},
134 }
135
136 for _, test := range tests {
137 t.Run(test.name, func(t *testing.T) {
138 simpleValid(test, t)
139 })
140 }
141}
142
143func TestUnmarshal_ObjectSimpleCorrupted(t *testing.T) {
144 tests := []*testNode{
145 simpleCorrupted("{{{\"key\": \"foo\"{{{{"),
146 simpleCorrupted("}"),
147 simpleCorrupted("{ }}}}}}}"),
148 simpleCorrupted(" }"),
149 simpleCorrupted("{,}"),
150 simpleCorrupted("{:}"),
151 simpleCorrupted("{100000}"),
152 simpleCorrupted("{1:1}"),
153 simpleCorrupted("{'1:2,3:4'}"),
154 simpleCorrupted(`{"d"}`),
155 simpleCorrupted(`{"foo"}`),
156 simpleCorrupted(`{"foo":}`),
157 simpleCorrupted(`{:"foo"}`),
158 simpleCorrupted(`{"foo":bar}`),
159 simpleCorrupted(`{"foo":"bar",}`),
160 simpleCorrupted(`{}{}`),
161 simpleCorrupted(`{},{}`),
162 simpleCorrupted(`{[},{]}`),
163 simpleCorrupted(`{[,]}`),
164 simpleCorrupted(`{[]}`),
165 simpleCorrupted(`{}1`),
166 simpleCorrupted(`1{}`),
167 simpleCorrupted(`{"x"::1}`),
168 simpleCorrupted(`{null:null}`),
169 simpleCorrupted(`{"foo:"bar"}`),
170 }
171
172 for _, test := range tests {
173 t.Run(test.name, func(t *testing.T) {
174 simpleInvalid(test, t)
175 })
176 }
177}
178
179func TestUnmarshal_NullSimpleCorrupted(t *testing.T) {
180 tests := []*testNode{
181 {name: "nul", input: []byte("nul")},
182 {name: "nil", input: []byte("nil")},
183 {name: "nill", input: []byte("nill")},
184 {name: "NILL", input: []byte("NILL")},
185 {name: "Null", input: []byte("Null")},
186 {name: "NULL", input: []byte("NULL")},
187 {name: "spaces", input: []byte("Nu ll")},
188 {name: "null1", input: []byte("null1")},
189 {name: "double", input: []byte("null null")},
190 }
191
192 for _, test := range tests {
193 t.Run(test.name, func(t *testing.T) {
194 simpleInvalid(test, t)
195 })
196 }
197}
198
199func TestUnmarshal_BoolSimpleSuccess(t *testing.T) {
200 tests := []*testNode{
201 {name: "lower true", input: []byte("true"), _type: Boolean, value: []byte("true")},
202 {name: "lower false", input: []byte("false"), _type: Boolean, value: []byte("false")},
203 {name: "spaces true", input: []byte(" true\r\n "), _type: Boolean, value: []byte("true")},
204 {name: "spaces false", input: []byte(" false\r\n "), _type: Boolean, value: []byte("false")},
205 }
206
207 for _, test := range tests {
208 t.Run(test.name, func(t *testing.T) {
209 simpleValid(test, t)
210 })
211 }
212}
213
214func TestUnmarshal_BoolSimpleCorrupted(t *testing.T) {
215 tests := []*testNode{
216 simpleCorrupted("tru"),
217 simpleCorrupted("fals"),
218 simpleCorrupted("tre"),
219 simpleCorrupted("fal se"),
220 simpleCorrupted("true false"),
221 simpleCorrupted("True"),
222 simpleCorrupted("TRUE"),
223 simpleCorrupted("False"),
224 simpleCorrupted("FALSE"),
225 }
226
227 for _, test := range tests {
228 t.Run(test.name, func(t *testing.T) {
229 simpleInvalid(test, t)
230 })
231 }
232}
233
234func TestUnmarshal_ArraySimpleSuccess(t *testing.T) {
235 tests := []*testNode{
236 {name: "[]", input: []byte("[]"), _type: Array, value: []byte("[]")},
237 {name: "[1]", input: []byte("[1]"), _type: Array, value: []byte("[1]")},
238 {name: "[1,2,3]", input: []byte("[1,2,3]"), _type: Array, value: []byte("[1,2,3]")},
239 {name: "[1, 2, 3]", input: []byte("[1, 2, 3]"), _type: Array, value: []byte("[1, 2, 3]")},
240 {name: "[1,[2],3]", input: []byte("[1,[2],3]"), _type: Array, value: []byte("[1,[2],3]")},
241 {name: "[[],[],[]]", input: []byte("[[],[],[]]"), _type: Array, value: []byte("[[],[],[]]")},
242 {name: "[[[[[]]]]]", input: []byte("[[[[[]]]]]"), _type: Array, value: []byte("[[[[[]]]]]")},
243 {name: "[true,null,1,\"foo\",[]]", input: []byte("[true,null,1,\"foo\",[]]"), _type: Array, value: []byte("[true,null,1,\"foo\",[]]")},
244 {name: "spaces", input: []byte("\n\r [\n1\n ]\r\n"), _type: Array, value: []byte("[\n1\n ]")},
245 }
246
247 for _, test := range tests {
248 t.Run(test.name, func(t *testing.T) {
249 simpleValid(test, t)
250 })
251 }
252}
253
254func TestUnmarshal_ArraySimpleCorrupted(t *testing.T) {
255 tests := []*testNode{
256 simpleCorrupted("[,]"),
257 simpleCorrupted("[]\\"),
258 simpleCorrupted("[1,]"),
259 simpleCorrupted("[[]"),
260 simpleCorrupted("[]]"),
261 simpleCorrupted("1[]"),
262 simpleCorrupted("[]1"),
263 simpleCorrupted("[[]1]"),
264 }
265
266 for _, test := range tests {
267 t.Run(test.name, func(t *testing.T) {
268 simpleInvalid(test, t)
269 })
270 }
271}
272
273// Examples from https://json.org/example.html
274func TestUnmarshal(t *testing.T) {
275 tests := []struct {
276 name string
277 value string
278 }{
279 {
280 name: "glossary",
281 value: `{
282 "glossary": {
283 "title": "example glossary",
284 "GlossDiv": {
285 "title": "S",
286 "GlossList": {
287 "GlossEntry": {
288 "ID": "SGML",
289 "SortAs": "SGML",
290 "GlossTerm": "Standard Generalized Markup Language",
291 "Acronym": "SGML",
292 "Abbrev": "ISO 8879:1986",
293 "GlossDef": {
294 "para": "A meta-markup language, used to create markup languages such as DocBook.",
295 "GlossSeeAlso": ["GML", "XML"]
296 },
297 "GlossSee": "markup"
298 }
299 }
300 }
301 }
302 }`,
303 },
304 {
305 name: "menu",
306 value: `{"menu": {
307 "id": "file",
308 "value": "File",
309 "popup": {
310 "menuitem": [
311 {"value": "New", "onclick": "CreateNewDoc()"},
312 {"value": "Open", "onclick": "OpenDoc()"},
313 {"value": "Close", "onclick": "CloseDoc()"}
314 ]
315 }
316 }}`,
317 },
318 {
319 name: "widget",
320 value: `{"widget": {
321 "debug": "on",
322 "window": {
323 "title": "Sample Konfabulator Widget",
324 "name": "main_window",
325 "width": 500,
326 "height": 500
327 },
328 "image": {
329 "src": "Images/Sun.png",
330 "name": "sun1",
331 "hOffset": 250,
332 "vOffset": 250,
333 "alignment": "center"
334 },
335 "text": {
336 "data": "Click Here",
337 "size": 36,
338 "style": "bold",
339 "name": "text1",
340 "hOffset": 250,
341 "vOffset": 100,
342 "alignment": "center",
343 "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
344 }
345 }} `,
346 },
347 {
348 name: "web-app",
349 value: `{"web-app": {
350 "servlet": [
351 {
352 "servlet-name": "cofaxCDS",
353 "servlet-class": "org.cofax.cds.CDSServlet",
354 "init-param": {
355 "configGlossary:installationAt": "Philadelphia, PA",
356 "configGlossary:adminEmail": "ksm@pobox.com",
357 "configGlossary:poweredBy": "Cofax",
358 "configGlossary:poweredByIcon": "/images/cofax.gif",
359 "configGlossary:staticPath": "/content/static",
360 "templateProcessorClass": "org.cofax.WysiwygTemplate",
361 "templateLoaderClass": "org.cofax.FilesTemplateLoader",
362 "templatePath": "templates",
363 "templateOverridePath": "",
364 "defaultListTemplate": "listTemplate.htm",
365 "defaultFileTemplate": "articleTemplate.htm",
366 "useJSP": false,
367 "jspListTemplate": "listTemplate.jsp",
368 "jspFileTemplate": "articleTemplate.jsp",
369 "cachePackageTagsTrack": 200,
370 "cachePackageTagsStore": 200,
371 "cachePackageTagsRefresh": 60,
372 "cacheTemplatesTrack": 100,
373 "cacheTemplatesStore": 50,
374 "cacheTemplatesRefresh": 15,
375 "cachePagesTrack": 200,
376 "cachePagesStore": 100,
377 "cachePagesRefresh": 10,
378 "cachePagesDirtyRead": 10,
379 "searchEngineListTemplate": "forSearchEnginesList.htm",
380 "searchEngineFileTemplate": "forSearchEngines.htm",
381 "searchEngineRobotsDb": "WEB-INF/robots.db",
382 "useDataStore": true,
383 "dataStoreClass": "org.cofax.SqlDataStore",
384 "redirectionClass": "org.cofax.SqlRedirection",
385 "dataStoreName": "cofax",
386 "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
387 "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
388 "dataStoreUser": "sa",
389 "dataStorePassword": "dataStoreTestQuery",
390 "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
391 "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
392 "dataStoreInitConns": 10,
393 "dataStoreMaxConns": 100,
394 "dataStoreConnUsageLimit": 100,
395 "dataStoreLogLevel": "debug",
396 "maxUrlLength": 500}},
397 {
398 "servlet-name": "cofaxEmail",
399 "servlet-class": "org.cofax.cds.EmailServlet",
400 "init-param": {
401 "mailHost": "mail1",
402 "mailHostOverride": "mail2"}},
403 {
404 "servlet-name": "cofaxAdmin",
405 "servlet-class": "org.cofax.cds.AdminServlet"},
406
407 {
408 "servlet-name": "fileServlet",
409 "servlet-class": "org.cofax.cds.FileServlet"},
410 {
411 "servlet-name": "cofaxTools",
412 "servlet-class": "org.cofax.cms.CofaxToolsServlet",
413 "init-param": {
414 "templatePath": "toolstemplates/",
415 "log": 1,
416 "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
417 "logMaxSize": "",
418 "dataLog": 1,
419 "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
420 "dataLogMaxSize": "",
421 "removePageCache": "/content/admin/remove?cache=pages&id=",
422 "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
423 "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
424 "lookInContext": 1,
425 "adminGroupID": 4,
426 "betaServer": true}}],
427 "servlet-mapping": {
428 "cofaxCDS": "/",
429 "cofaxEmail": "/cofaxutil/aemail/*",
430 "cofaxAdmin": "/admin/*",
431 "fileServlet": "/static/*",
432 "cofaxTools": "/tools/*"},
433
434 "taglib": {
435 "taglib-uri": "cofax.tld",
436 "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}`,
437 },
438 {
439 name: "SVG Viewer",
440 value: `{"menu": {
441 "header": "SVG Viewer",
442 "items": [
443 {"id": "Open"},
444 {"id": "OpenNew", "label": "Open New"},
445 null,
446 {"id": "ZoomIn", "label": "Zoom In"},
447 {"id": "ZoomOut", "label": "Zoom Out"},
448 {"id": "OriginalView", "label": "Original View"},
449 null,
450 {"id": "Quality"},
451 {"id": "Pause"},
452 {"id": "Mute"},
453 null,
454 {"id": "Find", "label": "Find..."},
455 {"id": "FindAgain", "label": "Find Again"},
456 {"id": "Copy"},
457 {"id": "CopyAgain", "label": "Copy Again"},
458 {"id": "CopySVG", "label": "Copy SVG"},
459 {"id": "ViewSVG", "label": "View SVG"},
460 {"id": "ViewSource", "label": "View Source"},
461 {"id": "SaveAs", "label": "Save As"},
462 null,
463 {"id": "Help"},
464 {"id": "About", "label": "About Adobe CVG Viewer..."}
465 ]
466 }}`,
467 },
468 }
469 for _, test := range tests {
470 t.Run(test.name, func(t *testing.T) {
471 _, err := Unmarshal([]byte(test.value))
472 if err != nil {
473 t.Errorf("Error on Unmarshal: %s", err.Error())
474 }
475 })
476 }
477}
478
479func TestUnmarshalSafe(t *testing.T) {
480 json := []byte(`{ "store": {
481 "book": [
482 { "category": "reference",
483 "author": "Nigel Rees",
484 "title": "Sayings of the Century",
485 "price": 8.95
486 },
487 { "category": "fiction",
488 "author": "Evelyn Waugh",
489 "title": "Sword of Honour",
490 "price": 12.99
491 },
492 { "category": "fiction",
493 "author": "Herman Melville",
494 "title": "Moby Dick",
495 "isbn": "0-553-21311-3",
496 "price": 8.99
497 },
498 { "category": "fiction",
499 "author": "J. R. R. Tolkien",
500 "title": "The Lord of the Rings",
501 "isbn": "0-395-19395-8",
502 "price": 22.99
503 }
504 ],
505 "bicycle": {
506 "color": "red",
507 "price": 19.95
508 }
509 }
510 }`)
511 safe, err := UnmarshalSafe(json)
512 if err != nil {
513 t.Errorf("Error on Unmarshal: %s", err.Error())
514 } else if safe == nil {
515 t.Errorf("Error on Unmarshal: safe is nil")
516 } else {
517 root, err := Unmarshal(json)
518 if err != nil {
519 t.Errorf("Error on Unmarshal: %s", err.Error())
520 } else if root == nil {
521 t.Errorf("Error on Unmarshal: root is nil")
522 } else if !bytes.Equal(root.source(), safe.source()) {
523 t.Errorf("Error on UnmarshalSafe: values not same")
524 }
525 }
526}
527
528// BenchmarkGoStdUnmarshal-8 61698 19350 ns/op 288 B/op 6 allocs/op
529// BenchmarkUnmarshal-8 45620 26165 ns/op 21889 B/op 367 allocs/op
530//
531// type bench struct {
532// Name string `json:"name"`
533// Value int `json:"value"`
534// }
535
536// func BenchmarkGoStdUnmarshal(b *testing.B) {
537// data := []byte(webApp)
538// for i := 0; i < b.N; i++ {
539// err := json.Unmarshal(data, &bench{})
540// if err != nil {
541// b.Fatal(err)
542// }
543// }
544// }
545
546// func BenchmarkUnmarshal(b *testing.B) {
547// data := []byte(webApp)
548// for i := 0; i < b.N; i++ {
549// _, err := Unmarshal(data)
550// if err != nil {
551// b.Fatal(err)
552// }
553// }
554// }