github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_decoder_native_struct_test.go (about)

     1  package jzon
     2  
     3  import (
     4  	"io"
     5  	"runtime/debug"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestValDecoder_Native_Struct_Zero_Field(t *testing.T) {
    12  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
    13  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
    14  	}
    15  	t.Run("nil receiver", func(t *testing.T) {
    16  		f(t, "null", ErrNilPointerReceiver, nil, nil)
    17  	})
    18  	t.Run("eof", func(t *testing.T) {
    19  		f(t, "", io.EOF, &struct{}{}, &struct{}{})
    20  	})
    21  	t.Run("null", func(t *testing.T) {
    22  		f(t, "null", nil, &struct{}{}, &struct{}{})
    23  	})
    24  	t.Run("invalid first byte", func(t *testing.T) {
    25  		f(t, "+", UnexpectedByteError{}, &struct{}{}, &struct{}{})
    26  	})
    27  	debug.FreeOSMemory()
    28  }
    29  
    30  func TestValDecoder_Native_Struct_Mapping(t *testing.T) {
    31  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
    32  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
    33  	}
    34  	t.Run("unexported field", func(t *testing.T) {
    35  		f(t, ` { "a" : "abc" } `, nil, &struct {
    36  			a string
    37  		}{}, &struct {
    38  			a string
    39  		}{})
    40  	})
    41  	t.Run("unexported field 2", func(t *testing.T) {
    42  		f(t, ` { "a" : "abc" } `, nil, &struct {
    43  			a string
    44  			B int
    45  		}{}, &struct {
    46  			a string
    47  			B int
    48  		}{})
    49  	})
    50  	t.Run("tag ignored 1", func(t *testing.T) {
    51  		f(t, ` { "A" : "abc" } `, nil, &struct {
    52  			A string `json:"-"`
    53  		}{A: "test"}, &struct {
    54  			A string `json:"-"`
    55  		}{A: "test"})
    56  	})
    57  	t.Run("tag", func(t *testing.T) {
    58  		f(t, ` { "b" : "abc" } `, nil, &struct {
    59  			A string `json:"B"`
    60  		}{A: "test"}, &struct {
    61  			A string `json:"B"`
    62  		}{A: "test"})
    63  	})
    64  	t.Run("case insensitive", func(t *testing.T) {
    65  		f(t, ` { "a" : "abc" } `, nil, &struct {
    66  			A string
    67  		}{A: "test"}, &struct {
    68  			A string
    69  		}{A: "test"})
    70  	})
    71  	t.Run("case insensitive 2", func(t *testing.T) {
    72  		f(t, ` { "A" : "abc" } `, nil, &struct {
    73  			A string `json:"a"`
    74  		}{A: "test"}, &struct {
    75  			A string `json:"a"`
    76  		}{A: "test"})
    77  	})
    78  	t.Run("multiple same key", func(t *testing.T) {
    79  		f(t, ` { "a" : "abc" , "a" : "def" } `, nil, &struct {
    80  			A string `json:"a"`
    81  		}{A: "test"}, &struct {
    82  			A string `json:"a"`
    83  		}{A: "test"})
    84  	})
    85  	debug.FreeOSMemory()
    86  }
    87  
    88  func TestValDecoder_Native_Struct(t *testing.T) {
    89  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
    90  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
    91  	}
    92  	t.Run("nil receiver", func(t *testing.T) {
    93  		f(t, "null", ErrNilPointerReceiver, nil, nil)
    94  	})
    95  	t.Run("eof", func(t *testing.T) {
    96  		f(t, "", io.EOF, &struct {
    97  			A string
    98  		}{A: "test"}, &struct {
    99  			A string
   100  		}{A: "test"})
   101  	})
   102  	t.Run("invalid first byte", func(t *testing.T) {
   103  		f(t, "+", UnexpectedByteError{}, &struct {
   104  			A string
   105  		}{A: "test"}, &struct {
   106  			A string
   107  		}{A: "test"})
   108  	})
   109  	t.Run("invalid null", func(t *testing.T) {
   110  		f(t, "nul", io.EOF, &struct {
   111  			A string
   112  		}{A: "test"}, &struct {
   113  			A string
   114  		}{A: "test"})
   115  	})
   116  	t.Run("null", func(t *testing.T) {
   117  		f(t, "null", nil, &struct {
   118  			A string
   119  		}{A: "test"}, &struct {
   120  			A string
   121  		}{A: "test"})
   122  	})
   123  	t.Run("eof after bracket", func(t *testing.T) {
   124  		f(t, "{", io.EOF, &struct {
   125  			A string
   126  		}{A: "test"}, &struct {
   127  			A string
   128  		}{A: "test"})
   129  	})
   130  	t.Run("empty object", func(t *testing.T) {
   131  		f(t, " { } ", nil, &struct {
   132  			A string
   133  		}{A: "test"}, &struct {
   134  			A string
   135  		}{A: "test"})
   136  	})
   137  	t.Run("invalid char after bracket", func(t *testing.T) {
   138  		f(t, " { { ", UnexpectedByteError{}, &struct {
   139  			A string
   140  		}{A: "test"}, &struct {
   141  			A string
   142  		}{A: "test"})
   143  	})
   144  	t.Run("invalid field", func(t *testing.T) {
   145  		f(t, ` { " `, io.EOF, &struct {
   146  			A string
   147  		}{A: "test"}, &struct {
   148  			A string
   149  		}{A: "test"})
   150  	})
   151  	t.Run("invalid field type", func(t *testing.T) {
   152  		f(t, ` { "A" : 1 } `, UnexpectedByteError{}, &struct {
   153  			A string
   154  		}{A: "test"}, &struct {
   155  			A string
   156  		}{A: "test"})
   157  	})
   158  	t.Run("field skip error", func(t *testing.T) {
   159  		f(t, ` { "b" : } `, UnexpectedByteError{}, &struct {
   160  			A string
   161  		}{A: "test"}, &struct {
   162  			A string
   163  		}{A: "test"})
   164  	})
   165  	t.Run("more field eof", func(t *testing.T) {
   166  		f(t, ` { "b" : 1 `, io.EOF, &struct {
   167  			A string
   168  		}{A: "test"}, &struct {
   169  			A string
   170  		}{A: "test"})
   171  	})
   172  	t.Run("non empty", func(t *testing.T) {
   173  		f(t, ` { "a" : "abc" } `, nil, &struct {
   174  			A string
   175  		}{A: "test"}, &struct {
   176  			A string
   177  		}{A: "test"})
   178  	})
   179  	t.Run("more field eof after comma", func(t *testing.T) {
   180  		f(t, ` { "b" : 1 , `, io.EOF, &struct {
   181  			A string
   182  		}{A: "test"}, &struct {
   183  			A string
   184  		}{A: "test"})
   185  	})
   186  	t.Run("more field invalid byte after comma", func(t *testing.T) {
   187  		f(t, ` { "b" : 1 , } `, UnexpectedByteError{}, &struct {
   188  			A string
   189  		}{A: "test"}, &struct {
   190  			A string
   191  		}{A: "test"})
   192  	})
   193  	t.Run("more field invalid comma", func(t *testing.T) {
   194  		f(t, ` { "b" : 1 { `, UnexpectedByteError{}, &struct {
   195  			A string
   196  		}{A: "test"}, &struct {
   197  			A string
   198  		}{A: "test"})
   199  	})
   200  	t.Run("two fields", func(t *testing.T) {
   201  		f(t, ` { "b" : 1 , "a" : "abc" } `, nil, &struct {
   202  			A string
   203  		}{A: "test"}, &struct {
   204  			A string
   205  		}{A: "test"})
   206  	})
   207  	debug.FreeOSMemory()
   208  }
   209  
   210  type testStruct struct {
   211  	A *testStruct `json:"a"`
   212  	C *int        `json:"c"`
   213  	B *testStruct `json:"b"`
   214  }
   215  
   216  func TestValDecoder_Native_Struct_Nested(t *testing.T) {
   217  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
   218  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
   219  	}
   220  	t.Run("nested", func(t *testing.T) {
   221  		f(t, `{"a":null,"c":1,"b":{}}`, nil, &testStruct{
   222  			A: &testStruct{},
   223  		}, &testStruct{
   224  			A: &testStruct{},
   225  		})
   226  	})
   227  	debug.FreeOSMemory()
   228  }
   229  
   230  func TestValDecoder_Native_Struct_CustomTag(t *testing.T) {
   231  	decCfg := NewDecoderConfig(&DecoderOption{
   232  		Tag: "jzon",
   233  	})
   234  	var p struct {
   235  		A string `jzon:"b"`
   236  	}
   237  	err := decCfg.Unmarshal([]byte(` { "b" : "c" }`), &p)
   238  	require.NoError(t, err)
   239  	require.Equal(t, "c", p.A)
   240  }
   241  
   242  func TestValDecoder_Native_Struct_Embedded_Unexported(t *testing.T) {
   243  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
   244  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
   245  	}
   246  	t.Run("not embedded", func(t *testing.T) {
   247  		type inner struct{}
   248  		type outer struct {
   249  			inner inner
   250  		}
   251  		f(t, `{"inner":{}}`, nil, &outer{}, &outer{})
   252  	})
   253  	t.Run("non struct", func(t *testing.T) {
   254  		type inner int
   255  		type outer struct {
   256  			inner
   257  		}
   258  		f(t, `{"inner":1}`, nil, &outer{}, &outer{})
   259  	})
   260  	t.Run("nil pointer receiver", func(t *testing.T) {
   261  		t.Run("duplicate field", func(t *testing.T) {
   262  			type inner struct {
   263  				A int `json:"a"`
   264  			}
   265  			type inner2 inner
   266  			type outer struct {
   267  				*inner
   268  				*inner2
   269  			}
   270  			f(t, `{"a":1}`, nil, &outer{}, &outer{})
   271  		})
   272  		t.Run("field not matched", func(t *testing.T) {
   273  			type inner struct {
   274  				B int
   275  			}
   276  			type outer struct {
   277  				*inner
   278  			}
   279  			f(t, `{"a":1}`, nil, &outer{}, &outer{})
   280  		})
   281  		t.Run("field matched", func(t *testing.T) {
   282  			type inner struct {
   283  				A int
   284  			}
   285  			type outer struct {
   286  				*inner
   287  			}
   288  			f(t, `{"a":1}`, ErrNilEmbeddedPointer, &outer{}, &outer{})
   289  		})
   290  		t.Run("exported field", func(t *testing.T) {
   291  			type Inner struct {
   292  				A int
   293  			}
   294  			type outer struct {
   295  				*Inner
   296  			}
   297  			f(t, `{"a":1}`, nil, &outer{}, &outer{})
   298  		})
   299  	})
   300  }
   301  
   302  func TestValDecoder_Native_Struct_DisallowUnknownFields(t *testing.T) {
   303  	decCfg := NewDecoderConfig(&DecoderOption{
   304  		DisallowUnknownFields: true,
   305  	})
   306  	t.Run("zero field", func(t *testing.T) {
   307  		t.Run("eof", func(t *testing.T) {
   308  			var st struct{}
   309  			err := decCfg.Unmarshal([]byte(""), &st)
   310  			checkError(t, io.EOF, err)
   311  		})
   312  		t.Run("invalid", func(t *testing.T) {
   313  			var st struct{}
   314  			err := decCfg.Unmarshal([]byte("["), &st)
   315  			checkError(t, UnexpectedByteError{}, err)
   316  		})
   317  		t.Run("null", func(t *testing.T) {
   318  			var st struct{}
   319  			err := decCfg.Unmarshal([]byte("null"), &st)
   320  			require.NoError(t, err)
   321  		})
   322  		t.Run("eof after bracket", func(t *testing.T) {
   323  			var st struct{}
   324  			err := decCfg.Unmarshal([]byte("{"), &st)
   325  			checkError(t, io.EOF, err)
   326  		})
   327  		t.Run("non empty", func(t *testing.T) {
   328  			var st struct{}
   329  			err := decCfg.Unmarshal([]byte(`{"a":1}`), &st)
   330  			checkError(t, UnexpectedByteError{}, err)
   331  		})
   332  		t.Run("empty", func(t *testing.T) {
   333  			var st struct{}
   334  			err := decCfg.Unmarshal([]byte(` { } `), &st)
   335  			require.NoError(t, err)
   336  		})
   337  	})
   338  	t.Run("one field", func(t *testing.T) {
   339  		t.Run("empty", func(t *testing.T) {
   340  			var st struct {
   341  				A int
   342  			}
   343  			err := decCfg.Unmarshal([]byte(` { } `), &st)
   344  			require.NoError(t, err)
   345  		})
   346  		t.Run("non empty", func(t *testing.T) {
   347  			var st struct {
   348  				A int
   349  			}
   350  			err := decCfg.Unmarshal([]byte(` { "b" : 1 } `), &st)
   351  			checkError(t, UnknownFieldError(""), err)
   352  		})
   353  	})
   354  }
   355  
   356  func TestValDecoder_Native_Struct_Quoted(t *testing.T) {
   357  	f := func(t *testing.T, data string, ex error, p1, p2 interface{}) {
   358  		checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2)
   359  	}
   360  	t.Run("string", func(t *testing.T) {
   361  		type st struct {
   362  			A string `json:",string"`
   363  		}
   364  		f2 := func(t *testing.T, data string, ex error) {
   365  			f(t, data, ex, &st{A: "test"}, &st{A: "test"})
   366  		}
   367  		t.Run("null", func(t *testing.T) {
   368  			f2(t, `{"a":null}`, nil)
   369  		})
   370  		t.Run("null string", func(t *testing.T) {
   371  			f2(t, `{"a":"null"}`, nil)
   372  		})
   373  		t.Run("leading space", func(t *testing.T) {
   374  			f2(t, `{"a":" 1"}`, BadQuotedStringError(""))
   375  		})
   376  		t.Run("trailing space", func(t *testing.T) {
   377  			f2(t, `{"a":"1 "}`, BadQuotedStringError(""))
   378  		})
   379  		t.Run("empty", func(t *testing.T) {
   380  			f2(t, `{"a":""}`, BadQuotedStringError(""))
   381  		})
   382  		t.Run("not string", func(t *testing.T) {
   383  			f2(t, `{"a":"1"}`, BadQuotedStringError(""))
   384  		})
   385  		t.Run("bad string", func(t *testing.T) {
   386  			f2(t, `{"a":"\"\"\""}`, BadQuotedStringError(""))
   387  		})
   388  		t.Run("ok", func(t *testing.T) {
   389  			f2(t, `{"a":"\"null\""}`, nil)
   390  		})
   391  	})
   392  	t.Run("int", func(t *testing.T) {
   393  		type stI8 struct {
   394  			A int8 `json:",string"`
   395  		}
   396  		type stI16 struct {
   397  			A int16 `json:",string"`
   398  		}
   399  		type stI32 struct {
   400  			A int32 `json:",string"`
   401  		}
   402  		type stI64 struct {
   403  			A int64 `json:",string"`
   404  		}
   405  		type stU8 struct {
   406  			A uint8 `json:",string"`
   407  		}
   408  		type stU16 struct {
   409  			A uint16 `json:",string"`
   410  		}
   411  		type stU32 struct {
   412  			A uint32 `json:",string"`
   413  		}
   414  		type stU64 struct {
   415  			A uint64 `json:",string"`
   416  		}
   417  		f2 := func(t *testing.T, data string, ex error) {
   418  			f(t, data, ex, &stI8{A: 2}, &stI8{A: 2})
   419  			f(t, data, ex, &stI16{A: 2}, &stI16{A: 2})
   420  			f(t, data, ex, &stI32{A: 2}, &stI32{A: 2})
   421  			f(t, data, ex, &stI64{A: 2}, &stI64{A: 2})
   422  			f(t, data, ex, &stU8{A: 2}, &stU8{A: 2})
   423  			f(t, data, ex, &stU16{A: 2}, &stU16{A: 2})
   424  			f(t, data, ex, &stU32{A: 2}, &stU32{A: 2})
   425  			f(t, data, ex, &stU64{A: 2}, &stU64{A: 2})
   426  		}
   427  		t.Run("unquoted", func(t *testing.T) {
   428  			f2(t, `{"a":1}`, UnexpectedByteError{})
   429  		})
   430  		t.Run("leading space", func(t *testing.T) {
   431  			f2(t, `{"a":" 1"}`, InvalidDigitError{})
   432  		})
   433  		t.Run("leading eof", func(t *testing.T) {
   434  			f2(t, `{"a":"`, io.EOF)
   435  		})
   436  		t.Run("trailing space", func(t *testing.T) {
   437  			f2(t, `{"a":"1 "}`, UnexpectedByteError{})
   438  		})
   439  		t.Run("trailing eof", func(t *testing.T) {
   440  			f2(t, `{"a":"1`, io.EOF)
   441  		})
   442  		t.Run("empty", func(t *testing.T) {
   443  			f2(t, `{"a":""}`, InvalidDigitError{})
   444  		})
   445  		t.Run("ok", func(t *testing.T) {
   446  			f2(t, `{"a":"1"}`, nil)
   447  		})
   448  	})
   449  }