github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/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/davecgh/go-spew/spew" 30 "github.com/goshafaq/sonic/internal/rt" 31 "github.com/goshafaq/sonic/option" 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 115 func (IfaceValue) Error() string { 116 return "not really implemented" 117 } 118 119 type JsonMarshalerValue int 120 121 func (JsonMarshalerValue) MarshalJSON() ([]byte, error) { 122 return []byte("123456789"), nil 123 } 124 125 type RecursiveValue struct { 126 A int `json:"a"` 127 P *RecursiveValue `json:"p,omitempty"` 128 Q []RecursiveValue `json:"q"` 129 R map[string]RecursiveValue `json:"r"` 130 Z int `json:"z"` 131 } 132 133 func mustCompile(t interface{}) _Program { 134 p, err := newCompiler().compile(reflect.TypeOf(t), !rt.UnpackEface(t).Type.Indirect()) 135 if err != nil { 136 panic(err) 137 } 138 return p 139 } 140 141 func TestAssembler_OpCode(t *testing.T) { 142 var iface error = IfaceValue(12345) 143 var eface interface{} = 12345 144 var jval = new(JsonMarshalerValue) 145 var jifv json.Marshaler = JsonMarshalerValue(0) 146 var jifp json.Marshaler = jval 147 var rec = &RecursiveValue{ 148 A: 123, 149 Z: 456, 150 P: &RecursiveValue{ 151 A: 789, 152 Z: 666, 153 P: &RecursiveValue{ 154 A: 777, 155 Z: 888, 156 Q: []RecursiveValue{{ 157 A: 999, 158 Z: 222, 159 R: map[string]RecursiveValue{ 160 "xxx": { 161 A: 333, 162 }, 163 }, 164 }}, 165 }, 166 }, 167 } 168 tests := []testOps{ 169 { 170 key: "_OP_null", 171 ins: []_Instr{newInsOp(_OP_null)}, 172 exp: "null", 173 val: nil, 174 }, { 175 key: "_OP_bool/true", 176 ins: []_Instr{newInsOp(_OP_bool)}, 177 exp: "true", 178 val: true, 179 }, { 180 key: "_OP_bool/false", 181 ins: []_Instr{newInsOp(_OP_bool)}, 182 exp: "false", 183 val: false, 184 }, { 185 key: "_OP_i8", 186 ins: []_Instr{newInsOp(_OP_i8)}, 187 exp: "-128", 188 val: int8(-128), 189 }, { 190 key: "_OP_i16", 191 ins: []_Instr{newInsOp(_OP_i16)}, 192 exp: "-32768", 193 val: int16(-32768), 194 }, { 195 key: "_OP_i32", 196 ins: []_Instr{newInsOp(_OP_i32)}, 197 exp: "-2147483648", 198 val: int32(-2147483648), 199 }, { 200 key: "_OP_i64", 201 ins: []_Instr{newInsOp(_OP_i64)}, 202 exp: "-9223372036854775808", 203 val: int64(math.MinInt64), 204 }, { 205 key: "_OP_u8", 206 ins: []_Instr{newInsOp(_OP_u8)}, 207 exp: "255", 208 val: uint8(255), 209 }, { 210 key: "_OP_u16", 211 ins: []_Instr{newInsOp(_OP_u16)}, 212 exp: "65535", 213 val: uint16(65535), 214 }, { 215 key: "_OP_u32", 216 ins: []_Instr{newInsOp(_OP_u32)}, 217 exp: "4294967295", 218 val: uint32(4294967295), 219 }, { 220 key: "_OP_u64", 221 ins: []_Instr{newInsOp(_OP_u64)}, 222 exp: "18446744073709551615", 223 val: uint64(18446744073709551615), 224 }, { 225 key: "_OP_f32", 226 ins: []_Instr{newInsOp(_OP_f32)}, 227 exp: "-12.5", 228 val: float32(-12.5), 229 }, { 230 key: "_OP_f32/nan", 231 ins: []_Instr{newInsOp(_OP_f32)}, 232 err: _ERR_nan_or_infinite, 233 val: float32(math.NaN()), 234 }, { 235 key: "_OP_f32/+inf", 236 ins: []_Instr{newInsOp(_OP_f32)}, 237 err: _ERR_nan_or_infinite, 238 val: float32(math.Inf(1)), 239 }, { 240 key: "_OP_f32/-inf", 241 ins: []_Instr{newInsOp(_OP_f32)}, 242 err: _ERR_nan_or_infinite, 243 val: float32(math.Inf(-1)), 244 }, { 245 key: "_OP_f64", 246 ins: []_Instr{newInsOp(_OP_f64)}, 247 exp: "-2.2250738585072014e-308", 248 val: -2.2250738585072014e-308, 249 }, { 250 key: "_OP_f64/nan", 251 ins: []_Instr{newInsOp(_OP_f64)}, 252 err: _ERR_nan_or_infinite, 253 val: math.NaN(), 254 }, { 255 key: "_OP_f64/+inf", 256 ins: []_Instr{newInsOp(_OP_f64)}, 257 err: _ERR_nan_or_infinite, 258 val: math.Inf(1), 259 }, { 260 key: "_OP_f64/-inf", 261 ins: []_Instr{newInsOp(_OP_f64)}, 262 err: _ERR_nan_or_infinite, 263 val: math.Inf(-1), 264 }, { 265 key: "_OP_str", 266 ins: []_Instr{newInsOp(_OP_str)}, 267 exp: `"Cartoonist, Illustrator, and T-Shirt connoisseur"`, 268 val: "Cartoonist, Illustrator, and T-Shirt connoisseur", 269 }, { 270 key: "_OP_str/empty", 271 ins: []_Instr{newInsOp(_OP_str)}, 272 exp: `""`, 273 val: "", 274 }, { 275 key: "_OP_bin", 276 ins: []_Instr{newInsOp(_OP_bin)}, 277 exp: `"AQIDBAU="`, 278 val: []byte{1, 2, 3, 4, 5}, 279 }, { 280 key: "_OP_bin/empty", 281 ins: []_Instr{newInsOp(_OP_bin)}, 282 exp: `""`, 283 val: []byte{}, 284 }, { 285 key: "_OP_quote", 286 ins: []_Instr{newInsOp(_OP_quote)}, 287 exp: `"\"test\""`, 288 val: "test", 289 }, { 290 key: "_OP_quote/escape", 291 ins: []_Instr{newInsOp(_OP_quote)}, 292 exp: `"\"hello\\n\\t\\rworld\""`, 293 val: "hello\n\t\rworld", 294 }, { 295 key: "_OP_number", 296 ins: []_Instr{newInsOp(_OP_number)}, 297 exp: "1.2345", 298 val: "1.2345", 299 }, { 300 key: "_OP_number/invalid", 301 ins: []_Instr{newInsOp(_OP_number)}, 302 err: error_number("not a number"), 303 val: "not a number", 304 }, { 305 key: "_OP_eface", 306 ins: []_Instr{newInsOp(_OP_eface)}, 307 exp: `12345`, 308 val: &eface, 309 }, { 310 key: "_OP_iface", 311 ins: []_Instr{newInsOp(_OP_iface)}, 312 exp: `12345`, 313 val: &iface, 314 }, { 315 key: "_OP_byte", 316 ins: []_Instr{newInsVi(_OP_byte, 'x')}, 317 exp: "x", 318 val: nil, 319 }, { 320 key: "_OP_text", 321 ins: []_Instr{newInsVs(_OP_text, "hello, world !!")}, 322 exp: "hello, world !!", 323 val: nil, 324 }, { 325 key: "_OP_map_[iter,next,value]", 326 ins: mustCompile(map[string]map[int64]int{}), 327 exp: `{"asdf":{"-9223372036854775808":1234}}`, 328 val: &map[string]map[int64]int{"asdf": {math.MinInt64: 1234}}, 329 }, { 330 key: "_OP_slice_[len,next]", 331 ins: mustCompile([][]int{}), 332 exp: `[[1,2,3],[4,5,6]]`, 333 val: &[][]int{{1, 2, 3}, {4, 5, 6}}, 334 }, { 335 key: "_OP_marshal[_text]", 336 ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(JsonMarshalerValue(0)))}, 337 exp: "123456789", 338 val: new(JsonMarshalerValue), 339 }, { 340 key: "_OP_marshal[_text]/ptr", 341 ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(new(JsonMarshalerValue)))}, 342 exp: "123456789", 343 val: &jval, 344 }, { 345 key: "_OP_marshal[_text]/iface_v", 346 ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)}, 347 exp: "123456789", 348 val: &jifv, 349 }, { 350 key: "_OP_marshal[_text]/iface_p", 351 ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)}, 352 exp: "123456789", 353 val: &jifp, 354 }, 355 { 356 key: "_OP_recurse", 357 ins: mustCompile(rec), 358 exp: `{"a":123,"p":{"a":789,"p":{"a":777,"q":[{"a":999,"q":null,"r":{"` + 359 `xxx":{"a":333,"q":null,"r":null,"z":0}},"z":222}],"r":null,"z":8` + 360 `88},"q":null,"r":null,"z":666},"q":null,"r":null,"z":456}`, 361 val: &rec, 362 }} 363 for _, tv := range tests { 364 t.Run(tv.key, func(t *testing.T) { 365 testOpCode(t, tv.val, tv.exp, tv.err, tv.ins) 366 }) 367 } 368 } 369 370 func TestAssembler_StringMoreSpace(t *testing.T) { 371 p := _Program{newInsOp(_OP_str)} 372 m := make([]byte, 0, 8) 373 s := new(_Stack) 374 a := newAssembler(p) 375 f := a.Load() 376 v := "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u0010" 377 e := f(&m, unsafe.Pointer(&v), s, 0) 378 assert.Nil(t, e) 379 spew.Dump(m) 380 } 381 382 func TestAssembler_TwitterJSON_Generic(t *testing.T) { 383 p := mustCompile(&_GenericValue) 384 m := []byte(nil) 385 s := new(_Stack) 386 a := newAssembler(p) 387 f := a.Load() 388 v := &_GenericValue 389 e := f(&m, unsafe.Pointer(&v), s, 0) 390 assert.Nil(t, e) 391 println(string(m)) 392 } 393 394 func TestAssembler_TwitterJSON_Structure(t *testing.T) { 395 p := mustCompile(_BindingValue) 396 m := []byte(nil) 397 s := new(_Stack) 398 a := newAssembler(p) 399 f := a.Load() 400 e := f(&m, unsafe.Pointer(&_BindingValue), s, 0) 401 assert.Nil(t, e) 402 println(string(m)) 403 runtime.KeepAlive(s) 404 } 405 406 func TestScratchedString(t *testing.T) { 407 fatal := *(*string)(unsafe.Pointer(&rt.GoString{nil, 1})) 408 defer func() { 409 if v := recover(); v == nil { 410 t.Fatal() 411 } else if s, ok := v.(string); !ok { 412 t.Fatal(v) 413 } else { 414 if !strings.Contains(s, "has nil pointer while its length is not zero") { 415 t.Fatal(s) 416 } 417 } 418 }() 419 _, _ = Encode(fatal, 0) 420 t.Fatal() 421 } 422 423 func TestScratchedNumber(t *testing.T) { 424 fatal := *(*json.Number)(unsafe.Pointer(&rt.GoString{nil, 1})) 425 defer func() { 426 if v := recover(); v == nil { 427 t.Fatal() 428 } else if s, ok := v.(string); !ok { 429 t.Fatal(v) 430 } else { 431 if !strings.Contains(s, "has nil pointer while its length is not zero") { 432 t.Fatal(s) 433 } 434 } 435 }() 436 _, _ = Encode(fatal, 0) 437 t.Fatal() 438 }