1 package misc_tests
2
3 import (
4 "encoding/json"
5 "github.com/json-iterator/go"
6 "reflect"
7 "strings"
8 "testing"
9 )
10
11 type Level1 struct {
12 Hello []Level2
13 }
14
15 type Level2 struct {
16 World string
17 }
18
19 func Test_deep_nested(t *testing.T) {
20 type unstructured interface{}
21
22 testcases := []struct {
23 name string
24 data []byte
25 expectError string
26 }{
27 {
28 name: "array under maxDepth",
29 data: []byte(`{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`),
30 expectError: "",
31 },
32 {
33 name: "array over maxDepth",
34 data: []byte(`{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`),
35 expectError: "max depth",
36 },
37 {
38 name: "object under maxDepth",
39 data: []byte(`{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`),
40 expectError: "",
41 },
42 {
43 name: "object over maxDepth",
44 data: []byte(`{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`),
45 expectError: "max depth",
46 },
47 }
48
49 targets := []struct {
50 name string
51 new func() interface{}
52 }{
53 {
54 name: "unstructured",
55 new: func() interface{} {
56 var v interface{}
57 return &v
58 },
59 },
60 {
61 name: "typed named field",
62 new: func() interface{} {
63 v := struct {
64 A interface{} `json:"a"`
65 }{}
66 return &v
67 },
68 },
69 {
70 name: "typed missing field",
71 new: func() interface{} {
72 v := struct {
73 B interface{} `json:"b"`
74 }{}
75 return &v
76 },
77 },
78 {
79 name: "typed 1 field",
80 new: func() interface{} {
81 v := struct {
82 A interface{} `json:"a"`
83 }{}
84 return &v
85 },
86 },
87 {
88 name: "typed 2 field",
89 new: func() interface{} {
90 v := struct {
91 A interface{} `json:"a"`
92 B interface{} `json:"b"`
93 }{}
94 return &v
95 },
96 },
97 {
98 name: "typed 3 field",
99 new: func() interface{} {
100 v := struct {
101 A interface{} `json:"a"`
102 B interface{} `json:"b"`
103 C interface{} `json:"c"`
104 }{}
105 return &v
106 },
107 },
108 {
109 name: "typed 4 field",
110 new: func() interface{} {
111 v := struct {
112 A interface{} `json:"a"`
113 B interface{} `json:"b"`
114 C interface{} `json:"c"`
115 D interface{} `json:"d"`
116 }{}
117 return &v
118 },
119 },
120 {
121 name: "typed 5 field",
122 new: func() interface{} {
123 v := struct {
124 A interface{} `json:"a"`
125 B interface{} `json:"b"`
126 C interface{} `json:"c"`
127 D interface{} `json:"d"`
128 E interface{} `json:"e"`
129 }{}
130 return &v
131 },
132 },
133 {
134 name: "typed 6 field",
135 new: func() interface{} {
136 v := struct {
137 A interface{} `json:"a"`
138 B interface{} `json:"b"`
139 C interface{} `json:"c"`
140 D interface{} `json:"d"`
141 E interface{} `json:"e"`
142 F interface{} `json:"f"`
143 }{}
144 return &v
145 },
146 },
147 {
148 name: "typed 7 field",
149 new: func() interface{} {
150 v := struct {
151 A interface{} `json:"a"`
152 B interface{} `json:"b"`
153 C interface{} `json:"c"`
154 D interface{} `json:"d"`
155 E interface{} `json:"e"`
156 F interface{} `json:"f"`
157 G interface{} `json:"g"`
158 }{}
159 return &v
160 },
161 },
162 {
163 name: "typed 8 field",
164 new: func() interface{} {
165 v := struct {
166 A interface{} `json:"a"`
167 B interface{} `json:"b"`
168 C interface{} `json:"c"`
169 D interface{} `json:"d"`
170 E interface{} `json:"e"`
171 F interface{} `json:"f"`
172 G interface{} `json:"g"`
173 H interface{} `json:"h"`
174 }{}
175 return &v
176 },
177 },
178 {
179 name: "typed 9 field",
180 new: func() interface{} {
181 v := struct {
182 A interface{} `json:"a"`
183 B interface{} `json:"b"`
184 C interface{} `json:"c"`
185 D interface{} `json:"d"`
186 E interface{} `json:"e"`
187 F interface{} `json:"f"`
188 G interface{} `json:"g"`
189 H interface{} `json:"h"`
190 I interface{} `json:"i"`
191 }{}
192 return &v
193 },
194 },
195 {
196 name: "typed 10 field",
197 new: func() interface{} {
198 v := struct {
199 A interface{} `json:"a"`
200 B interface{} `json:"b"`
201 C interface{} `json:"c"`
202 D interface{} `json:"d"`
203 E interface{} `json:"e"`
204 F interface{} `json:"f"`
205 G interface{} `json:"g"`
206 H interface{} `json:"h"`
207 I interface{} `json:"i"`
208 J interface{} `json:"j"`
209 }{}
210 return &v
211 },
212 },
213 {
214 name: "typed 11 field",
215 new: func() interface{} {
216 v := struct {
217 A interface{} `json:"a"`
218 B interface{} `json:"b"`
219 C interface{} `json:"c"`
220 D interface{} `json:"d"`
221 E interface{} `json:"e"`
222 F interface{} `json:"f"`
223 G interface{} `json:"g"`
224 H interface{} `json:"h"`
225 I interface{} `json:"i"`
226 J interface{} `json:"j"`
227 K interface{} `json:"k"`
228 }{}
229 return &v
230 },
231 },
232 }
233
234 for _, tc := range testcases {
235 t.Run(tc.name, func(t *testing.T) {
236 for _, target := range targets {
237 t.Run(target.name, func(t *testing.T) {
238 err := jsoniter.Unmarshal(tc.data, target.new())
239 if len(tc.expectError) == 0 {
240 if err != nil {
241 t.Errorf("unexpected error: %v", err)
242 }
243 } else {
244 if err == nil {
245 t.Errorf("expected error, got none")
246 } else if !strings.Contains(err.Error(), tc.expectError) {
247 t.Errorf("expected error containing '%s', got: %v", tc.expectError, err)
248 }
249 }
250 })
251 }
252 })
253 }
254 }
255
256 func Test_nested(t *testing.T) {
257 iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
258 l1 := Level1{}
259 for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
260 switch l1Field {
261 case "hello":
262 l2Array := []Level2{}
263 for iter.ReadArray() {
264 l2 := Level2{}
265 for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
266 switch l2Field {
267 case "world":
268 l2.World = iter.ReadString()
269 default:
270 iter.ReportError("bind l2", "unexpected field: "+l2Field)
271 }
272 }
273 l2Array = append(l2Array, l2)
274 }
275 l1.Hello = l2Array
276 default:
277 iter.ReportError("bind l1", "unexpected field: "+l1Field)
278 }
279 }
280 if !reflect.DeepEqual(l1, Level1{
281 Hello: []Level2{
282 {World: "value1"},
283 {World: "value2"},
284 },
285 }) {
286 t.Fatal(l1)
287 }
288 }
289
290 func Benchmark_jsoniter_nested(b *testing.B) {
291 for n := 0; n < b.N; n++ {
292 iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
293 l1 := Level1{}
294 for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
295 switch l1Field {
296 case "hello":
297 l1.Hello = readLevel1Hello(iter)
298 default:
299 iter.Skip()
300 }
301 }
302 }
303 }
304
305 func readLevel1Hello(iter *jsoniter.Iterator) []Level2 {
306 l2Array := make([]Level2, 0, 2)
307 for iter.ReadArray() {
308 l2 := Level2{}
309 for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
310 switch l2Field {
311 case "world":
312 l2.World = iter.ReadString()
313 default:
314 iter.Skip()
315 }
316 }
317 l2Array = append(l2Array, l2)
318 }
319 return l2Array
320 }
321
322 func Benchmark_json_nested(b *testing.B) {
323 for n := 0; n < b.N; n++ {
324 l1 := Level1{}
325 json.Unmarshal([]byte(`{"hello": [{"world": "value1"}, {"world": "value2"}]}`), &l1)
326 }
327 }
328
View as plain text