...

Source file src/github.com/json-iterator/go/misc_tests/jsoniter_nested_test.go

Documentation: github.com/json-iterator/go/misc_tests

     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