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