Black Lives Matter. Support the Equal Justice Initiative.

Source file src/encoding/json/scanner_test.go

Documentation: encoding/json

     1  // Copyright 2010 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  package json
     6  
     7  import (
     8  	"bytes"
     9  	"math"
    10  	"math/rand"
    11  	"reflect"
    12  	"testing"
    13  )
    14  
    15  var validTests = []struct {
    16  	data string
    17  	ok   bool
    18  }{
    19  	{`foo`, false},
    20  	{`}{`, false},
    21  	{`{]`, false},
    22  	{`{}`, true},
    23  	{`{"foo":"bar"}`, true},
    24  	{`{"foo":"bar","bar":{"baz":["qux"]}}`, true},
    25  }
    26  
    27  func TestValid(t *testing.T) {
    28  	for _, tt := range validTests {
    29  		if ok := Valid([]byte(tt.data)); ok != tt.ok {
    30  			t.Errorf("Valid(%#q) = %v, want %v", tt.data, ok, tt.ok)
    31  		}
    32  	}
    33  }
    34  
    35  // Tests of simple examples.
    36  
    37  type example struct {
    38  	compact string
    39  	indent  string
    40  }
    41  
    42  var examples = []example{
    43  	{`1`, `1`},
    44  	{`{}`, `{}`},
    45  	{`[]`, `[]`},
    46  	{`{"":2}`, "{\n\t\"\": 2\n}"},
    47  	{`[3]`, "[\n\t3\n]"},
    48  	{`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
    49  	{`{"x":1}`, "{\n\t\"x\": 1\n}"},
    50  	{ex1, ex1i},
    51  	{"{\"\":\"<>&\u2028\u2029\"}", "{\n\t\"\": \"<>&\u2028\u2029\"\n}"}, // See golang.org/issue/34070
    52  }
    53  
    54  var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
    55  
    56  var ex1i = `[
    57  	true,
    58  	false,
    59  	null,
    60  	"x",
    61  	1,
    62  	1.5,
    63  	0,
    64  	-5e+2
    65  ]`
    66  
    67  func TestCompact(t *testing.T) {
    68  	var buf bytes.Buffer
    69  	for _, tt := range examples {
    70  		buf.Reset()
    71  		if err := Compact(&buf, []byte(tt.compact)); err != nil {
    72  			t.Errorf("Compact(%#q): %v", tt.compact, err)
    73  		} else if s := buf.String(); s != tt.compact {
    74  			t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
    75  		}
    76  
    77  		buf.Reset()
    78  		if err := Compact(&buf, []byte(tt.indent)); err != nil {
    79  			t.Errorf("Compact(%#q): %v", tt.indent, err)
    80  			continue
    81  		} else if s := buf.String(); s != tt.compact {
    82  			t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
    83  		}
    84  	}
    85  }
    86  
    87  func TestCompactSeparators(t *testing.T) {
    88  	// U+2028 and U+2029 should be escaped inside strings.
    89  	// They should not appear outside strings.
    90  	tests := []struct {
    91  		in, compact string
    92  	}{
    93  		{"{\"\u2028\": 1}", "{\"\u2028\":1}"},
    94  		{"{\"\u2029\" :2}", "{\"\u2029\":2}"},
    95  	}
    96  	for _, tt := range tests {
    97  		var buf bytes.Buffer
    98  		if err := Compact(&buf, []byte(tt.in)); err != nil {
    99  			t.Errorf("Compact(%q): %v", tt.in, err)
   100  		} else if s := buf.String(); s != tt.compact {
   101  			t.Errorf("Compact(%q) = %q, want %q", tt.in, s, tt.compact)
   102  		}
   103  	}
   104  }
   105  
   106  func TestIndent(t *testing.T) {
   107  	var buf bytes.Buffer
   108  	for _, tt := range examples {
   109  		buf.Reset()
   110  		if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
   111  			t.Errorf("Indent(%#q): %v", tt.indent, err)
   112  		} else if s := buf.String(); s != tt.indent {
   113  			t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
   114  		}
   115  
   116  		buf.Reset()
   117  		if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
   118  			t.Errorf("Indent(%#q): %v", tt.compact, err)
   119  			continue
   120  		} else if s := buf.String(); s != tt.indent {
   121  			t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
   122  		}
   123  	}
   124  }
   125  
   126  // Tests of a large random structure.
   127  
   128  func TestCompactBig(t *testing.T) {
   129  	initBig()
   130  	var buf bytes.Buffer
   131  	if err := Compact(&buf, jsonBig); err != nil {
   132  		t.Fatalf("Compact: %v", err)
   133  	}
   134  	b := buf.Bytes()
   135  	if !bytes.Equal(b, jsonBig) {
   136  		t.Error("Compact(jsonBig) != jsonBig")
   137  		diff(t, b, jsonBig)
   138  		return
   139  	}
   140  }
   141  
   142  func TestIndentBig(t *testing.T) {
   143  	t.Parallel()
   144  	initBig()
   145  	var buf bytes.Buffer
   146  	if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
   147  		t.Fatalf("Indent1: %v", err)
   148  	}
   149  	b := buf.Bytes()
   150  	if len(b) == len(jsonBig) {
   151  		// jsonBig is compact (no unnecessary spaces);
   152  		// indenting should make it bigger
   153  		t.Fatalf("Indent(jsonBig) did not get bigger")
   154  	}
   155  
   156  	// should be idempotent
   157  	var buf1 bytes.Buffer
   158  	if err := Indent(&buf1, b, "", "\t"); err != nil {
   159  		t.Fatalf("Indent2: %v", err)
   160  	}
   161  	b1 := buf1.Bytes()
   162  	if !bytes.Equal(b1, b) {
   163  		t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
   164  		diff(t, b1, b)
   165  		return
   166  	}
   167  
   168  	// should get back to original
   169  	buf1.Reset()
   170  	if err := Compact(&buf1, b); err != nil {
   171  		t.Fatalf("Compact: %v", err)
   172  	}
   173  	b1 = buf1.Bytes()
   174  	if !bytes.Equal(b1, jsonBig) {
   175  		t.Error("Compact(Indent(jsonBig)) != jsonBig")
   176  		diff(t, b1, jsonBig)
   177  		return
   178  	}
   179  }
   180  
   181  type indentErrorTest struct {
   182  	in  string
   183  	err error
   184  }
   185  
   186  var indentErrorTests = []indentErrorTest{
   187  	{`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
   188  	{`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
   189  }
   190  
   191  func TestIndentErrors(t *testing.T) {
   192  	for i, tt := range indentErrorTests {
   193  		slice := make([]uint8, 0)
   194  		buf := bytes.NewBuffer(slice)
   195  		if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
   196  			if !reflect.DeepEqual(err, tt.err) {
   197  				t.Errorf("#%d: Indent: %#v", i, err)
   198  				continue
   199  			}
   200  		}
   201  	}
   202  }
   203  
   204  func diff(t *testing.T, a, b []byte) {
   205  	for i := 0; ; i++ {
   206  		if i >= len(a) || i >= len(b) || a[i] != b[i] {
   207  			j := i - 10
   208  			if j < 0 {
   209  				j = 0
   210  			}
   211  			t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
   212  			return
   213  		}
   214  	}
   215  }
   216  
   217  func trim(b []byte) []byte {
   218  	if len(b) > 20 {
   219  		return b[0:20]
   220  	}
   221  	return b
   222  }
   223  
   224  // Generate a random JSON object.
   225  
   226  var jsonBig []byte
   227  
   228  func initBig() {
   229  	n := 10000
   230  	if testing.Short() {
   231  		n = 100
   232  	}
   233  	b, err := Marshal(genValue(n))
   234  	if err != nil {
   235  		panic(err)
   236  	}
   237  	jsonBig = b
   238  }
   239  
   240  func genValue(n int) interface{} {
   241  	if n > 1 {
   242  		switch rand.Intn(2) {
   243  		case 0:
   244  			return genArray(n)
   245  		case 1:
   246  			return genMap(n)
   247  		}
   248  	}
   249  	switch rand.Intn(3) {
   250  	case 0:
   251  		return rand.Intn(2) == 0
   252  	case 1:
   253  		return rand.NormFloat64()
   254  	case 2:
   255  		return genString(30)
   256  	}
   257  	panic("unreachable")
   258  }
   259  
   260  func genString(stddev float64) string {
   261  	n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
   262  	c := make([]rune, n)
   263  	for i := range c {
   264  		f := math.Abs(rand.NormFloat64()*64 + 32)
   265  		if f > 0x10ffff {
   266  			f = 0x10ffff
   267  		}
   268  		c[i] = rune(f)
   269  	}
   270  	return string(c)
   271  }
   272  
   273  func genArray(n int) []interface{} {
   274  	f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
   275  	if f > n {
   276  		f = n
   277  	}
   278  	if f < 1 {
   279  		f = 1
   280  	}
   281  	x := make([]interface{}, f)
   282  	for i := range x {
   283  		x[i] = genValue(((i+1)*n)/f - (i*n)/f)
   284  	}
   285  	return x
   286  }
   287  
   288  func genMap(n int) map[string]interface{} {
   289  	f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
   290  	if f > n {
   291  		f = n
   292  	}
   293  	if n > 0 && f == 0 {
   294  		f = 1
   295  	}
   296  	x := make(map[string]interface{})
   297  	for i := 0; i < f; i++ {
   298  		x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
   299  	}
   300  	return x
   301  }
   302  

View as plain text