1package misc_tests 2 3import ( 4 "encoding/json" 5 "github.com/json-iterator/go" 6 "reflect" 7 "strings" 8 "testing" 9) 10 11type Level1 struct { 12 Hello []Level2 13} 14 15type Level2 struct { 16 World string 17} 18 19func 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 256func 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 290func 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 305func 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 322func 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