The Go Programming Language

Source file src/pkg/json/scanner_test.go

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.