github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/internal/encoder/assembler_test.go (about) 1 /* 2 * Copyright 2021 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package encoder 18 19 import ( 20 `encoding/hex` 21 `encoding/json` 22 `math` 23 `reflect` 24 `runtime` 25 `strings` 26 `testing` 27 `unsafe` 28 29 `github.com/bytedance/sonic/option` 30 `github.com/bytedance/sonic/internal/rt` 31 `github.com/davecgh/go-spew/spew` 32 `github.com/stretchr/testify/assert` 33 ) 34 35 func TestEncoderMemoryCorruption(t *testing.T) { 36 println("TestEncoderMemoryCorruption") 37 runtime.GC() 38 var m = map[string]interface{}{ 39 "1": map[string]interface{} { 40 `"`+strings.Repeat("a", int(option.DefaultEncoderBufferSize) - 38)+`"`: "b", 41 "1": map[string]int32{ 42 "b": 1658219785, 43 }, 44 }, 45 } 46 out, err := Encode(m, SortMapKeys) 47 if err != nil { 48 t.Fatal(err) 49 } 50 println(len(out)) 51 if err := json.Unmarshal(out, &m); err != nil { 52 t.Fatal(err) 53 } 54 } 55 56 func TestAssembler_CompileAndLoad(t *testing.T) { 57 p, err := newCompiler().compile(reflect.TypeOf((*bool)(nil)), true) 58 assert.Nil(t, err) 59 a := newAssembler(p) 60 f := a.Load() 61 s := newStack() 62 b := []byte(nil) 63 64 /* true */ 65 v := true 66 u := &v 67 e := f(&b, unsafe.Pointer(&u), s, 0) 68 assert.Nil(t, e) 69 println(cap(b)) 70 println(hex.Dump(b)) 71 72 /* false */ 73 v = false 74 u = &v 75 b = b[:0] 76 e = f(&b, unsafe.Pointer(&u), s, 0) 77 assert.Nil(t, e) 78 println(cap(b)) 79 println(hex.Dump(b)) 80 81 /* nil */ 82 u = nil 83 b = b[:0] 84 e = f(&b, unsafe.Pointer(&u), s, 0) 85 assert.Nil(t, e) 86 println(cap(b)) 87 println(hex.Dump(b)) 88 } 89 90 type testOps struct { 91 key string 92 ins _Program 93 exp string 94 err error 95 val interface{} 96 } 97 98 func testOpCode(t *testing.T, v interface{}, ex string, err error, ins _Program) { 99 p := ins 100 m := []byte(nil) 101 s := new(_Stack) 102 a := newAssembler(p) 103 f := a.Load() 104 e := f(&m, rt.UnpackEface(v).Value, s, 0) 105 if err != nil { 106 assert.EqualError(t, e, err.Error()) 107 } else { 108 assert.Nil(t, e) 109 assert.Equal(t, ex, string(m)) 110 } 111 } 112 113 type IfaceValue int 114 func (IfaceValue) Error() string { 115 return "not really implemented" 116 } 117 118 type JsonMarshalerValue int 119 func (JsonMarshalerValue) MarshalJSON() ([]byte, error) { 120 return []byte("123456789"), nil 121 } 122 123 type RecursiveValue struct { 124 A int `json:"a"` 125 P *RecursiveValue `json:"p,omitempty"` 126 Q []RecursiveValue `json:"q"` 127 R map[string]RecursiveValue `json:"r"` 128 Z int `json:"z"` 129 } 130 131 func mustCompile(t interface{}) _Program { 132 p, err := newCompiler().compile(reflect.TypeOf(t), !rt.UnpackEface(t).Type.Indirect()) 133 if err != nil { 134 panic(err) 135 } 136 return p 137 } 138 139 func TestAssembler_OpCode(t *testing.T) { 140 var iface error = IfaceValue(12345) 141 var eface interface{} = 12345 142 var jval = new(JsonMarshalerValue) 143 var jifv json.Marshaler = JsonMarshalerValue(0) 144 var jifp json.Marshaler = jval 145 var rec = &RecursiveValue { 146 A: 123, 147 Z: 456, 148 P: &RecursiveValue { 149 A: 789, 150 Z: 666, 151 P: &RecursiveValue { 152 A: 777, 153 Z: 888, 154 Q: []RecursiveValue {{ 155 A: 999, 156 Z: 222, 157 R: map[string]RecursiveValue { 158 "xxx": { 159 A: 333, 160 }, 161 }, 162 }}, 163 }, 164 }, 165 } 166 tests := []testOps { 167 { 168 key: "_OP_null", 169 ins: []_Instr{newInsOp(_OP_null)}, 170 exp: "null", 171 val: nil, 172 }, { 173 key: "_OP_bool/true", 174 ins: []_Instr{newInsOp(_OP_bool)}, 175 exp: "true", 176 val: true, 177 }, { 178 key: "_OP_bool/false", 179 ins: []_Instr{newInsOp(_OP_bool)}, 180 exp: "false", 181 val: false, 182 }, { 183 key: "_OP_i8", 184 ins: []_Instr{newInsOp(_OP_i8)}, 185 exp: "-128", 186 val: int8(-128), 187 }, { 188 key: "_OP_i16", 189 ins: []_Instr{newInsOp(_OP_i16)}, 190 exp: "-32768", 191 val: int16(-32768), 192 }, { 193 key: "_OP_i32", 194 ins: []_Instr{newInsOp(_OP_i32)}, 195 exp: "-2147483648", 196 val: int32(-2147483648), 197 }, { 198 key: "_OP_i64", 199 ins: []_Instr{newInsOp(_OP_i64)}, 200 exp: "-9223372036854775808", 201 val: int64(math.MinInt64), 202 }, { 203 key: "_OP_u8", 204 ins: []_Instr{newInsOp(_OP_u8)}, 205 exp: "255", 206 val: uint8(255), 207 }, { 208 key: "_OP_u16", 209 ins: []_Instr{newInsOp(_OP_u16)}, 210 exp: "65535", 211 val: uint16(65535), 212 }, { 213 key: "_OP_u32", 214 ins: []_Instr{newInsOp(_OP_u32)}, 215 exp: "4294967295", 216 val: uint32(4294967295), 217 }, { 218 key: "_OP_u64", 219 ins: []_Instr{newInsOp(_OP_u64)}, 220 exp: "18446744073709551615", 221 val: uint64(18446744073709551615), 222 }, { 223 key: "_OP_f32", 224 ins: []_Instr{newInsOp(_OP_f32)}, 225 exp: "-12.5", 226 val: float32(-12.5), 227 }, { 228 key: "_OP_f32/nan", 229 ins: []_Instr{newInsOp(_OP_f32)}, 230 err: _ERR_nan_or_infinite, 231 val: float32(math.NaN()), 232 }, { 233 key: "_OP_f32/+inf", 234 ins: []_Instr{newInsOp(_OP_f32)}, 235 err: _ERR_nan_or_infinite, 236 val: float32(math.Inf(1)), 237 }, { 238 key: "_OP_f32/-inf", 239 ins: []_Instr{newInsOp(_OP_f32)}, 240 err: _ERR_nan_or_infinite, 241 val: float32(math.Inf(-1)), 242 }, { 243 key: "_OP_f64", 244 ins: []_Instr{newInsOp(_OP_f64)}, 245 exp: "-2.2250738585072014e-308", 246 val: -2.2250738585072014e-308, 247 }, { 248 key: "_OP_f64/nan", 249 ins: []_Instr{newInsOp(_OP_f64)}, 250 err: _ERR_nan_or_infinite, 251 val: math.NaN(), 252 }, { 253 key: "_OP_f64/+inf", 254 ins: []_Instr{newInsOp(_OP_f64)}, 255 err: _ERR_nan_or_infinite, 256 val: math.Inf(1), 257 }, { 258 key: "_OP_f64/-inf", 259 ins: []_Instr{newInsOp(_OP_f64)}, 260 err: _ERR_nan_or_infinite, 261 val: math.Inf(-1), 262 }, { 263 key: "_OP_str", 264 ins: []_Instr{newInsOp(_OP_str)}, 265 exp: `"Cartoonist, Illustrator, and T-Shirt connoisseur"`, 266 val: "Cartoonist, Illustrator, and T-Shirt connoisseur", 267 }, { 268 key: "_OP_str/empty", 269 ins: []_Instr{newInsOp(_OP_str)}, 270 exp: `""`, 271 val: "", 272 }, { 273 key: "_OP_bin", 274 ins: []_Instr{newInsOp(_OP_bin)}, 275 exp: `"AQIDBAU="`, 276 val: []byte{1, 2, 3, 4, 5}, 277 }, { 278 key: "_OP_bin/empty", 279 ins: []_Instr{newInsOp(_OP_bin)}, 280 exp: `""`, 281 val: []byte{}, 282 }, { 283 key: "_OP_quote", 284 ins: []_Instr{newInsOp(_OP_quote)}, 285 exp: `"\"test\""`, 286 val: "test", 287 }, { 288 key: "_OP_quote/escape", 289 ins: []_Instr{newInsOp(_OP_quote)}, 290 exp: `"\"hello\\n\\t\\rworld\""`, 291 val: "hello\n\t\rworld", 292 }, { 293 key: "_OP_number", 294 ins: []_Instr{newInsOp(_OP_number)}, 295 exp: "1.2345", 296 val: "1.2345", 297 }, { 298 key: "_OP_number/invalid", 299 ins: []_Instr{newInsOp(_OP_number)}, 300 err: error_number("not a number"), 301 val: "not a number", 302 }, { 303 key: "_OP_eface", 304 ins: []_Instr{newInsOp(_OP_eface)}, 305 exp: `12345`, 306 val: &eface, 307 }, { 308 key: "_OP_iface", 309 ins: []_Instr{newInsOp(_OP_iface)}, 310 exp: `12345`, 311 val: &iface, 312 }, { 313 key: "_OP_byte", 314 ins: []_Instr{newInsVi(_OP_byte, 'x')}, 315 exp: "x", 316 val: nil, 317 }, { 318 key: "_OP_text", 319 ins: []_Instr{newInsVs(_OP_text, "hello, world !!")}, 320 exp: "hello, world !!", 321 val: nil, 322 }, { 323 key: "_OP_map_[iter,next,value]", 324 ins: mustCompile(map[string]map[int64]int{}), 325 exp: `{"asdf":{"-9223372036854775808":1234}}`, 326 val: &map[string]map[int64]int{"asdf": {math.MinInt64: 1234}}, 327 }, { 328 key: "_OP_slice_[len,next]", 329 ins: mustCompile([][]int{}), 330 exp: `[[1,2,3],[4,5,6]]`, 331 val: &[][]int{{1, 2, 3}, {4, 5, 6}}, 332 }, { 333 key: "_OP_marshal[_text]", 334 ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(JsonMarshalerValue(0)))}, 335 exp: "123456789", 336 val: new(JsonMarshalerValue), 337 }, { 338 key: "_OP_marshal[_text]/ptr", 339 ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(new(JsonMarshalerValue)))}, 340 exp: "123456789", 341 val: &jval, 342 }, { 343 key: "_OP_marshal[_text]/iface_v", 344 ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)}, 345 exp: "123456789", 346 val: &jifv, 347 }, { 348 key: "_OP_marshal[_text]/iface_p", 349 ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)}, 350 exp: "123456789", 351 val: &jifp, 352 }, 353 { 354 key: "_OP_recurse", 355 ins: mustCompile(rec), 356 exp: `{"a":123,"p":{"a":789,"p":{"a":777,"q":[{"a":999,"q":null,"r":{"` + 357 `xxx":{"a":333,"q":null,"r":null,"z":0}},"z":222}],"r":null,"z":8` + 358 `88},"q":null,"r":null,"z":666},"q":null,"r":null,"z":456}`, 359 val: &rec, 360 }} 361 for _, tv := range tests { 362 t.Run(tv.key, func(t *testing.T) { 363 testOpCode(t, tv.val, tv.exp, tv.err, tv.ins) 364 }) 365 } 366 } 367 368 func TestAssembler_StringMoreSpace(t *testing.T) { 369 p := _Program{newInsOp(_OP_str)} 370 m := make([]byte, 0, 8) 371 s := new(_Stack) 372 a := newAssembler(p) 373 f := a.Load() 374 v := "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u0010" 375 e := f(&m, unsafe.Pointer(&v), s, 0) 376 assert.Nil(t, e) 377 spew.Dump(m) 378 } 379 380 func TestAssembler_TwitterJSON_Generic(t *testing.T) { 381 p := mustCompile(&_GenericValue) 382 m := []byte(nil) 383 s := new(_Stack) 384 a := newAssembler(p) 385 f := a.Load() 386 v := &_GenericValue 387 e := f(&m, unsafe.Pointer(&v), s, 0) 388 assert.Nil(t, e) 389 println(string(m)) 390 } 391 392 func TestAssembler_TwitterJSON_Structure(t *testing.T) { 393 p := mustCompile(_BindingValue) 394 m := []byte(nil) 395 s := new(_Stack) 396 a := newAssembler(p) 397 f := a.Load() 398 e := f(&m, unsafe.Pointer(&_BindingValue), s, 0) 399 assert.Nil(t, e) 400 println(string(m)) 401 runtime.KeepAlive(s) 402 } 403 404 func TestScratchedString(t *testing.T) { 405 fatal := *(*string)(unsafe.Pointer(&rt.GoString{nil, 1})) 406 defer func(){ 407 if v := recover(); v == nil { 408 t.Fatal() 409 } else if s, ok := v.(string); !ok { 410 t.Fatal(v) 411 }else{ 412 if !strings.Contains(s, "has nil pointer while its length is not zero") { 413 t.Fatal(s) 414 } 415 } 416 }() 417 _, _ = Encode(fatal, 0) 418 t.Fatal() 419 } 420 421 func TestScratchedNumber(t *testing.T) { 422 fatal := *(*json.Number)(unsafe.Pointer(&rt.GoString{nil, 1})) 423 defer func(){ 424 if v := recover(); v == nil { 425 t.Fatal() 426 } else if s, ok := v.(string); !ok { 427 t.Fatal(v) 428 }else{ 429 if !strings.Contains(s, "has nil pointer while its length is not zero") { 430 t.Fatal(s) 431 } 432 } 433 }() 434 _, _ = Encode(fatal, 0) 435 t.Fatal() 436 }