...

Source file src/go.mongodb.org/mongo-driver/bson/bsonrw/json_scanner_test.go

Documentation: go.mongodb.org/mongo-driver/bson/bsonrw

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package bsonrw
     8  
     9  import (
    10  	"strings"
    11  	"testing"
    12  	"testing/iotest"
    13  
    14  	"github.com/google/go-cmp/cmp"
    15  )
    16  
    17  func jttDiff(t *testing.T, expected, actual jsonTokenType, desc string) {
    18  	if diff := cmp.Diff(expected, actual); diff != "" {
    19  		t.Helper()
    20  		t.Errorf("%s: Incorrect JSON Token Type (-want, +got): %s\n", desc, diff)
    21  		t.FailNow()
    22  	}
    23  }
    24  
    25  func jtvDiff(t *testing.T, expected, actual interface{}, desc string) {
    26  	if diff := cmp.Diff(expected, actual); diff != "" {
    27  		t.Helper()
    28  		t.Errorf("%s: Incorrect JSON Token Value (-want, +got): %s\n", desc, diff)
    29  		t.FailNow()
    30  	}
    31  }
    32  
    33  func expectNilToken(t *testing.T, v *jsonToken, desc string) {
    34  	if v != nil {
    35  		t.Helper()
    36  		t.Errorf("%s: Expected nil JSON token", desc)
    37  		t.FailNow()
    38  	}
    39  }
    40  
    41  func expectError(t *testing.T, err error, desc string) {
    42  	if err == nil {
    43  		t.Helper()
    44  		t.Errorf("%s: Expected error", desc)
    45  		t.FailNow()
    46  	}
    47  }
    48  
    49  func expectNoError(t *testing.T, err error, desc string) {
    50  	if err != nil {
    51  		t.Helper()
    52  		t.Errorf("%s: Unepexted error: %v", desc, err)
    53  		t.FailNow()
    54  	}
    55  }
    56  
    57  type jsonScannerTestCase struct {
    58  	desc   string
    59  	input  string
    60  	tokens []jsonToken
    61  }
    62  
    63  // length = 512
    64  const longKey = "abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    65  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    66  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    67  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    68  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    69  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    70  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    71  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    72  	"abcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyz" +
    73  	"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr"
    74  
    75  func TestJsonScannerValidInputs(t *testing.T) {
    76  	cases := []jsonScannerTestCase{
    77  		{
    78  			desc: "empty input", input: "",
    79  			tokens: []jsonToken{},
    80  		},
    81  		{
    82  			desc: "empty object", input: "{}",
    83  			tokens: []jsonToken{{t: jttBeginObject, v: byte('{')}, {t: jttEndObject, v: byte('}')}},
    84  		},
    85  		{
    86  			desc: "empty array", input: "[]",
    87  			tokens: []jsonToken{{t: jttBeginArray, v: byte('[')}, {t: jttEndArray, v: byte(']')}},
    88  		},
    89  		{
    90  			desc: "valid empty string", input: `""`,
    91  			tokens: []jsonToken{{t: jttString, v: ""}},
    92  		},
    93  		{
    94  			desc:   "valid string--no escaped characters",
    95  			input:  `"string"`,
    96  			tokens: []jsonToken{{t: jttString, v: "string"}},
    97  		},
    98  		{
    99  			desc:   "valid string--escaped characters",
   100  			input:  `"\"\\\/\b\f\n\r\t"`,
   101  			tokens: []jsonToken{{t: jttString, v: "\"\\/\b\f\n\r\t"}},
   102  		},
   103  		{
   104  			desc:   "valid string--surrogate pair",
   105  			input:  `"abc \uD834\uDd1e 123"`,
   106  			tokens: []jsonToken{{t: jttString, v: "abc 𝄞 123"}},
   107  		},
   108  		{
   109  			desc:   "valid string--high surrogate at end of string",
   110  			input:  `"abc \uD834"`,
   111  			tokens: []jsonToken{{t: jttString, v: "abc �"}},
   112  		},
   113  		{
   114  			desc:   "valid string--low surrogate at end of string",
   115  			input:  `"abc \uDD1E"`,
   116  			tokens: []jsonToken{{t: jttString, v: "abc �"}},
   117  		},
   118  		{
   119  			desc:   "valid string--high surrogate with non-surrogate Unicode value",
   120  			input:  `"abc \uDD1E\u00BF"`,
   121  			tokens: []jsonToken{{t: jttString, v: "abc �¿"}},
   122  		},
   123  		{
   124  			desc:   "valid string--high surrogate with non-Unicode escape sequence",
   125  			input:  `"abc \uDD1E\t"`,
   126  			tokens: []jsonToken{{t: jttString, v: "abc �\t"}},
   127  		},
   128  		{
   129  			desc: "valid literal--true", input: "true",
   130  			tokens: []jsonToken{{t: jttBool, v: true}},
   131  		},
   132  		{
   133  			desc: "valid literal--false", input: "false",
   134  			tokens: []jsonToken{{t: jttBool, v: false}},
   135  		},
   136  		{
   137  			desc: "valid literal--null", input: "null",
   138  			tokens: []jsonToken{{t: jttNull}},
   139  		},
   140  		{
   141  			desc: "valid int32: 0", input: "0",
   142  			tokens: []jsonToken{{t: jttInt32, v: int32(0)}},
   143  		},
   144  		{
   145  			desc: "valid int32: -0", input: "-0",
   146  			tokens: []jsonToken{{t: jttInt32, v: int32(0)}},
   147  		},
   148  		{
   149  			desc: "valid int32: 1", input: "1",
   150  			tokens: []jsonToken{{t: jttInt32, v: int32(1)}},
   151  		},
   152  		{
   153  			desc: "valid int32: -1", input: "-1",
   154  			tokens: []jsonToken{{t: jttInt32, v: int32(-1)}},
   155  		},
   156  		{
   157  			desc: "valid int32: 10", input: "10",
   158  			tokens: []jsonToken{{t: jttInt32, v: int32(10)}},
   159  		},
   160  		{
   161  			desc: "valid int32: 1234", input: "1234",
   162  			tokens: []jsonToken{{t: jttInt32, v: int32(1234)}},
   163  		},
   164  		{
   165  			desc: "valid int32: -10", input: "-10",
   166  			tokens: []jsonToken{{t: jttInt32, v: int32(-10)}},
   167  		},
   168  		{
   169  			desc: "valid int32: -1234", input: "-1234",
   170  			tokens: []jsonToken{{t: jttInt32, v: int32(-1234)}},
   171  		},
   172  		{
   173  			desc: "valid int64: 2147483648", input: "2147483648",
   174  			tokens: []jsonToken{{t: jttInt64, v: int64(2147483648)}},
   175  		},
   176  		{
   177  			desc: "valid int64: -2147483649", input: "-2147483649",
   178  			tokens: []jsonToken{{t: jttInt64, v: int64(-2147483649)}},
   179  		},
   180  		{
   181  			desc: "valid double: 0.0", input: "0.0",
   182  			tokens: []jsonToken{{t: jttDouble, v: 0.0}},
   183  		},
   184  		{
   185  			desc: "valid double: -0.0", input: "-0.0",
   186  			tokens: []jsonToken{{t: jttDouble, v: 0.0}},
   187  		},
   188  		{
   189  			desc: "valid double: 0.1", input: "0.1",
   190  			tokens: []jsonToken{{t: jttDouble, v: 0.1}},
   191  		},
   192  		{
   193  			desc: "valid double: 0.1234", input: "0.1234",
   194  			tokens: []jsonToken{{t: jttDouble, v: 0.1234}},
   195  		},
   196  		{
   197  			desc: "valid double: 1.0", input: "1.0",
   198  			tokens: []jsonToken{{t: jttDouble, v: 1.0}},
   199  		},
   200  		{
   201  			desc: "valid double: -1.0", input: "-1.0",
   202  			tokens: []jsonToken{{t: jttDouble, v: -1.0}},
   203  		},
   204  		{
   205  			desc: "valid double: 1.234", input: "1.234",
   206  			tokens: []jsonToken{{t: jttDouble, v: 1.234}},
   207  		},
   208  		{
   209  			desc: "valid double: -1.234", input: "-1.234",
   210  			tokens: []jsonToken{{t: jttDouble, v: -1.234}},
   211  		},
   212  		{
   213  			desc: "valid double: 1e10", input: "1e10",
   214  			tokens: []jsonToken{{t: jttDouble, v: 1e+10}},
   215  		},
   216  		{
   217  			desc: "valid double: 1E10", input: "1E10",
   218  			tokens: []jsonToken{{t: jttDouble, v: 1e+10}},
   219  		},
   220  		{
   221  			desc: "valid double: 1.2e10", input: "1.2e10",
   222  			tokens: []jsonToken{{t: jttDouble, v: 1.2e+10}},
   223  		},
   224  		{
   225  			desc: "valid double: 1.2E10", input: "1.2E10",
   226  			tokens: []jsonToken{{t: jttDouble, v: 1.2e+10}},
   227  		},
   228  		{
   229  			desc: "valid double: -1.2e10", input: "-1.2e10",
   230  			tokens: []jsonToken{{t: jttDouble, v: -1.2e+10}},
   231  		},
   232  		{
   233  			desc: "valid double: -1.2E10", input: "-1.2E10",
   234  			tokens: []jsonToken{{t: jttDouble, v: -1.2e+10}},
   235  		},
   236  		{
   237  			desc: "valid double: -1.2e+10", input: "-1.2e+10",
   238  			tokens: []jsonToken{{t: jttDouble, v: -1.2e+10}},
   239  		},
   240  		{
   241  			desc: "valid double: -1.2E+10", input: "-1.2E+10",
   242  			tokens: []jsonToken{{t: jttDouble, v: -1.2e+10}},
   243  		},
   244  		{
   245  			desc: "valid double: 1.2e-10", input: "1.2e-10",
   246  			tokens: []jsonToken{{t: jttDouble, v: 1.2e-10}},
   247  		},
   248  		{
   249  			desc: "valid double: 1.2E-10", input: "1.2e-10",
   250  			tokens: []jsonToken{{t: jttDouble, v: 1.2e-10}},
   251  		},
   252  		{
   253  			desc: "valid double: -1.2e-10", input: "-1.2e-10",
   254  			tokens: []jsonToken{{t: jttDouble, v: -1.2e-10}},
   255  		},
   256  		{
   257  			desc: "valid double: -1.2E-10", input: "-1.2E-10",
   258  			tokens: []jsonToken{{t: jttDouble, v: -1.2e-10}},
   259  		},
   260  		{
   261  			desc: "valid double: 8005332285744496613785600", input: "8005332285744496613785600",
   262  			tokens: []jsonToken{{t: jttDouble, v: float64(8005332285744496613785600)}},
   263  		},
   264  		{
   265  			desc:  "valid object, only spaces",
   266  			input: `{"key": "string", "key2": 2, "key3": {}, "key4": [], "key5": false }`,
   267  			tokens: []jsonToken{
   268  				{t: jttBeginObject, v: byte('{')}, {t: jttString, v: "key"}, {t: jttColon, v: byte(':')}, {t: jttString, v: "string"},
   269  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key2"}, {t: jttColon, v: byte(':')}, {t: jttInt32, v: int32(2)},
   270  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key3"}, {t: jttColon, v: byte(':')}, {t: jttBeginObject, v: byte('{')}, {t: jttEndObject, v: byte('}')},
   271  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key4"}, {t: jttColon, v: byte(':')}, {t: jttBeginArray, v: byte('[')}, {t: jttEndArray, v: byte(']')},
   272  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key5"}, {t: jttColon, v: byte(':')}, {t: jttBool, v: false}, {t: jttEndObject, v: byte('}')},
   273  			},
   274  		},
   275  		{
   276  			desc: "valid object, mixed whitespace",
   277  			input: `
   278  					{ "key" : "string"
   279  					, "key2": 2
   280  					, "key3": {}
   281  					, "key4": []
   282  					, "key5": false
   283  					}`,
   284  			tokens: []jsonToken{
   285  				{t: jttBeginObject, v: byte('{')}, {t: jttString, v: "key"}, {t: jttColon, v: byte(':')}, {t: jttString, v: "string"},
   286  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key2"}, {t: jttColon, v: byte(':')}, {t: jttInt32, v: int32(2)},
   287  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key3"}, {t: jttColon, v: byte(':')}, {t: jttBeginObject, v: byte('{')}, {t: jttEndObject, v: byte('}')},
   288  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key4"}, {t: jttColon, v: byte(':')}, {t: jttBeginArray, v: byte('[')}, {t: jttEndArray, v: byte(']')},
   289  				{t: jttComma, v: byte(',')}, {t: jttString, v: "key5"}, {t: jttColon, v: byte(':')}, {t: jttBool, v: false}, {t: jttEndObject, v: byte('}')},
   290  			},
   291  		},
   292  		{
   293  			desc:  "input greater than buffer size",
   294  			input: `{"` + longKey + `": 1}`,
   295  			tokens: []jsonToken{
   296  				{t: jttBeginObject, v: byte('{')}, {t: jttString, v: longKey}, {t: jttColon, v: byte(':')},
   297  				{t: jttInt32, v: int32(1)}, {t: jttEndObject, v: byte('}')},
   298  			},
   299  		},
   300  	}
   301  
   302  	for _, tc := range cases {
   303  		t.Run(tc.desc, func(t *testing.T) {
   304  			js := &jsonScanner{r: strings.NewReader(tc.input)}
   305  
   306  			for _, token := range tc.tokens {
   307  				c, err := js.nextToken()
   308  				expectNoError(t, err, tc.desc)
   309  				jttDiff(t, token.t, c.t, tc.desc)
   310  				jtvDiff(t, token.v, c.v, tc.desc)
   311  			}
   312  
   313  			c, err := js.nextToken()
   314  			noerr(t, err)
   315  			jttDiff(t, jttEOF, c.t, tc.desc)
   316  
   317  			// testing early EOF reading
   318  			js = &jsonScanner{r: iotest.DataErrReader(strings.NewReader(tc.input))}
   319  
   320  			for _, token := range tc.tokens {
   321  				c, err := js.nextToken()
   322  				expectNoError(t, err, tc.desc)
   323  				jttDiff(t, token.t, c.t, tc.desc)
   324  				jtvDiff(t, token.v, c.v, tc.desc)
   325  			}
   326  
   327  			c, err = js.nextToken()
   328  			noerr(t, err)
   329  			jttDiff(t, jttEOF, c.t, tc.desc)
   330  		})
   331  	}
   332  }
   333  
   334  func TestJsonScannerInvalidInputs(t *testing.T) {
   335  	cases := []jsonScannerTestCase{
   336  		{desc: "missing quotation", input: `"missing`},
   337  		{desc: "invalid escape character--first character", input: `"\invalid"`},
   338  		{desc: "invalid escape character--middle", input: `"i\nv\alid"`},
   339  		{desc: "invalid escape character--single quote", input: `"f\'oo"`},
   340  		{desc: "invalid literal--trueee", input: "trueee"},
   341  		{desc: "invalid literal--tire", input: "tire"},
   342  		{desc: "invalid literal--nulll", input: "nulll"},
   343  		{desc: "invalid literal--fals", input: "fals"},
   344  		{desc: "invalid literal--falsee", input: "falsee"},
   345  		{desc: "invalid literal--fake", input: "fake"},
   346  		{desc: "invalid literal--bad", input: "bad"},
   347  		{desc: "invalid number: -", input: "-"},
   348  		{desc: "invalid number: --0", input: "--0"},
   349  		{desc: "invalid number: -a", input: "-a"},
   350  		{desc: "invalid number: 00", input: "00"},
   351  		{desc: "invalid number: 01", input: "01"},
   352  		{desc: "invalid number: 0-", input: "0-"},
   353  		{desc: "invalid number: 1-", input: "1-"},
   354  		{desc: "invalid number: 0..", input: "0.."},
   355  		{desc: "invalid number: 0.-", input: "0.-"},
   356  		{desc: "invalid number: 0..0", input: "0..0"},
   357  		{desc: "invalid number: 0.1.0", input: "0.1.0"},
   358  		{desc: "invalid number: 0e", input: "0e"},
   359  		{desc: "invalid number: 0e.", input: "0e."},
   360  		{desc: "invalid number: 0e1.", input: "0e1."},
   361  		{desc: "invalid number: 0e1e", input: "0e1e"},
   362  		{desc: "invalid number: 0e+.1", input: "0e+.1"},
   363  		{desc: "invalid number: 0e+1.", input: "0e+1."},
   364  		{desc: "invalid number: 0e+1e", input: "0e+1e"},
   365  	}
   366  
   367  	for _, tc := range cases {
   368  		t.Run(tc.desc, func(t *testing.T) {
   369  			js := &jsonScanner{r: strings.NewReader(tc.input)}
   370  
   371  			c, err := js.nextToken()
   372  			expectNilToken(t, c, tc.desc)
   373  			expectError(t, err, tc.desc)
   374  		})
   375  	}
   376  }
   377  

View as plain text