github.com/searKing/golang/go@v1.2.117/encoding/prettyjson/scanner_test.go (about) 1 // Copyright 2023 The searKing Author. 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 prettyjson 6 7 import ( 8 "bytes" 9 "math" 10 "math/rand" 11 "testing" 12 ) 13 14 var validTests = []struct { 15 data string 16 ok bool 17 }{ 18 {`foo`, false}, 19 {`}{`, false}, 20 {`{]`, false}, 21 {`{}`, true}, 22 {`{"foo":"bar"}`, true}, 23 {`{"foo":"bar","bar":{"baz":["qux"]}}`, true}, 24 } 25 26 func TestValid(t *testing.T) { 27 for _, tt := range validTests { 28 if ok := Valid([]byte(tt.data)); ok != tt.ok { 29 t.Errorf("Valid(%#q) = %v, want %v", tt.data, ok, tt.ok) 30 } 31 } 32 } 33 34 // Tests of simple examples. 35 36 type example struct { 37 compact string 38 indent string 39 } 40 41 var examples = []example{ 42 {`1`, `1`}, 43 {`{}`, `{}`}, 44 {`[]`, `[]`}, 45 {`{"":2}`, "{\n\t\"\": 2\n}"}, 46 {`[3]`, "[\n\t3\n]"}, 47 {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"}, 48 {`{"x":1}`, "{\n\t\"x\": 1\n}"}, 49 {ex1, ex1i}, 50 {"{\"\":\"<>&\u2028\u2029\"}", "{\n\t\"\": \"<>&\u2028\u2029\"\n}"}, // See golang.org/issue/34070 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 func diff(t *testing.T, a, b []byte) { 181 for i := 0; ; i++ { 182 if i >= len(a) || i >= len(b) || a[i] != b[i] { 183 j := i - 10 184 if j < 0 { 185 j = 0 186 } 187 t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:])) 188 return 189 } 190 } 191 } 192 193 func trim(b []byte) []byte { 194 if len(b) > 20 { 195 return b[0:20] 196 } 197 return b 198 } 199 200 // Generate a random JSON object. 201 202 var jsonBig []byte 203 204 func initBig() { 205 n := 10000 206 if testing.Short() { 207 n = 100 208 } 209 b, err := Marshal(genValue(n)) 210 if err != nil { 211 panic(err) 212 } 213 jsonBig = b 214 } 215 216 func genValue(n int) any { 217 if n > 1 { 218 switch rand.Intn(2) { 219 case 0: 220 return genArray(n) 221 case 1: 222 return genMap(n) 223 } 224 } 225 switch rand.Intn(3) { 226 case 0: 227 return rand.Intn(2) == 0 228 case 1: 229 return rand.NormFloat64() 230 case 2: 231 return genString(30) 232 } 233 panic("unreachable") 234 } 235 236 func genString(stddev float64) string { 237 n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2)) 238 c := make([]rune, n) 239 for i := range c { 240 f := math.Abs(rand.NormFloat64()*64 + 32) 241 if f > 0x10ffff { 242 f = 0x10ffff 243 } 244 c[i] = rune(f) 245 } 246 return string(c) 247 } 248 249 func genArray(n int) []any { 250 f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 251 if f > n { 252 f = n 253 } 254 if f < 1 { 255 f = 1 256 } 257 x := make([]any, f) 258 for i := range x { 259 x[i] = genValue(((i+1)*n)/f - (i*n)/f) 260 } 261 return x 262 } 263 264 func genMap(n int) map[string]any { 265 f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) 266 if f > n { 267 f = n 268 } 269 if n > 0 && f == 0 { 270 f = 1 271 } 272 x := make(map[string]any) 273 for i := 0; i < f; i++ { 274 x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f) 275 } 276 return x 277 }