Source file src/encoding/json/jsontext/coder_test.go

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.jsonv2
     6  
     7  package jsontext
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"io"
    13  	"math"
    14  	"math/rand"
    15  	"path"
    16  	"reflect"
    17  	"strings"
    18  	"testing"
    19  
    20  	"encoding/json/internal/jsontest"
    21  	"encoding/json/internal/jsonwire"
    22  )
    23  
    24  func E(err error) *SyntacticError {
    25  	return &SyntacticError{Err: err}
    26  }
    27  
    28  func newInvalidCharacterError(prefix, where string) *SyntacticError {
    29  	return E(jsonwire.NewInvalidCharacterError(prefix, where))
    30  }
    31  
    32  func newInvalidEscapeSequenceError(what string) *SyntacticError {
    33  	return E(jsonwire.NewInvalidEscapeSequenceError(what))
    34  }
    35  
    36  func (e *SyntacticError) withPos(prefix string, pointer Pointer) *SyntacticError {
    37  	e.ByteOffset = int64(len(prefix))
    38  	e.JSONPointer = pointer
    39  	return e
    40  }
    41  
    42  func equalError(x, y error) bool {
    43  	return reflect.DeepEqual(x, y)
    44  }
    45  
    46  var (
    47  	zeroToken Token
    48  	zeroValue Value
    49  )
    50  
    51  // tokOrVal is either a Token or a Value.
    52  type tokOrVal interface{ Kind() Kind }
    53  
    54  type coderTestdataEntry struct {
    55  	name             jsontest.CaseName
    56  	in               string
    57  	outCompacted     string
    58  	outEscaped       string // outCompacted if empty; escapes all runes in a string
    59  	outIndented      string // outCompacted if empty; uses "  " for indent prefix and "\t" for indent
    60  	outCanonicalized string // outCompacted if empty
    61  	tokens           []Token
    62  	pointers         []Pointer
    63  }
    64  
    65  var coderTestdata = []coderTestdataEntry{{
    66  	name:         jsontest.Name("Null"),
    67  	in:           ` null `,
    68  	outCompacted: `null`,
    69  	tokens:       []Token{Null},
    70  	pointers:     []Pointer{""},
    71  }, {
    72  	name:         jsontest.Name("False"),
    73  	in:           ` false `,
    74  	outCompacted: `false`,
    75  	tokens:       []Token{False},
    76  }, {
    77  	name:         jsontest.Name("True"),
    78  	in:           ` true `,
    79  	outCompacted: `true`,
    80  	tokens:       []Token{True},
    81  }, {
    82  	name:         jsontest.Name("EmptyString"),
    83  	in:           ` "" `,
    84  	outCompacted: `""`,
    85  	tokens:       []Token{String("")},
    86  }, {
    87  	name:         jsontest.Name("SimpleString"),
    88  	in:           ` "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" `,
    89  	outCompacted: `"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"`,
    90  	outEscaped:   `"\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a"`,
    91  	tokens:       []Token{String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")},
    92  }, {
    93  	name:             jsontest.Name("ComplicatedString"),
    94  	in:               " \"Hello, δΈ–η•Œ πŸŒŸβ˜…β˜†βœ©πŸŒ  " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + ` \ud800\udead \"\\\/\b\f\n\r\t \u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009" `,
    95  	outCompacted:     "\"Hello, δΈ–η•Œ πŸŒŸβ˜…β˜†βœ©πŸŒ  " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + " 𐊭 \\\"\\\\/\\b\\f\\n\\r\\t \\\"\\\\/\\b\\f\\n\\r\\t\"",
    96  	outEscaped:       `"\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u4e16\u754c\u0020\ud83c\udf1f\u2605\u2606\u2729\ud83c\udf20\u0020\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\ud83d\ude02\u0020\ud800\udead\u0020\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009\u0020\u0022\u005c\u002f\u0008\u000c\u000a\u000d\u0009"`,
    97  	outCanonicalized: `"Hello, δΈ–η•Œ πŸŒŸβ˜…β˜†βœ©πŸŒ  Β€ΓΆβ‚¬νž™ξ€€ο¬³οΏ½πŸ˜‚ 𐊭 \"\\/\b\f\n\r\t \"\\/\b\f\n\r\t"`,
    98  	tokens:           []Token{rawToken("\"Hello, δΈ–η•Œ πŸŒŸβ˜…β˜†βœ©πŸŒ  " + "\u0080\u00f6\u20ac\ud799\ue000\ufb33\ufffd\U0001f602" + " 𐊭 \\\"\\\\/\\b\\f\\n\\r\\t \\\"\\\\/\\b\\f\\n\\r\\t\"")},
    99  }, {
   100  	name:         jsontest.Name("ZeroNumber"),
   101  	in:           ` 0 `,
   102  	outCompacted: `0`,
   103  	tokens:       []Token{Uint(0)},
   104  }, {
   105  	name:         jsontest.Name("SimpleNumber"),
   106  	in:           ` 123456789 `,
   107  	outCompacted: `123456789`,
   108  	tokens:       []Token{Uint(123456789)},
   109  }, {
   110  	name:         jsontest.Name("NegativeNumber"),
   111  	in:           ` -123456789 `,
   112  	outCompacted: `-123456789`,
   113  	tokens:       []Token{Int(-123456789)},
   114  }, {
   115  	name:         jsontest.Name("FractionalNumber"),
   116  	in:           " 0.123456789 ",
   117  	outCompacted: `0.123456789`,
   118  	tokens:       []Token{Float(0.123456789)},
   119  }, {
   120  	name:             jsontest.Name("ExponentNumber"),
   121  	in:               " 0e12456789 ",
   122  	outCompacted:     `0e12456789`,
   123  	outCanonicalized: `0`,
   124  	tokens:           []Token{rawToken(`0e12456789`)},
   125  }, {
   126  	name:             jsontest.Name("ExponentNumberP"),
   127  	in:               " 0e+12456789 ",
   128  	outCompacted:     `0e+12456789`,
   129  	outCanonicalized: `0`,
   130  	tokens:           []Token{rawToken(`0e+12456789`)},
   131  }, {
   132  	name:             jsontest.Name("ExponentNumberN"),
   133  	in:               " 0e-12456789 ",
   134  	outCompacted:     `0e-12456789`,
   135  	outCanonicalized: `0`,
   136  	tokens:           []Token{rawToken(`0e-12456789`)},
   137  }, {
   138  	name:             jsontest.Name("ComplicatedNumber"),
   139  	in:               ` -123456789.987654321E+0123456789 `,
   140  	outCompacted:     `-123456789.987654321E+0123456789`,
   141  	outCanonicalized: `-1.7976931348623157e+308`,
   142  	tokens:           []Token{rawToken(`-123456789.987654321E+0123456789`)},
   143  }, {
   144  	name: jsontest.Name("Numbers"),
   145  	in: ` [
   146  		0, -0, 0.0, -0.0, 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, 1e1000,
   147  		-5e-324, 1e+100, 1.7976931348623157e+308,
   148  		9007199254740990, 9007199254740991, 9007199254740992, 9007199254740993, 9007199254740994,
   149  		-9223372036854775808, 9223372036854775807, 0, 18446744073709551615
   150  	] `,
   151  	outCompacted: "[0,-0,0.0,-0.0,1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1e1000,-5e-324,1e+100,1.7976931348623157e+308,9007199254740990,9007199254740991,9007199254740992,9007199254740993,9007199254740994,-9223372036854775808,9223372036854775807,0,18446744073709551615]",
   152  	outIndented: `[
   153  	    0,
   154  	    -0,
   155  	    0.0,
   156  	    -0.0,
   157  	    1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,
   158  	    1e1000,
   159  	    -5e-324,
   160  	    1e+100,
   161  	    1.7976931348623157e+308,
   162  	    9007199254740990,
   163  	    9007199254740991,
   164  	    9007199254740992,
   165  	    9007199254740993,
   166  	    9007199254740994,
   167  	    -9223372036854775808,
   168  	    9223372036854775807,
   169  	    0,
   170  	    18446744073709551615
   171  	]`,
   172  	outCanonicalized: `[0,0,0,0,1,1.7976931348623157e+308,-5e-324,1e+100,1.7976931348623157e+308,9007199254740990,9007199254740991,9007199254740992,9007199254740992,9007199254740994,-9223372036854776000,9223372036854776000,0,18446744073709552000]`,
   173  	tokens: []Token{
   174  		BeginArray,
   175  		Float(0), Float(math.Copysign(0, -1)), rawToken(`0.0`), rawToken(`-0.0`), rawToken(`1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001`), rawToken(`1e1000`),
   176  		Float(-5e-324), Float(1e100), Float(1.7976931348623157e+308),
   177  		Float(9007199254740990), Float(9007199254740991), Float(9007199254740992), rawToken(`9007199254740993`), rawToken(`9007199254740994`),
   178  		Int(minInt64), Int(maxInt64), Uint(minUint64), Uint(maxUint64),
   179  		EndArray,
   180  	},
   181  	pointers: []Pointer{
   182  		"", "/0", "/1", "/2", "/3", "/4", "/5", "/6", "/7", "/8", "/9", "/10", "/11", "/12", "/13", "/14", "/15", "/16", "/17", "",
   183  	},
   184  }, {
   185  	name:         jsontest.Name("ObjectN0"),
   186  	in:           ` { } `,
   187  	outCompacted: `{}`,
   188  	tokens:       []Token{BeginObject, EndObject},
   189  	pointers:     []Pointer{"", ""},
   190  }, {
   191  	name:         jsontest.Name("ObjectN1"),
   192  	in:           ` { "0" : 0 } `,
   193  	outCompacted: `{"0":0}`,
   194  	outEscaped:   `{"\u0030":0}`,
   195  	outIndented: `{
   196  	    "0": 0
   197  	}`,
   198  	tokens:   []Token{BeginObject, String("0"), Uint(0), EndObject},
   199  	pointers: []Pointer{"", "/0", "/0", ""},
   200  }, {
   201  	name:         jsontest.Name("ObjectN2"),
   202  	in:           ` { "0" : 0 , "1" : 1 } `,
   203  	outCompacted: `{"0":0,"1":1}`,
   204  	outEscaped:   `{"\u0030":0,"\u0031":1}`,
   205  	outIndented: `{
   206  	    "0": 0,
   207  	    "1": 1
   208  	}`,
   209  	tokens:   []Token{BeginObject, String("0"), Uint(0), String("1"), Uint(1), EndObject},
   210  	pointers: []Pointer{"", "/0", "/0", "/1", "/1", ""},
   211  }, {
   212  	name:         jsontest.Name("ObjectNested"),
   213  	in:           ` { "0" : { "1" : { "2" : { "3" : { "4" : {  } } } } } } `,
   214  	outCompacted: `{"0":{"1":{"2":{"3":{"4":{}}}}}}`,
   215  	outEscaped:   `{"\u0030":{"\u0031":{"\u0032":{"\u0033":{"\u0034":{}}}}}}`,
   216  	outIndented: `{
   217  	    "0": {
   218  	        "1": {
   219  	            "2": {
   220  	                "3": {
   221  	                    "4": {}
   222  	                }
   223  	            }
   224  	        }
   225  	    }
   226  	}`,
   227  	tokens: []Token{BeginObject, String("0"), BeginObject, String("1"), BeginObject, String("2"), BeginObject, String("3"), BeginObject, String("4"), BeginObject, EndObject, EndObject, EndObject, EndObject, EndObject, EndObject},
   228  	pointers: []Pointer{
   229  		"",
   230  		"/0", "/0",
   231  		"/0/1", "/0/1",
   232  		"/0/1/2", "/0/1/2",
   233  		"/0/1/2/3", "/0/1/2/3",
   234  		"/0/1/2/3/4", "/0/1/2/3/4",
   235  		"/0/1/2/3/4",
   236  		"/0/1/2/3",
   237  		"/0/1/2",
   238  		"/0/1",
   239  		"/0",
   240  		"",
   241  	},
   242  }, {
   243  	name: jsontest.Name("ObjectSuperNested"),
   244  	in: `{"": {
   245  		"44444": {
   246  			"6666666":  "ccccccc",
   247  			"77777777": "bb",
   248  			"555555":   "aaaa"
   249  		},
   250  		"0": {
   251  			"3333": "bbb",
   252  			"11":   "",
   253  			"222":  "aaaaa"
   254  		}
   255  	}}`,
   256  	outCompacted: `{"":{"44444":{"6666666":"ccccccc","77777777":"bb","555555":"aaaa"},"0":{"3333":"bbb","11":"","222":"aaaaa"}}}`,
   257  	outEscaped:   `{"":{"\u0034\u0034\u0034\u0034\u0034":{"\u0036\u0036\u0036\u0036\u0036\u0036\u0036":"\u0063\u0063\u0063\u0063\u0063\u0063\u0063","\u0037\u0037\u0037\u0037\u0037\u0037\u0037\u0037":"\u0062\u0062","\u0035\u0035\u0035\u0035\u0035\u0035":"\u0061\u0061\u0061\u0061"},"\u0030":{"\u0033\u0033\u0033\u0033":"\u0062\u0062\u0062","\u0031\u0031":"","\u0032\u0032\u0032":"\u0061\u0061\u0061\u0061\u0061"}}}`,
   258  	outIndented: `{
   259  	    "": {
   260  	        "44444": {
   261  	            "6666666": "ccccccc",
   262  	            "77777777": "bb",
   263  	            "555555": "aaaa"
   264  	        },
   265  	        "0": {
   266  	            "3333": "bbb",
   267  	            "11": "",
   268  	            "222": "aaaaa"
   269  	        }
   270  	    }
   271  	}`,
   272  	outCanonicalized: `{"":{"0":{"11":"","222":"aaaaa","3333":"bbb"},"44444":{"555555":"aaaa","6666666":"ccccccc","77777777":"bb"}}}`,
   273  	tokens: []Token{
   274  		BeginObject,
   275  		String(""),
   276  		BeginObject,
   277  		String("44444"),
   278  		BeginObject,
   279  		String("6666666"), String("ccccccc"),
   280  		String("77777777"), String("bb"),
   281  		String("555555"), String("aaaa"),
   282  		EndObject,
   283  		String("0"),
   284  		BeginObject,
   285  		String("3333"), String("bbb"),
   286  		String("11"), String(""),
   287  		String("222"), String("aaaaa"),
   288  		EndObject,
   289  		EndObject,
   290  		EndObject,
   291  	},
   292  	pointers: []Pointer{
   293  		"",
   294  		"/", "/",
   295  		"//44444", "//44444",
   296  		"//44444/6666666", "//44444/6666666",
   297  		"//44444/77777777", "//44444/77777777",
   298  		"//44444/555555", "//44444/555555",
   299  		"//44444",
   300  		"//0", "//0",
   301  		"//0/3333", "//0/3333",
   302  		"//0/11", "//0/11",
   303  		"//0/222", "//0/222",
   304  		"//0",
   305  		"/",
   306  		"",
   307  	},
   308  }, {
   309  	name:         jsontest.Name("ArrayN0"),
   310  	in:           ` [ ] `,
   311  	outCompacted: `[]`,
   312  	tokens:       []Token{BeginArray, EndArray},
   313  	pointers:     []Pointer{"", ""},
   314  }, {
   315  	name:         jsontest.Name("ArrayN1"),
   316  	in:           ` [ 0 ] `,
   317  	outCompacted: `[0]`,
   318  	outIndented: `[
   319  	    0
   320  	]`,
   321  	tokens:   []Token{BeginArray, Uint(0), EndArray},
   322  	pointers: []Pointer{"", "/0", ""},
   323  }, {
   324  	name:         jsontest.Name("ArrayN2"),
   325  	in:           ` [ 0 , 1 ] `,
   326  	outCompacted: `[0,1]`,
   327  	outIndented: `[
   328  	    0,
   329  	    1
   330  	]`,
   331  	tokens: []Token{BeginArray, Uint(0), Uint(1), EndArray},
   332  }, {
   333  	name:         jsontest.Name("ArrayNested"),
   334  	in:           ` [ [ [ [ [ ] ] ] ] ] `,
   335  	outCompacted: `[[[[[]]]]]`,
   336  	outIndented: `[
   337  	    [
   338  	        [
   339  	            [
   340  	                []
   341  	            ]
   342  	        ]
   343  	    ]
   344  	]`,
   345  	tokens: []Token{BeginArray, BeginArray, BeginArray, BeginArray, BeginArray, EndArray, EndArray, EndArray, EndArray, EndArray},
   346  	pointers: []Pointer{
   347  		"",
   348  		"/0",
   349  		"/0/0",
   350  		"/0/0/0",
   351  		"/0/0/0/0",
   352  		"/0/0/0/0",
   353  		"/0/0/0",
   354  		"/0/0",
   355  		"/0",
   356  		"",
   357  	},
   358  }, {
   359  	name: jsontest.Name("Everything"),
   360  	in: ` {
   361  		"literals" : [ null , false , true ],
   362  		"string" : "Hello, δΈ–η•Œ" ,
   363  		"number" : 3.14159 ,
   364  		"arrayN0" : [ ] ,
   365  		"arrayN1" : [ 0 ] ,
   366  		"arrayN2" : [ 0 , 1 ] ,
   367  		"objectN0" : { } ,
   368  		"objectN1" : { "0" : 0 } ,
   369  		"objectN2" : { "0" : 0 , "1" : 1 }
   370  	} `,
   371  	outCompacted: `{"literals":[null,false,true],"string":"Hello, δΈ–η•Œ","number":3.14159,"arrayN0":[],"arrayN1":[0],"arrayN2":[0,1],"objectN0":{},"objectN1":{"0":0},"objectN2":{"0":0,"1":1}}`,
   372  	outEscaped:   `{"\u006c\u0069\u0074\u0065\u0072\u0061\u006c\u0073":[null,false,true],"\u0073\u0074\u0072\u0069\u006e\u0067":"\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u4e16\u754c","\u006e\u0075\u006d\u0062\u0065\u0072":3.14159,"\u0061\u0072\u0072\u0061\u0079\u004e\u0030":[],"\u0061\u0072\u0072\u0061\u0079\u004e\u0031":[0],"\u0061\u0072\u0072\u0061\u0079\u004e\u0032":[0,1],"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0030":{},"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0031":{"\u0030":0},"\u006f\u0062\u006a\u0065\u0063\u0074\u004e\u0032":{"\u0030":0,"\u0031":1}}`,
   373  	outIndented: `{
   374  	    "literals": [
   375  	        null,
   376  	        false,
   377  	        true
   378  	    ],
   379  	    "string": "Hello, δΈ–η•Œ",
   380  	    "number": 3.14159,
   381  	    "arrayN0": [],
   382  	    "arrayN1": [
   383  	        0
   384  	    ],
   385  	    "arrayN2": [
   386  	        0,
   387  	        1
   388  	    ],
   389  	    "objectN0": {},
   390  	    "objectN1": {
   391  	        "0": 0
   392  	    },
   393  	    "objectN2": {
   394  	        "0": 0,
   395  	        "1": 1
   396  	    }
   397  	}`,
   398  	outCanonicalized: `{"arrayN0":[],"arrayN1":[0],"arrayN2":[0,1],"literals":[null,false,true],"number":3.14159,"objectN0":{},"objectN1":{"0":0},"objectN2":{"0":0,"1":1},"string":"Hello, δΈ–η•Œ"}`,
   399  	tokens: []Token{
   400  		BeginObject,
   401  		String("literals"), BeginArray, Null, False, True, EndArray,
   402  		String("string"), String("Hello, δΈ–η•Œ"),
   403  		String("number"), Float(3.14159),
   404  		String("arrayN0"), BeginArray, EndArray,
   405  		String("arrayN1"), BeginArray, Uint(0), EndArray,
   406  		String("arrayN2"), BeginArray, Uint(0), Uint(1), EndArray,
   407  		String("objectN0"), BeginObject, EndObject,
   408  		String("objectN1"), BeginObject, String("0"), Uint(0), EndObject,
   409  		String("objectN2"), BeginObject, String("0"), Uint(0), String("1"), Uint(1), EndObject,
   410  		EndObject,
   411  	},
   412  	pointers: []Pointer{
   413  		"",
   414  		"/literals", "/literals",
   415  		"/literals/0",
   416  		"/literals/1",
   417  		"/literals/2",
   418  		"/literals",
   419  		"/string", "/string",
   420  		"/number", "/number",
   421  		"/arrayN0", "/arrayN0", "/arrayN0",
   422  		"/arrayN1", "/arrayN1",
   423  		"/arrayN1/0",
   424  		"/arrayN1",
   425  		"/arrayN2", "/arrayN2",
   426  		"/arrayN2/0",
   427  		"/arrayN2/1",
   428  		"/arrayN2",
   429  		"/objectN0", "/objectN0", "/objectN0",
   430  		"/objectN1", "/objectN1",
   431  		"/objectN1/0", "/objectN1/0",
   432  		"/objectN1",
   433  		"/objectN2", "/objectN2",
   434  		"/objectN2/0", "/objectN2/0",
   435  		"/objectN2/1", "/objectN2/1",
   436  		"/objectN2",
   437  		"",
   438  	},
   439  }}
   440  
   441  // TestCoderInterleaved tests that we can interleave calls that operate on
   442  // tokens and raw values. The only error condition is trying to operate on a
   443  // raw value when the next token is an end of object or array.
   444  func TestCoderInterleaved(t *testing.T) {
   445  	for _, td := range coderTestdata {
   446  		// In TokenFirst and ValueFirst, alternate between tokens and values.
   447  		// In TokenDelims, only use tokens for object and array delimiters.
   448  		for _, modeName := range []string{"TokenFirst", "ValueFirst", "TokenDelims"} {
   449  			t.Run(path.Join(td.name.Name, modeName), func(t *testing.T) {
   450  				testCoderInterleaved(t, td.name.Where, modeName, td)
   451  			})
   452  		}
   453  	}
   454  }
   455  func testCoderInterleaved(t *testing.T, where jsontest.CasePos, modeName string, td coderTestdataEntry) {
   456  	src := strings.NewReader(td.in)
   457  	dst := new(bytes.Buffer)
   458  	dec := NewDecoder(src)
   459  	enc := NewEncoder(dst)
   460  	tickTock := modeName == "TokenFirst"
   461  	for {
   462  		if modeName == "TokenDelims" {
   463  			switch dec.PeekKind() {
   464  			case '{', '}', '[', ']':
   465  				tickTock = true // as token
   466  			default:
   467  				tickTock = false // as value
   468  			}
   469  		}
   470  		if tickTock {
   471  			tok, err := dec.ReadToken()
   472  			if err != nil {
   473  				if err == io.EOF {
   474  					break
   475  				}
   476  				t.Fatalf("%s: Decoder.ReadToken error: %v", where, err)
   477  			}
   478  			if err := enc.WriteToken(tok); err != nil {
   479  				t.Fatalf("%s: Encoder.WriteToken error: %v", where, err)
   480  			}
   481  		} else {
   482  			val, err := dec.ReadValue()
   483  			if err != nil {
   484  				// It is a syntactic error to call ReadValue
   485  				// at the end of an object or array.
   486  				// Retry as a ReadToken call.
   487  				expectError := dec.PeekKind() == '}' || dec.PeekKind() == ']'
   488  				if expectError {
   489  					if !errors.As(err, new(*SyntacticError)) {
   490  						t.Fatalf("%s: Decoder.ReadToken error is %T, want %T", where, err, new(SyntacticError))
   491  					}
   492  					tickTock = !tickTock
   493  					continue
   494  				}
   495  
   496  				if err == io.EOF {
   497  					break
   498  				}
   499  				t.Fatalf("%s: Decoder.ReadValue error: %v", where, err)
   500  			}
   501  			if err := enc.WriteValue(val); err != nil {
   502  				t.Fatalf("%s: Encoder.WriteValue error: %v", where, err)
   503  			}
   504  		}
   505  		tickTock = !tickTock
   506  	}
   507  
   508  	got := dst.String()
   509  	want := td.outCompacted + "\n"
   510  	if got != want {
   511  		t.Fatalf("%s: output mismatch:\ngot  %q\nwant %q", where, got, want)
   512  	}
   513  }
   514  
   515  func TestCoderStackPointer(t *testing.T) {
   516  	tests := []struct {
   517  		token Token
   518  		want  Pointer
   519  	}{
   520  		{Null, ""},
   521  
   522  		{BeginArray, ""},
   523  		{EndArray, ""},
   524  
   525  		{BeginArray, ""},
   526  		{Bool(true), "/0"},
   527  		{EndArray, ""},
   528  
   529  		{BeginArray, ""},
   530  		{String("hello"), "/0"},
   531  		{String("goodbye"), "/1"},
   532  		{EndArray, ""},
   533  
   534  		{BeginObject, ""},
   535  		{EndObject, ""},
   536  
   537  		{BeginObject, ""},
   538  		{String("hello"), "/hello"},
   539  		{String("goodbye"), "/hello"},
   540  		{EndObject, ""},
   541  
   542  		{BeginObject, ""},
   543  		{String(""), "/"},
   544  		{Null, "/"},
   545  		{String("0"), "/0"},
   546  		{Null, "/0"},
   547  		{String("~"), "/~0"},
   548  		{Null, "/~0"},
   549  		{String("/"), "/~1"},
   550  		{Null, "/~1"},
   551  		{String("a//b~/c/~d~~e"), "/a~1~1b~0~1c~1~0d~0~0e"},
   552  		{Null, "/a~1~1b~0~1c~1~0d~0~0e"},
   553  		{String(" \r\n\t"), "/ \r\n\t"},
   554  		{Null, "/ \r\n\t"},
   555  		{EndObject, ""},
   556  
   557  		{BeginArray, ""},
   558  		{BeginObject, "/0"},
   559  		{String(""), "/0/"},
   560  		{BeginArray, "/0/"},
   561  		{BeginObject, "/0//0"},
   562  		{String("#"), "/0//0/#"},
   563  		{Null, "/0//0/#"},
   564  		{EndObject, "/0//0"},
   565  		{EndArray, "/0/"},
   566  		{EndObject, "/0"},
   567  		{EndArray, ""},
   568  	}
   569  
   570  	for _, allowDupes := range []bool{false, true} {
   571  		var name string
   572  		switch allowDupes {
   573  		case false:
   574  			name = "RejectDuplicateNames"
   575  		case true:
   576  			name = "AllowDuplicateNames"
   577  		}
   578  
   579  		t.Run(name, func(t *testing.T) {
   580  			bb := new(bytes.Buffer)
   581  
   582  			enc := NewEncoder(bb, AllowDuplicateNames(allowDupes))
   583  			for i, tt := range tests {
   584  				if err := enc.WriteToken(tt.token); err != nil {
   585  					t.Fatalf("%d: Encoder.WriteToken error: %v", i, err)
   586  				}
   587  				if got := enc.StackPointer(); got != tests[i].want {
   588  					t.Fatalf("%d: Encoder.StackPointer = %v, want %v", i, got, tests[i].want)
   589  				}
   590  			}
   591  
   592  			dec := NewDecoder(bb, AllowDuplicateNames(allowDupes))
   593  			for i := range tests {
   594  				if _, err := dec.ReadToken(); err != nil {
   595  					t.Fatalf("%d: Decoder.ReadToken error: %v", i, err)
   596  				}
   597  				if got := dec.StackPointer(); got != tests[i].want {
   598  					t.Fatalf("%d: Decoder.StackPointer = %v, want %v", i, got, tests[i].want)
   599  				}
   600  			}
   601  		})
   602  	}
   603  }
   604  
   605  func TestCoderMaxDepth(t *testing.T) {
   606  	trimArray := func(b []byte) []byte { return b[len(`[`) : len(b)-len(`]`)] }
   607  	maxArrays := []byte(strings.Repeat(`[`, maxNestingDepth+1) + strings.Repeat(`]`, maxNestingDepth+1))
   608  	trimObject := func(b []byte) []byte { return b[len(`{"":`) : len(b)-len(`}`)] }
   609  	maxObjects := []byte(strings.Repeat(`{"":`, maxNestingDepth+1) + `""` + strings.Repeat(`}`, maxNestingDepth+1))
   610  
   611  	t.Run("Decoder", func(t *testing.T) {
   612  		var dec Decoder
   613  		checkReadToken := func(t *testing.T, wantKind Kind, wantErr error) {
   614  			t.Helper()
   615  			if tok, err := dec.ReadToken(); tok.Kind() != wantKind || !equalError(err, wantErr) {
   616  				t.Fatalf("Decoder.ReadToken = (%q, %v), want (%q, %v)", byte(tok.Kind()), err, byte(wantKind), wantErr)
   617  			}
   618  		}
   619  		checkReadValue := func(t *testing.T, wantLen int, wantErr error) {
   620  			t.Helper()
   621  			if val, err := dec.ReadValue(); len(val) != wantLen || !equalError(err, wantErr) {
   622  				t.Fatalf("Decoder.ReadValue = (%d, %v), want (%d, %v)", len(val), err, wantLen, wantErr)
   623  			}
   624  		}
   625  
   626  		t.Run("ArraysValid/SingleValue", func(t *testing.T) {
   627  			dec.s.reset(trimArray(maxArrays), nil)
   628  			checkReadValue(t, maxNestingDepth*len(`[]`), nil)
   629  		})
   630  		t.Run("ArraysValid/TokenThenValue", func(t *testing.T) {
   631  			dec.s.reset(trimArray(maxArrays), nil)
   632  			checkReadToken(t, '[', nil)
   633  			checkReadValue(t, (maxNestingDepth-1)*len(`[]`), nil)
   634  			checkReadToken(t, ']', nil)
   635  		})
   636  		t.Run("ArraysValid/AllTokens", func(t *testing.T) {
   637  			dec.s.reset(trimArray(maxArrays), nil)
   638  			for range maxNestingDepth {
   639  				checkReadToken(t, '[', nil)
   640  			}
   641  			for range maxNestingDepth {
   642  				checkReadToken(t, ']', nil)
   643  			}
   644  		})
   645  
   646  		wantErr := &SyntacticError{
   647  			ByteOffset:  maxNestingDepth,
   648  			JSONPointer: Pointer(strings.Repeat("/0", maxNestingDepth)),
   649  			Err:         errMaxDepth,
   650  		}
   651  		t.Run("ArraysInvalid/SingleValue", func(t *testing.T) {
   652  			dec.s.reset(maxArrays, nil)
   653  			checkReadValue(t, 0, wantErr)
   654  		})
   655  		t.Run("ArraysInvalid/TokenThenValue", func(t *testing.T) {
   656  			dec.s.reset(maxArrays, nil)
   657  			checkReadToken(t, '[', nil)
   658  			checkReadValue(t, 0, wantErr)
   659  		})
   660  		t.Run("ArraysInvalid/AllTokens", func(t *testing.T) {
   661  			dec.s.reset(maxArrays, nil)
   662  			for range maxNestingDepth {
   663  				checkReadToken(t, '[', nil)
   664  			}
   665  			checkReadValue(t, 0, wantErr)
   666  		})
   667  
   668  		t.Run("ObjectsValid/SingleValue", func(t *testing.T) {
   669  			dec.s.reset(trimObject(maxObjects), nil)
   670  			checkReadValue(t, maxNestingDepth*len(`{"":}`)+len(`""`), nil)
   671  		})
   672  		t.Run("ObjectsValid/TokenThenValue", func(t *testing.T) {
   673  			dec.s.reset(trimObject(maxObjects), nil)
   674  			checkReadToken(t, '{', nil)
   675  			checkReadToken(t, '"', nil)
   676  			checkReadValue(t, (maxNestingDepth-1)*len(`{"":}`)+len(`""`), nil)
   677  			checkReadToken(t, '}', nil)
   678  		})
   679  		t.Run("ObjectsValid/AllTokens", func(t *testing.T) {
   680  			dec.s.reset(trimObject(maxObjects), nil)
   681  			for range maxNestingDepth {
   682  				checkReadToken(t, '{', nil)
   683  				checkReadToken(t, '"', nil)
   684  			}
   685  			checkReadToken(t, '"', nil)
   686  			for range maxNestingDepth {
   687  				checkReadToken(t, '}', nil)
   688  			}
   689  		})
   690  
   691  		wantErr = &SyntacticError{
   692  			ByteOffset:  maxNestingDepth * int64(len(`{"":`)),
   693  			JSONPointer: Pointer(strings.Repeat("/", maxNestingDepth)),
   694  			Err:         errMaxDepth,
   695  		}
   696  		t.Run("ObjectsInvalid/SingleValue", func(t *testing.T) {
   697  			dec.s.reset(maxObjects, nil)
   698  			checkReadValue(t, 0, wantErr)
   699  		})
   700  		t.Run("ObjectsInvalid/TokenThenValue", func(t *testing.T) {
   701  			dec.s.reset(maxObjects, nil)
   702  			checkReadToken(t, '{', nil)
   703  			checkReadToken(t, '"', nil)
   704  			checkReadValue(t, 0, wantErr)
   705  		})
   706  		t.Run("ObjectsInvalid/AllTokens", func(t *testing.T) {
   707  			dec.s.reset(maxObjects, nil)
   708  			for range maxNestingDepth {
   709  				checkReadToken(t, '{', nil)
   710  				checkReadToken(t, '"', nil)
   711  			}
   712  			checkReadToken(t, 0, wantErr)
   713  		})
   714  	})
   715  
   716  	t.Run("Encoder", func(t *testing.T) {
   717  		var enc Encoder
   718  		checkWriteToken := func(t *testing.T, tok Token, wantErr error) {
   719  			t.Helper()
   720  			if err := enc.WriteToken(tok); !equalError(err, wantErr) {
   721  				t.Fatalf("Encoder.WriteToken = %v, want %v", err, wantErr)
   722  			}
   723  		}
   724  		checkWriteValue := func(t *testing.T, val Value, wantErr error) {
   725  			t.Helper()
   726  			if err := enc.WriteValue(val); !equalError(err, wantErr) {
   727  				t.Fatalf("Encoder.WriteValue = %v, want %v", err, wantErr)
   728  			}
   729  		}
   730  
   731  		wantErr := &SyntacticError{
   732  			ByteOffset:  maxNestingDepth,
   733  			JSONPointer: Pointer(strings.Repeat("/0", maxNestingDepth)),
   734  			Err:         errMaxDepth,
   735  		}
   736  		t.Run("Arrays/SingleValue", func(t *testing.T) {
   737  			enc.s.reset(enc.s.Buf[:0], nil)
   738  			checkWriteValue(t, maxArrays, wantErr)
   739  			checkWriteValue(t, trimArray(maxArrays), nil)
   740  		})
   741  		t.Run("Arrays/TokenThenValue", func(t *testing.T) {
   742  			enc.s.reset(enc.s.Buf[:0], nil)
   743  			checkWriteToken(t, BeginArray, nil)
   744  			checkWriteValue(t, trimArray(maxArrays), wantErr)
   745  			checkWriteValue(t, trimArray(trimArray(maxArrays)), nil)
   746  			checkWriteToken(t, EndArray, nil)
   747  		})
   748  		t.Run("Arrays/AllTokens", func(t *testing.T) {
   749  			enc.s.reset(enc.s.Buf[:0], nil)
   750  			for range maxNestingDepth {
   751  				checkWriteToken(t, BeginArray, nil)
   752  			}
   753  			checkWriteToken(t, BeginArray, wantErr)
   754  			for range maxNestingDepth {
   755  				checkWriteToken(t, EndArray, nil)
   756  			}
   757  		})
   758  
   759  		wantErr = &SyntacticError{
   760  			ByteOffset:  maxNestingDepth * int64(len(`{"":`)),
   761  			JSONPointer: Pointer(strings.Repeat("/", maxNestingDepth)),
   762  			Err:         errMaxDepth,
   763  		}
   764  		t.Run("Objects/SingleValue", func(t *testing.T) {
   765  			enc.s.reset(enc.s.Buf[:0], nil)
   766  			checkWriteValue(t, maxObjects, wantErr)
   767  			checkWriteValue(t, trimObject(maxObjects), nil)
   768  		})
   769  		t.Run("Objects/TokenThenValue", func(t *testing.T) {
   770  			enc.s.reset(enc.s.Buf[:0], nil)
   771  			checkWriteToken(t, BeginObject, nil)
   772  			checkWriteToken(t, String(""), nil)
   773  			checkWriteValue(t, trimObject(maxObjects), wantErr)
   774  			checkWriteValue(t, trimObject(trimObject(maxObjects)), nil)
   775  			checkWriteToken(t, EndObject, nil)
   776  		})
   777  		t.Run("Objects/AllTokens", func(t *testing.T) {
   778  			enc.s.reset(enc.s.Buf[:0], nil)
   779  			for range maxNestingDepth - 1 {
   780  				checkWriteToken(t, BeginObject, nil)
   781  				checkWriteToken(t, String(""), nil)
   782  			}
   783  			checkWriteToken(t, BeginObject, nil)
   784  			checkWriteToken(t, String(""), nil)
   785  			checkWriteToken(t, BeginObject, wantErr)
   786  			checkWriteToken(t, String(""), nil)
   787  			for range maxNestingDepth {
   788  				checkWriteToken(t, EndObject, nil)
   789  			}
   790  		})
   791  	})
   792  }
   793  
   794  // FaultyBuffer implements io.Reader and io.Writer.
   795  // It may process fewer bytes than the provided buffer
   796  // and may randomly return an error.
   797  type FaultyBuffer struct {
   798  	B []byte
   799  
   800  	// MaxBytes is the maximum number of bytes read/written.
   801  	// A random number of bytes within [0, MaxBytes] are processed.
   802  	// A non-positive value is treated as infinity.
   803  	MaxBytes int
   804  
   805  	// MayError specifies whether to randomly provide this error.
   806  	// Even if an error is returned, no bytes are dropped.
   807  	MayError error
   808  
   809  	// Rand to use for pseudo-random behavior.
   810  	// If nil, it will be initialized with rand.NewSource(0).
   811  	Rand rand.Source
   812  }
   813  
   814  func (p *FaultyBuffer) Read(b []byte) (int, error) {
   815  	b = b[:copy(b[:p.mayTruncate(len(b))], p.B)]
   816  	p.B = p.B[len(b):]
   817  	if len(p.B) == 0 && (len(b) == 0 || p.randN(2) == 0) {
   818  		return len(b), io.EOF
   819  	}
   820  	return len(b), p.mayError()
   821  }
   822  
   823  func (p *FaultyBuffer) Write(b []byte) (int, error) {
   824  	b2 := b[:p.mayTruncate(len(b))]
   825  	p.B = append(p.B, b2...)
   826  	if len(b2) < len(b) {
   827  		return len(b2), io.ErrShortWrite
   828  	}
   829  	return len(b2), p.mayError()
   830  }
   831  
   832  // mayTruncate may return a value between [0, n].
   833  func (p *FaultyBuffer) mayTruncate(n int) int {
   834  	if p.MaxBytes > 0 {
   835  		if n > p.MaxBytes {
   836  			n = p.MaxBytes
   837  		}
   838  		return p.randN(n + 1)
   839  	}
   840  	return n
   841  }
   842  
   843  // mayError may return a non-nil error.
   844  func (p *FaultyBuffer) mayError() error {
   845  	if p.MayError != nil && p.randN(2) == 0 {
   846  		return p.MayError
   847  	}
   848  	return nil
   849  }
   850  
   851  func (p *FaultyBuffer) randN(n int) int {
   852  	if p.Rand == nil {
   853  		p.Rand = rand.NewSource(0)
   854  	}
   855  	return int(p.Rand.Int63() % int64(n))
   856  }
   857  

View as plain text