From 7831ee28e93af6d6d1c454ea3b05c7a13a3318b1 Mon Sep 17 00:00:00 2001 From: "liuqiang.06" Date: Thu, 8 Aug 2024 15:51:38 +0800 Subject: [PATCH] chore: all fallback to encoding/json --- ast/api.go | 135 - ast/api_compat.go | 2 - ast/api_native_test.go | 208 - ast/asm.s | 0 compat.go | 2 - decode_test.go | 2817 --- decoder/decoder_compat.go | 6 - decoder/decoder_native.go | 70 - decoder/decoder_native_test.go | 278 - encode_test.go | 1227 -- encoder/encoder_compat.go | 2 - encoder/encoder_native.go | 120 - encoder/encoder_native_test.go | 120 - internal/base64/b64_amd64.go | 46 - internal/base64/b64_compat.go | 44 - internal/cpu/features.go | 40 - internal/decoder/api/decoder.go | 172 - internal/decoder/api/decoder_amd64.go | 38 - internal/decoder/api/decoder_arm64.go | 38 - internal/decoder/api/norace_test.go | 98 - internal/decoder/api/stream.go | 248 - internal/decoder/api/stream_test.go | 347 - internal/decoder/api/testdata_test.go | 551 - internal/decoder/consts/option.go | 33 - internal/decoder/errors/errors.go | 191 - internal/decoder/errors/errors_test.go | 61 - internal/decoder/errors/fuzz_test.go | 78 - internal/decoder/jitdec/asm.s | 0 .../decoder/jitdec/asm_stubs_amd64_go117.go | 126 - .../decoder/jitdec/asm_stubs_amd64_go121.go | 132 - .../decoder/jitdec/assembler_regabi_amd64.go | 1949 -- internal/decoder/jitdec/assembler_test.go | 755 - internal/decoder/jitdec/compiler.go | 1203 -- internal/decoder/jitdec/compiler_test.go | 30 - internal/decoder/jitdec/debug.go | 70 - internal/decoder/jitdec/decoder.go | 139 - .../decoder/jitdec/generic_regabi_amd64.go | 730 - .../jitdec/generic_regabi_amd64_test.s | 37 - internal/decoder/jitdec/generic_test.go | 77 - internal/decoder/jitdec/pools.go | 143 - internal/decoder/jitdec/primitives.go | 51 - internal/decoder/jitdec/stubs_go116.go | 106 - internal/decoder/jitdec/stubs_go120.go | 106 - internal/decoder/jitdec/testdata_test.go | 551 - internal/decoder/jitdec/types.go | 58 - internal/decoder/jitdec/utils.go | 39 - internal/decoder/optdec/compile_struct.go | 174 - internal/decoder/optdec/compiler.go | 449 - internal/decoder/optdec/const.go | 60 - internal/decoder/optdec/context.go | 3 - internal/decoder/optdec/decoder.go | 160 - internal/decoder/optdec/errors.go | 73 - internal/decoder/optdec/functor.go | 281 - internal/decoder/optdec/helper.go | 101 - internal/decoder/optdec/interface.go | 169 - internal/decoder/optdec/map.go | 430 - internal/decoder/optdec/native.go | 269 - internal/decoder/optdec/native_test.go | 72 - internal/decoder/optdec/node.go | 1279 -- internal/decoder/optdec/slice.go | 224 - internal/decoder/optdec/stringopts.go | 360 - internal/decoder/optdec/structs.go | 61 - internal/decoder/optdec/testdata_test.go | 551 - internal/decoder/optdec/types.go | 60 - internal/encoder/alg/mapiter.go | 206 - internal/encoder/alg/opts.go | 31 - internal/encoder/alg/primitives.go | 95 - internal/encoder/alg/sort.go | 206 - internal/encoder/alg/sort_test.go | 168 - internal/encoder/alg/spec.go | 198 - internal/encoder/alg/spec_compat.go | 148 - internal/encoder/compiler.go | 676 - internal/encoder/compiler_test.go | 50 - internal/encoder/encode_norace.go | 24 - internal/encoder/encode_race.go | 54 - internal/encoder/encoder.go | 318 - internal/encoder/encoder_norace_test.go | 56 - internal/encoder/encoder_test.go | 642 - internal/encoder/ir/op.go | 473 - internal/encoder/pools_amd64.go | 97 - internal/encoder/pools_compt.go | 24 - internal/encoder/stream.go | 91 - internal/encoder/stream_test.go | 140 - internal/encoder/testdata_test.go | 552 - internal/encoder/vars/cache.go | 48 - internal/encoder/vars/const.go | 42 - internal/encoder/vars/errors.go | 65 - internal/encoder/vars/stack.go | 146 - internal/encoder/vars/types.go | 47 - internal/encoder/vm/stbus.go | 45 - internal/encoder/vm/vm.go | 374 - internal/encoder/vm/vm_test.go | 67 - internal/encoder/x86/asm_stubs_amd64_go117.go | 53 - internal/encoder/x86/asm_stubs_amd64_go121.go | 52 - .../encoder/x86/assembler_regabi_amd64.go | 1194 -- internal/encoder/x86/assembler_test.go | 365 - internal/encoder/x86/debug_go116.go | 66 - internal/encoder/x86/debug_go117.go | 201 - internal/encoder/x86/stbus.go | 54 - internal/jit/arch_amd64.go | 67 - internal/jit/asm.s | 0 internal/jit/assembler_amd64.go | 269 - internal/jit/backend.go | 120 - internal/jit/backend_test.go | 34 - internal/jit/runtime.go | 49 - internal/native/avx2/f32toa.go | 35 - internal/native/avx2/f32toa_subr.go | 46 - internal/native/avx2/f32toa_text_amd64.go | 1066 -- internal/native/avx2/f64toa.go | 35 - internal/native/avx2/f64toa_subr.go | 46 - internal/native/avx2/f64toa_text_amd64.go | 2504 --- internal/native/avx2/fastfloat_test.go | 143 - internal/native/avx2/fastint_test.go | 156 - internal/native/avx2/get_by_path.go | 35 - internal/native/avx2/get_by_path_subr.go | 46 - .../native/avx2/get_by_path_text_amd64.go | 6340 ------- internal/native/avx2/html_escape.go | 34 - internal/native/avx2/html_escape_subr.go | 45 - .../native/avx2/html_escape_text_amd64.go | 832 - internal/native/avx2/i64toa.go | 35 - internal/native/avx2/i64toa_subr.go | 47 - internal/native/avx2/i64toa_text_amd64.go | 631 - internal/native/avx2/lookup_small_key.go | 37 - internal/native/avx2/lookup_small_key_subr.go | 45 - .../avx2/lookup_small_key_text_amd64.go | 218 - internal/native/avx2/lspace.go | 35 - internal/native/avx2/lspace_subr.go | 38 - internal/native/avx2/lspace_text_amd64.go | 112 - internal/native/avx2/native_export.go | 51 - internal/native/avx2/native_test.go | 636 - internal/native/avx2/parse_with_padding.go | 36 - .../native/avx2/parse_with_padding_subr.go | 46 - .../avx2/parse_with_padding_text_amd64.go | 15205 ---------------- internal/native/avx2/quote.go | 33 - internal/native/avx2/quote_subr.go | 46 - internal/native/avx2/quote_text_amd64.go | 1390 -- internal/native/avx2/recover_test.go | 722 - internal/native/avx2/skip_array.go | 35 - internal/native/avx2/skip_array_subr.go | 46 - internal/native/avx2/skip_array_text_amd64.go | 3052 ---- internal/native/avx2/skip_number.go | 34 - internal/native/avx2/skip_number_subr.go | 46 - .../native/avx2/skip_number_text_amd64.go | 494 - internal/native/avx2/skip_object.go | 35 - internal/native/avx2/skip_object_subr.go | 46 - .../native/avx2/skip_object_text_amd64.go | 3052 ---- internal/native/avx2/skip_one.go | 35 - internal/native/avx2/skip_one_fast.go | 35 - internal/native/avx2/skip_one_fast_subr.go | 46 - .../native/avx2/skip_one_fast_text_amd64.go | 956 - internal/native/avx2/skip_one_subr.go | 46 - internal/native/avx2/skip_one_text_amd64.go | 3054 ---- internal/native/avx2/u64toa.go | 34 - internal/native/avx2/u64toa_subr.go | 39 - internal/native/avx2/u64toa_text_amd64.go | 364 - internal/native/avx2/unquote.go | 34 - internal/native/avx2/unquote_subr.go | 46 - internal/native/avx2/unquote_text_amd64.go | 622 - internal/native/avx2/validate_one.go | 35 - internal/native/avx2/validate_one_subr.go | 46 - .../native/avx2/validate_one_text_amd64.go | 3054 ---- internal/native/avx2/validate_utf8.go | 37 - internal/native/avx2/validate_utf8_fast.go | 34 - .../native/avx2/validate_utf8_fast_subr.go | 42 - .../avx2/validate_utf8_fast_text_amd64.go | 753 - internal/native/avx2/validate_utf8_subr.go | 44 - .../native/avx2/validate_utf8_text_amd64.go | 193 - internal/native/avx2/value.go | 33 - internal/native/avx2/value_subr.go | 46 - internal/native/avx2/value_text_amd64.go | 5554 ------ internal/native/avx2/vnumber.go | 33 - internal/native/avx2/vnumber_subr.go | 45 - internal/native/avx2/vnumber_text_amd64.go | 4216 ----- internal/native/avx2/vsigned.go | 33 - internal/native/avx2/vsigned_subr.go | 50 - internal/native/avx2/vsigned_text_amd64.go | 120 - internal/native/avx2/vstring.go | 33 - internal/native/avx2/vstring_subr.go | 46 - internal/native/avx2/vstring_text_amd64.go | 513 - internal/native/avx2/vunsigned.go | 33 - internal/native/avx2/vunsigned_subr.go | 57 - internal/native/avx2/vunsigned_text_amd64.go | 127 - internal/native/dispatch_amd64.go | 258 - internal/native/dispatch_arm64.go | 169 - internal/native/f32toa.tmpl | 35 - internal/native/f64toa.tmpl | 35 - internal/native/fastfloat_test.tmpl | 143 - internal/native/fastint_test.tmpl | 156 - internal/native/get_by_path.tmpl | 35 - internal/native/html_escape.tmpl | 34 - internal/native/i64toa.tmpl | 35 - internal/native/lookup_small_key.tmpl | 37 - internal/native/lspace.tmpl | 35 - internal/native/native_export.tmpl | 51 - internal/native/native_test.tmpl | 636 - internal/native/neon/f32toa_arm64.go | 29 - internal/native/neon/f32toa_arm64.s | 1019 -- internal/native/neon/f32toa_subr_arm64.go | 25 - internal/native/neon/f64toa_arm64.go | 29 - internal/native/neon/f64toa_arm64.s | 2492 --- internal/native/neon/f64toa_subr_arm64.go | 25 - internal/native/neon/fastfloat_arm64_test.go | 147 - internal/native/neon/fastint_arm64_test.go | 153 - internal/native/neon/get_by_path_arm64.go | 33 - internal/native/neon/get_by_path_arm64.s | 5627 ------ .../native/neon/get_by_path_subr_arm64.go | 25 - internal/native/neon/html_escape_arm64.go | 35 - internal/native/neon/html_escape_arm64.s | 1406 -- .../native/neon/html_escape_subr_arm64.go | 25 - internal/native/neon/i64toa_arm64.go | 29 - internal/native/neon/i64toa_arm64.s | 985 - internal/native/neon/i64toa_subr_arm64.go | 25 - .../native/neon/lookup_small_key_arm64.go | 31 - internal/native/neon/lookup_small_key_arm64.s | 354 - .../neon/lookup_small_key_subr_arm64.go | 25 - internal/native/neon/lspace_arm64.go | 35 - internal/native/neon/lspace_arm64.s | 68 - internal/native/neon/lspace_subr_arm64.go | 25 - internal/native/neon/native_arm64_test.go | 635 - internal/native/neon/native_export_arm64.go | 51 - .../native/neon/parse_with_padding_arm64.go | 30 - .../native/neon/parse_with_padding_arm64.s | 14122 -------------- .../neon/parse_with_padding_subr_arm64.go | 25 - internal/native/neon/quote_arm64.go | 35 - internal/native/neon/quote_arm64.s | 2563 --- internal/native/neon/quote_subr_arm64.go | 25 - internal/native/neon/recover_arm64_test.go | 660 - internal/native/neon/skip_array_arm64.go | 35 - internal/native/neon/skip_array_arm64.s | 2384 --- internal/native/neon/skip_array_subr_arm64.go | 25 - internal/native/neon/skip_number_arm64.go | 29 - internal/native/neon/skip_number_arm64.s | 373 - .../native/neon/skip_number_subr_arm64.go | 25 - internal/native/neon/skip_object_arm64.go | 35 - internal/native/neon/skip_object_arm64.s | 2384 --- .../native/neon/skip_object_subr_arm64.go | 25 - internal/native/neon/skip_one_arm64.go | 35 - internal/native/neon/skip_one_arm64.s | 2384 --- internal/native/neon/skip_one_fast_arm64.go | 29 - internal/native/neon/skip_one_fast_arm64.s | 998 - .../native/neon/skip_one_fast_subr_arm64.go | 25 - internal/native/neon/skip_one_subr_arm64.go | 25 - internal/native/neon/u64toa_arm64.go | 29 - internal/native/neon/u64toa_arm64.s | 598 - internal/native/neon/u64toa_subr_arm64.go | 25 - internal/native/neon/unquote_arm64.go | 35 - internal/native/neon/unquote_arm64.s | 615 - internal/native/neon/unquote_subr_arm64.go | 25 - internal/native/neon/validate_one_arm64.go | 35 - internal/native/neon/validate_one_arm64.s | 2383 --- .../native/neon/validate_one_subr_arm64.go | 25 - internal/native/neon/validate_utf8_arm64.go | 36 - internal/native/neon/validate_utf8_arm64.s | 222 - .../native/neon/validate_utf8_fast_arm64.go | 29 - .../native/neon/validate_utf8_fast_arm64.s | 182 - .../neon/validate_utf8_fast_subr_arm64.go | 25 - .../native/neon/validate_utf8_subr_arm64.go | 25 - internal/native/neon/value_arm64.go | 34 - internal/native/neon/value_arm64.s | 5968 ------ internal/native/neon/value_subr_arm64.go | 25 - internal/native/neon/vnumber_arm64.go | 34 - internal/native/neon/vnumber_arm64.s | 4690 ----- internal/native/neon/vnumber_subr_arm64.go | 25 - internal/native/neon/vsigned_arm64.go | 32 - internal/native/neon/vsigned_arm64.s | 156 - internal/native/neon/vsigned_subr_arm64.go | 25 - internal/native/neon/vstring_arm64.go | 32 - internal/native/neon/vstring_arm64.s | 628 - internal/native/neon/vstring_subr_arm64.go | 25 - internal/native/neon/vunsigned_arm64.go | 32 - internal/native/neon/vunsigned_arm64.s | 150 - internal/native/neon/vunsigned_subr_arm64.go | 25 - internal/native/parse_with_padding.tmpl | 36 - internal/native/quote.tmpl | 33 - internal/native/recover_test.tmpl | 722 - internal/native/skip_array.tmpl | 35 - internal/native/skip_number.tmpl | 34 - internal/native/skip_object.tmpl | 35 - internal/native/skip_one.tmpl | 35 - internal/native/skip_one_fast.tmpl | 35 - internal/native/sse/f32toa.go | 35 - internal/native/sse/f32toa_subr.go | 46 - internal/native/sse/f32toa_text_amd64.go | 1055 -- internal/native/sse/f64toa.go | 35 - internal/native/sse/f64toa_subr.go | 46 - internal/native/sse/f64toa_text_amd64.go | 2493 --- internal/native/sse/fastfloat_test.go | 143 - internal/native/sse/fastint_test.go | 156 - internal/native/sse/get_by_path.go | 35 - internal/native/sse/get_by_path_subr.go | 46 - internal/native/sse/get_by_path_text_amd64.go | 6217 ------- internal/native/sse/html_escape.go | 34 - internal/native/sse/html_escape_subr.go | 45 - internal/native/sse/html_escape_text_amd64.go | 634 - internal/native/sse/i64toa.go | 35 - internal/native/sse/i64toa_subr.go | 47 - internal/native/sse/i64toa_text_amd64.go | 658 - internal/native/sse/lookup_small_key.go | 37 - internal/native/sse/lookup_small_key_subr.go | 45 - .../native/sse/lookup_small_key_text_amd64.go | 242 - internal/native/sse/lspace.go | 35 - internal/native/sse/lspace_subr.go | 33 - internal/native/sse/lspace_text_amd64.go | 37 - internal/native/sse/native_export.go | 51 - internal/native/sse/native_test.go | 636 - internal/native/sse/parse_with_padding.go | 36 - .../native/sse/parse_with_padding_subr.go | 46 - .../sse/parse_with_padding_text_amd64.go | 14926 --------------- internal/native/sse/quote.go | 33 - internal/native/sse/quote_subr.go | 46 - internal/native/sse/quote_text_amd64.go | 1111 -- internal/native/sse/recover_test.go | 722 - internal/native/sse/skip_array.go | 35 - internal/native/sse/skip_array_subr.go | 46 - internal/native/sse/skip_array_text_amd64.go | 2949 --- internal/native/sse/skip_number.go | 34 - internal/native/sse/skip_number_subr.go | 46 - internal/native/sse/skip_number_text_amd64.go | 351 - internal/native/sse/skip_object.go | 35 - internal/native/sse/skip_object_subr.go | 46 - internal/native/sse/skip_object_text_amd64.go | 2949 --- internal/native/sse/skip_one.go | 35 - internal/native/sse/skip_one_fast.go | 35 - internal/native/sse/skip_one_fast_subr.go | 46 - .../native/sse/skip_one_fast_text_amd64.go | 1038 -- internal/native/sse/skip_one_subr.go | 46 - internal/native/sse/skip_one_text_amd64.go | 2949 --- internal/native/sse/u64toa.go | 34 - internal/native/sse/u64toa_subr.go | 39 - internal/native/sse/u64toa_text_amd64.go | 384 - internal/native/sse/unquote.go | 34 - internal/native/sse/unquote_subr.go | 46 - internal/native/sse/unquote_text_amd64.go | 571 - internal/native/sse/validate_one.go | 35 - internal/native/sse/validate_one_subr.go | 46 - .../native/sse/validate_one_text_amd64.go | 2949 --- internal/native/sse/validate_utf8.go | 37 - internal/native/sse/validate_utf8_fast.go | 34 - .../native/sse/validate_utf8_fast_subr.go | 41 - .../sse/validate_utf8_fast_text_amd64.go | 158 - internal/native/sse/validate_utf8_subr.go | 44 - .../native/sse/validate_utf8_text_amd64.go | 193 - internal/native/sse/value.go | 33 - internal/native/sse/value_subr.go | 46 - internal/native/sse/value_text_amd64.go | 5312 ------ internal/native/sse/vnumber.go | 33 - internal/native/sse/vnumber_subr.go | 45 - internal/native/sse/vnumber_text_amd64.go | 4083 ----- internal/native/sse/vsigned.go | 33 - internal/native/sse/vsigned_subr.go | 50 - internal/native/sse/vsigned_text_amd64.go | 120 - internal/native/sse/vstring.go | 33 - internal/native/sse/vstring_subr.go | 46 - internal/native/sse/vstring_text_amd64.go | 657 - internal/native/sse/vunsigned.go | 33 - internal/native/sse/vunsigned_subr.go | 57 - internal/native/sse/vunsigned_text_amd64.go | 127 - internal/native/traceback_test.mock_tmpl | 379 - internal/native/u64toa.tmpl | 34 - internal/native/unquote.tmpl | 34 - internal/native/validate_one.tmpl | 35 - internal/native/validate_utf8.tmpl | 37 - internal/native/validate_utf8_fast.tmpl | 34 - internal/native/value.tmpl | 33 - internal/native/vnumber.tmpl | 33 - internal/native/vsigned.tmpl | 33 - internal/native/vstring.tmpl | 33 - internal/native/vunsigned.tmpl | 33 - internal/optcaching/asm.s | 0 internal/optcaching/fcache.go | 362 - search_test.go | 3 - sonic.go | 173 - tools/asm2asm | 2 +- 373 files changed, 1 insertion(+), 199155 deletions(-) delete mode 100644 ast/api.go delete mode 100644 ast/api_native_test.go delete mode 100644 ast/asm.s delete mode 100644 decode_test.go delete mode 100644 decoder/decoder_native.go delete mode 100644 decoder/decoder_native_test.go delete mode 100644 encode_test.go delete mode 100644 encoder/encoder_native.go delete mode 100644 encoder/encoder_native_test.go delete mode 100644 internal/base64/b64_amd64.go delete mode 100644 internal/base64/b64_compat.go delete mode 100644 internal/cpu/features.go delete mode 100644 internal/decoder/api/decoder.go delete mode 100644 internal/decoder/api/decoder_amd64.go delete mode 100644 internal/decoder/api/decoder_arm64.go delete mode 100644 internal/decoder/api/norace_test.go delete mode 100644 internal/decoder/api/stream.go delete mode 100644 internal/decoder/api/stream_test.go delete mode 100644 internal/decoder/api/testdata_test.go delete mode 100644 internal/decoder/consts/option.go delete mode 100644 internal/decoder/errors/errors.go delete mode 100644 internal/decoder/errors/errors_test.go delete mode 100644 internal/decoder/errors/fuzz_test.go delete mode 100644 internal/decoder/jitdec/asm.s delete mode 100644 internal/decoder/jitdec/asm_stubs_amd64_go117.go delete mode 100644 internal/decoder/jitdec/asm_stubs_amd64_go121.go delete mode 100644 internal/decoder/jitdec/assembler_regabi_amd64.go delete mode 100644 internal/decoder/jitdec/assembler_test.go delete mode 100644 internal/decoder/jitdec/compiler.go delete mode 100644 internal/decoder/jitdec/compiler_test.go delete mode 100644 internal/decoder/jitdec/debug.go delete mode 100644 internal/decoder/jitdec/decoder.go delete mode 100644 internal/decoder/jitdec/generic_regabi_amd64.go delete mode 100644 internal/decoder/jitdec/generic_regabi_amd64_test.s delete mode 100644 internal/decoder/jitdec/generic_test.go delete mode 100644 internal/decoder/jitdec/pools.go delete mode 100644 internal/decoder/jitdec/primitives.go delete mode 100644 internal/decoder/jitdec/stubs_go116.go delete mode 100644 internal/decoder/jitdec/stubs_go120.go delete mode 100644 internal/decoder/jitdec/testdata_test.go delete mode 100644 internal/decoder/jitdec/types.go delete mode 100644 internal/decoder/jitdec/utils.go delete mode 100644 internal/decoder/optdec/compile_struct.go delete mode 100644 internal/decoder/optdec/compiler.go delete mode 100644 internal/decoder/optdec/const.go delete mode 100644 internal/decoder/optdec/context.go delete mode 100644 internal/decoder/optdec/decoder.go delete mode 100644 internal/decoder/optdec/errors.go delete mode 100644 internal/decoder/optdec/functor.go delete mode 100644 internal/decoder/optdec/helper.go delete mode 100644 internal/decoder/optdec/interface.go delete mode 100644 internal/decoder/optdec/map.go delete mode 100644 internal/decoder/optdec/native.go delete mode 100644 internal/decoder/optdec/native_test.go delete mode 100644 internal/decoder/optdec/node.go delete mode 100644 internal/decoder/optdec/slice.go delete mode 100644 internal/decoder/optdec/stringopts.go delete mode 100644 internal/decoder/optdec/structs.go delete mode 100644 internal/decoder/optdec/testdata_test.go delete mode 100644 internal/decoder/optdec/types.go delete mode 100644 internal/encoder/alg/mapiter.go delete mode 100644 internal/encoder/alg/opts.go delete mode 100644 internal/encoder/alg/primitives.go delete mode 100644 internal/encoder/alg/sort.go delete mode 100644 internal/encoder/alg/sort_test.go delete mode 100644 internal/encoder/alg/spec.go delete mode 100644 internal/encoder/alg/spec_compat.go delete mode 100644 internal/encoder/compiler.go delete mode 100644 internal/encoder/compiler_test.go delete mode 100644 internal/encoder/encode_norace.go delete mode 100644 internal/encoder/encode_race.go delete mode 100644 internal/encoder/encoder.go delete mode 100644 internal/encoder/encoder_norace_test.go delete mode 100644 internal/encoder/encoder_test.go delete mode 100644 internal/encoder/ir/op.go delete mode 100644 internal/encoder/pools_amd64.go delete mode 100644 internal/encoder/pools_compt.go delete mode 100644 internal/encoder/stream.go delete mode 100644 internal/encoder/stream_test.go delete mode 100644 internal/encoder/testdata_test.go delete mode 100644 internal/encoder/vars/cache.go delete mode 100644 internal/encoder/vars/const.go delete mode 100644 internal/encoder/vars/errors.go delete mode 100644 internal/encoder/vars/stack.go delete mode 100644 internal/encoder/vars/types.go delete mode 100644 internal/encoder/vm/stbus.go delete mode 100644 internal/encoder/vm/vm.go delete mode 100644 internal/encoder/vm/vm_test.go delete mode 100644 internal/encoder/x86/asm_stubs_amd64_go117.go delete mode 100644 internal/encoder/x86/asm_stubs_amd64_go121.go delete mode 100644 internal/encoder/x86/assembler_regabi_amd64.go delete mode 100644 internal/encoder/x86/assembler_test.go delete mode 100644 internal/encoder/x86/debug_go116.go delete mode 100644 internal/encoder/x86/debug_go117.go delete mode 100644 internal/encoder/x86/stbus.go delete mode 100644 internal/jit/arch_amd64.go delete mode 100644 internal/jit/asm.s delete mode 100644 internal/jit/assembler_amd64.go delete mode 100644 internal/jit/backend.go delete mode 100644 internal/jit/backend_test.go delete mode 100644 internal/jit/runtime.go delete mode 100644 internal/native/avx2/f32toa.go delete mode 100644 internal/native/avx2/f32toa_subr.go delete mode 100644 internal/native/avx2/f32toa_text_amd64.go delete mode 100644 internal/native/avx2/f64toa.go delete mode 100644 internal/native/avx2/f64toa_subr.go delete mode 100644 internal/native/avx2/f64toa_text_amd64.go delete mode 100644 internal/native/avx2/fastfloat_test.go delete mode 100644 internal/native/avx2/fastint_test.go delete mode 100644 internal/native/avx2/get_by_path.go delete mode 100644 internal/native/avx2/get_by_path_subr.go delete mode 100644 internal/native/avx2/get_by_path_text_amd64.go delete mode 100644 internal/native/avx2/html_escape.go delete mode 100644 internal/native/avx2/html_escape_subr.go delete mode 100644 internal/native/avx2/html_escape_text_amd64.go delete mode 100644 internal/native/avx2/i64toa.go delete mode 100644 internal/native/avx2/i64toa_subr.go delete mode 100644 internal/native/avx2/i64toa_text_amd64.go delete mode 100644 internal/native/avx2/lookup_small_key.go delete mode 100644 internal/native/avx2/lookup_small_key_subr.go delete mode 100644 internal/native/avx2/lookup_small_key_text_amd64.go delete mode 100644 internal/native/avx2/lspace.go delete mode 100644 internal/native/avx2/lspace_subr.go delete mode 100644 internal/native/avx2/lspace_text_amd64.go delete mode 100644 internal/native/avx2/native_export.go delete mode 100644 internal/native/avx2/native_test.go delete mode 100644 internal/native/avx2/parse_with_padding.go delete mode 100644 internal/native/avx2/parse_with_padding_subr.go delete mode 100644 internal/native/avx2/parse_with_padding_text_amd64.go delete mode 100644 internal/native/avx2/quote.go delete mode 100644 internal/native/avx2/quote_subr.go delete mode 100644 internal/native/avx2/quote_text_amd64.go delete mode 100644 internal/native/avx2/recover_test.go delete mode 100644 internal/native/avx2/skip_array.go delete mode 100644 internal/native/avx2/skip_array_subr.go delete mode 100644 internal/native/avx2/skip_array_text_amd64.go delete mode 100644 internal/native/avx2/skip_number.go delete mode 100644 internal/native/avx2/skip_number_subr.go delete mode 100644 internal/native/avx2/skip_number_text_amd64.go delete mode 100644 internal/native/avx2/skip_object.go delete mode 100644 internal/native/avx2/skip_object_subr.go delete mode 100644 internal/native/avx2/skip_object_text_amd64.go delete mode 100644 internal/native/avx2/skip_one.go delete mode 100644 internal/native/avx2/skip_one_fast.go delete mode 100644 internal/native/avx2/skip_one_fast_subr.go delete mode 100644 internal/native/avx2/skip_one_fast_text_amd64.go delete mode 100644 internal/native/avx2/skip_one_subr.go delete mode 100644 internal/native/avx2/skip_one_text_amd64.go delete mode 100644 internal/native/avx2/u64toa.go delete mode 100644 internal/native/avx2/u64toa_subr.go delete mode 100644 internal/native/avx2/u64toa_text_amd64.go delete mode 100644 internal/native/avx2/unquote.go delete mode 100644 internal/native/avx2/unquote_subr.go delete mode 100644 internal/native/avx2/unquote_text_amd64.go delete mode 100644 internal/native/avx2/validate_one.go delete mode 100644 internal/native/avx2/validate_one_subr.go delete mode 100644 internal/native/avx2/validate_one_text_amd64.go delete mode 100644 internal/native/avx2/validate_utf8.go delete mode 100644 internal/native/avx2/validate_utf8_fast.go delete mode 100644 internal/native/avx2/validate_utf8_fast_subr.go delete mode 100644 internal/native/avx2/validate_utf8_fast_text_amd64.go delete mode 100644 internal/native/avx2/validate_utf8_subr.go delete mode 100644 internal/native/avx2/validate_utf8_text_amd64.go delete mode 100644 internal/native/avx2/value.go delete mode 100644 internal/native/avx2/value_subr.go delete mode 100644 internal/native/avx2/value_text_amd64.go delete mode 100644 internal/native/avx2/vnumber.go delete mode 100644 internal/native/avx2/vnumber_subr.go delete mode 100644 internal/native/avx2/vnumber_text_amd64.go delete mode 100644 internal/native/avx2/vsigned.go delete mode 100644 internal/native/avx2/vsigned_subr.go delete mode 100644 internal/native/avx2/vsigned_text_amd64.go delete mode 100644 internal/native/avx2/vstring.go delete mode 100644 internal/native/avx2/vstring_subr.go delete mode 100644 internal/native/avx2/vstring_text_amd64.go delete mode 100644 internal/native/avx2/vunsigned.go delete mode 100644 internal/native/avx2/vunsigned_subr.go delete mode 100644 internal/native/avx2/vunsigned_text_amd64.go delete mode 100644 internal/native/dispatch_amd64.go delete mode 100644 internal/native/dispatch_arm64.go delete mode 100644 internal/native/f32toa.tmpl delete mode 100644 internal/native/f64toa.tmpl delete mode 100644 internal/native/fastfloat_test.tmpl delete mode 100644 internal/native/fastint_test.tmpl delete mode 100644 internal/native/get_by_path.tmpl delete mode 100644 internal/native/html_escape.tmpl delete mode 100644 internal/native/i64toa.tmpl delete mode 100644 internal/native/lookup_small_key.tmpl delete mode 100644 internal/native/lspace.tmpl delete mode 100644 internal/native/native_export.tmpl delete mode 100644 internal/native/native_test.tmpl delete mode 100644 internal/native/neon/f32toa_arm64.go delete mode 100644 internal/native/neon/f32toa_arm64.s delete mode 100644 internal/native/neon/f32toa_subr_arm64.go delete mode 100644 internal/native/neon/f64toa_arm64.go delete mode 100644 internal/native/neon/f64toa_arm64.s delete mode 100644 internal/native/neon/f64toa_subr_arm64.go delete mode 100644 internal/native/neon/fastfloat_arm64_test.go delete mode 100644 internal/native/neon/fastint_arm64_test.go delete mode 100644 internal/native/neon/get_by_path_arm64.go delete mode 100644 internal/native/neon/get_by_path_arm64.s delete mode 100644 internal/native/neon/get_by_path_subr_arm64.go delete mode 100644 internal/native/neon/html_escape_arm64.go delete mode 100644 internal/native/neon/html_escape_arm64.s delete mode 100644 internal/native/neon/html_escape_subr_arm64.go delete mode 100644 internal/native/neon/i64toa_arm64.go delete mode 100644 internal/native/neon/i64toa_arm64.s delete mode 100644 internal/native/neon/i64toa_subr_arm64.go delete mode 100644 internal/native/neon/lookup_small_key_arm64.go delete mode 100644 internal/native/neon/lookup_small_key_arm64.s delete mode 100644 internal/native/neon/lookup_small_key_subr_arm64.go delete mode 100644 internal/native/neon/lspace_arm64.go delete mode 100644 internal/native/neon/lspace_arm64.s delete mode 100644 internal/native/neon/lspace_subr_arm64.go delete mode 100644 internal/native/neon/native_arm64_test.go delete mode 100644 internal/native/neon/native_export_arm64.go delete mode 100644 internal/native/neon/parse_with_padding_arm64.go delete mode 100644 internal/native/neon/parse_with_padding_arm64.s delete mode 100644 internal/native/neon/parse_with_padding_subr_arm64.go delete mode 100644 internal/native/neon/quote_arm64.go delete mode 100644 internal/native/neon/quote_arm64.s delete mode 100644 internal/native/neon/quote_subr_arm64.go delete mode 100644 internal/native/neon/recover_arm64_test.go delete mode 100644 internal/native/neon/skip_array_arm64.go delete mode 100644 internal/native/neon/skip_array_arm64.s delete mode 100644 internal/native/neon/skip_array_subr_arm64.go delete mode 100644 internal/native/neon/skip_number_arm64.go delete mode 100644 internal/native/neon/skip_number_arm64.s delete mode 100644 internal/native/neon/skip_number_subr_arm64.go delete mode 100644 internal/native/neon/skip_object_arm64.go delete mode 100644 internal/native/neon/skip_object_arm64.s delete mode 100644 internal/native/neon/skip_object_subr_arm64.go delete mode 100644 internal/native/neon/skip_one_arm64.go delete mode 100644 internal/native/neon/skip_one_arm64.s delete mode 100644 internal/native/neon/skip_one_fast_arm64.go delete mode 100644 internal/native/neon/skip_one_fast_arm64.s delete mode 100644 internal/native/neon/skip_one_fast_subr_arm64.go delete mode 100644 internal/native/neon/skip_one_subr_arm64.go delete mode 100644 internal/native/neon/u64toa_arm64.go delete mode 100644 internal/native/neon/u64toa_arm64.s delete mode 100644 internal/native/neon/u64toa_subr_arm64.go delete mode 100644 internal/native/neon/unquote_arm64.go delete mode 100644 internal/native/neon/unquote_arm64.s delete mode 100644 internal/native/neon/unquote_subr_arm64.go delete mode 100644 internal/native/neon/validate_one_arm64.go delete mode 100644 internal/native/neon/validate_one_arm64.s delete mode 100644 internal/native/neon/validate_one_subr_arm64.go delete mode 100644 internal/native/neon/validate_utf8_arm64.go delete mode 100644 internal/native/neon/validate_utf8_arm64.s delete mode 100644 internal/native/neon/validate_utf8_fast_arm64.go delete mode 100644 internal/native/neon/validate_utf8_fast_arm64.s delete mode 100644 internal/native/neon/validate_utf8_fast_subr_arm64.go delete mode 100644 internal/native/neon/validate_utf8_subr_arm64.go delete mode 100644 internal/native/neon/value_arm64.go delete mode 100644 internal/native/neon/value_arm64.s delete mode 100644 internal/native/neon/value_subr_arm64.go delete mode 100644 internal/native/neon/vnumber_arm64.go delete mode 100644 internal/native/neon/vnumber_arm64.s delete mode 100644 internal/native/neon/vnumber_subr_arm64.go delete mode 100644 internal/native/neon/vsigned_arm64.go delete mode 100644 internal/native/neon/vsigned_arm64.s delete mode 100644 internal/native/neon/vsigned_subr_arm64.go delete mode 100644 internal/native/neon/vstring_arm64.go delete mode 100644 internal/native/neon/vstring_arm64.s delete mode 100644 internal/native/neon/vstring_subr_arm64.go delete mode 100644 internal/native/neon/vunsigned_arm64.go delete mode 100644 internal/native/neon/vunsigned_arm64.s delete mode 100644 internal/native/neon/vunsigned_subr_arm64.go delete mode 100644 internal/native/parse_with_padding.tmpl delete mode 100644 internal/native/quote.tmpl delete mode 100644 internal/native/recover_test.tmpl delete mode 100644 internal/native/skip_array.tmpl delete mode 100644 internal/native/skip_number.tmpl delete mode 100644 internal/native/skip_object.tmpl delete mode 100644 internal/native/skip_one.tmpl delete mode 100644 internal/native/skip_one_fast.tmpl delete mode 100644 internal/native/sse/f32toa.go delete mode 100644 internal/native/sse/f32toa_subr.go delete mode 100644 internal/native/sse/f32toa_text_amd64.go delete mode 100644 internal/native/sse/f64toa.go delete mode 100644 internal/native/sse/f64toa_subr.go delete mode 100644 internal/native/sse/f64toa_text_amd64.go delete mode 100644 internal/native/sse/fastfloat_test.go delete mode 100644 internal/native/sse/fastint_test.go delete mode 100644 internal/native/sse/get_by_path.go delete mode 100644 internal/native/sse/get_by_path_subr.go delete mode 100644 internal/native/sse/get_by_path_text_amd64.go delete mode 100644 internal/native/sse/html_escape.go delete mode 100644 internal/native/sse/html_escape_subr.go delete mode 100644 internal/native/sse/html_escape_text_amd64.go delete mode 100644 internal/native/sse/i64toa.go delete mode 100644 internal/native/sse/i64toa_subr.go delete mode 100644 internal/native/sse/i64toa_text_amd64.go delete mode 100644 internal/native/sse/lookup_small_key.go delete mode 100644 internal/native/sse/lookup_small_key_subr.go delete mode 100644 internal/native/sse/lookup_small_key_text_amd64.go delete mode 100644 internal/native/sse/lspace.go delete mode 100644 internal/native/sse/lspace_subr.go delete mode 100644 internal/native/sse/lspace_text_amd64.go delete mode 100644 internal/native/sse/native_export.go delete mode 100644 internal/native/sse/native_test.go delete mode 100644 internal/native/sse/parse_with_padding.go delete mode 100644 internal/native/sse/parse_with_padding_subr.go delete mode 100644 internal/native/sse/parse_with_padding_text_amd64.go delete mode 100644 internal/native/sse/quote.go delete mode 100644 internal/native/sse/quote_subr.go delete mode 100644 internal/native/sse/quote_text_amd64.go delete mode 100644 internal/native/sse/recover_test.go delete mode 100644 internal/native/sse/skip_array.go delete mode 100644 internal/native/sse/skip_array_subr.go delete mode 100644 internal/native/sse/skip_array_text_amd64.go delete mode 100644 internal/native/sse/skip_number.go delete mode 100644 internal/native/sse/skip_number_subr.go delete mode 100644 internal/native/sse/skip_number_text_amd64.go delete mode 100644 internal/native/sse/skip_object.go delete mode 100644 internal/native/sse/skip_object_subr.go delete mode 100644 internal/native/sse/skip_object_text_amd64.go delete mode 100644 internal/native/sse/skip_one.go delete mode 100644 internal/native/sse/skip_one_fast.go delete mode 100644 internal/native/sse/skip_one_fast_subr.go delete mode 100644 internal/native/sse/skip_one_fast_text_amd64.go delete mode 100644 internal/native/sse/skip_one_subr.go delete mode 100644 internal/native/sse/skip_one_text_amd64.go delete mode 100644 internal/native/sse/u64toa.go delete mode 100644 internal/native/sse/u64toa_subr.go delete mode 100644 internal/native/sse/u64toa_text_amd64.go delete mode 100644 internal/native/sse/unquote.go delete mode 100644 internal/native/sse/unquote_subr.go delete mode 100644 internal/native/sse/unquote_text_amd64.go delete mode 100644 internal/native/sse/validate_one.go delete mode 100644 internal/native/sse/validate_one_subr.go delete mode 100644 internal/native/sse/validate_one_text_amd64.go delete mode 100644 internal/native/sse/validate_utf8.go delete mode 100644 internal/native/sse/validate_utf8_fast.go delete mode 100644 internal/native/sse/validate_utf8_fast_subr.go delete mode 100644 internal/native/sse/validate_utf8_fast_text_amd64.go delete mode 100644 internal/native/sse/validate_utf8_subr.go delete mode 100644 internal/native/sse/validate_utf8_text_amd64.go delete mode 100644 internal/native/sse/value.go delete mode 100644 internal/native/sse/value_subr.go delete mode 100644 internal/native/sse/value_text_amd64.go delete mode 100644 internal/native/sse/vnumber.go delete mode 100644 internal/native/sse/vnumber_subr.go delete mode 100644 internal/native/sse/vnumber_text_amd64.go delete mode 100644 internal/native/sse/vsigned.go delete mode 100644 internal/native/sse/vsigned_subr.go delete mode 100644 internal/native/sse/vsigned_text_amd64.go delete mode 100644 internal/native/sse/vstring.go delete mode 100644 internal/native/sse/vstring_subr.go delete mode 100644 internal/native/sse/vstring_text_amd64.go delete mode 100644 internal/native/sse/vunsigned.go delete mode 100644 internal/native/sse/vunsigned_subr.go delete mode 100644 internal/native/sse/vunsigned_text_amd64.go delete mode 100644 internal/native/traceback_test.mock_tmpl delete mode 100644 internal/native/u64toa.tmpl delete mode 100644 internal/native/unquote.tmpl delete mode 100644 internal/native/validate_one.tmpl delete mode 100644 internal/native/validate_utf8.tmpl delete mode 100644 internal/native/validate_utf8_fast.tmpl delete mode 100644 internal/native/value.tmpl delete mode 100644 internal/native/vnumber.tmpl delete mode 100644 internal/native/vsigned.tmpl delete mode 100644 internal/native/vstring.tmpl delete mode 100644 internal/native/vunsigned.tmpl delete mode 100644 internal/optcaching/asm.s delete mode 100644 internal/optcaching/fcache.go delete mode 100644 sonic.go diff --git a/ast/api.go b/ast/api.go deleted file mode 100644 index 7c8253aa1..000000000 --- a/ast/api.go +++ /dev/null @@ -1,135 +0,0 @@ -//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - -/* - * Copyright 2022 ByteDance Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ast - -import ( - `runtime` - `unsafe` - - `github.com/bytedance/sonic/encoder` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - uq `github.com/bytedance/sonic/unquote` - `github.com/bytedance/sonic/utf8` -) - -var typeByte = rt.UnpackEface(byte(0)).Type - -//go:nocheckptr -func quote(buf *[]byte, val string) { - *buf = append(*buf, '"') - if len(val) == 0 { - *buf = append(*buf, '"') - return - } - - sp := rt.IndexChar(val, 0) - nb := len(val) - b := (*rt.GoSlice)(unsafe.Pointer(buf)) - - // input buffer - for nb > 0 { - // output buffer - dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len)) - dn := b.Cap - b.Len - // call native.Quote, dn is byte count it outputs - ret := native.Quote(sp, nb, dp, &dn, 0) - // update *buf length - b.Len += dn - - // no need more output - if ret >= 0 { - break - } - - // double buf size - *b = rt.GrowSlice(typeByte, *b, b.Cap*2) - // ret is the complement of consumed input - ret = ^ret - // update input buffer - nb -= ret - sp = unsafe.Pointer(uintptr(sp) + uintptr(ret)) - } - - runtime.KeepAlive(buf) - runtime.KeepAlive(sp) - *buf = append(*buf, '"') -} - -func unquote(src string) (string, types.ParsingError) { - return uq.String(src) -} - -func (self *Parser) decodeValue() (val types.JsonState) { - sv := (*rt.GoString)(unsafe.Pointer(&self.s)) - flag := types.F_USE_NUMBER - if self.dbuf != nil { - flag = 0 - val.Dbuf = self.dbuf - val.Dcap = types.MaxDigitNums - } - self.p = native.Value(sv.Ptr, sv.Len, self.p, &val, uint64(flag)) - return -} - -func (self *Parser) skip() (int, types.ParsingError) { - fsm := types.NewStateMachine() - start := native.SkipOne(&self.s, &self.p, fsm, 0) - types.FreeStateMachine(fsm) - - if start < 0 { - return self.p, types.ParsingError(-start) - } - return start, 0 -} - -func (self *Node) encodeInterface(buf *[]byte) error { - //WARN: NOT compatible with json.Encoder - return encoder.EncodeInto(buf, self.packAny(), encoder.NoEncoderNewline) -} - -func (self *Parser) skipFast() (int, types.ParsingError) { - start := native.SkipOneFast(&self.s, &self.p) - if start < 0 { - return self.p, types.ParsingError(-start) - } - return start, 0 -} - -func (self *Parser) getByPath(validate bool, path ...interface{}) (int, types.ParsingError) { - var fsm *types.StateMachine - if validate { - fsm = types.NewStateMachine() - } - start := native.GetByPath(&self.s, &self.p, &path, fsm) - if validate { - types.FreeStateMachine(fsm) - } - runtime.KeepAlive(path) - if start < 0 { - return self.p, types.ParsingError(-start) - } - return start, 0 -} - -func validate_utf8(str string) bool { - return utf8.ValidateString(str) -} diff --git a/ast/api_compat.go b/ast/api_compat.go index a349afc0b..fde7d1718 100644 --- a/ast/api_compat.go +++ b/ast/api_compat.go @@ -1,5 +1,3 @@ -// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 - /* * Copyright 2022 ByteDance Inc. * diff --git a/ast/api_native_test.go b/ast/api_native_test.go deleted file mode 100644 index 61cf85d94..000000000 --- a/ast/api_native_test.go +++ /dev/null @@ -1,208 +0,0 @@ -//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - -/* - * Copyright 2022 ByteDance Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ast - -import ( - `encoding/json` - `fmt` - `reflect` - `runtime` - `runtime/debug` - `testing` - - `github.com/bytedance/sonic/encoder` - `github.com/stretchr/testify/require` -) - -func TestSortNodeTwitter(t *testing.T) { - if encoder.EnableFallback { - return - } - root, err := NewSearcher(_TwitterJson).GetByPath() - if err != nil { - t.Fatal(err) - } - obj, err := root.MapUseNumber() - if err != nil { - t.Fatal(err) - } - exp, err := encoder.Encode(obj, encoder.SortMapKeys|encoder.NoEncoderNewline) - if err != nil { - t.Fatal(err) - } - var expObj interface{} - require.NoError(t, json.Unmarshal(exp, &expObj)) - - if err := root.SortKeys(true); err != nil { - t.Fatal(err) - } - act, err := root.MarshalJSON() - if err != nil { - t.Fatal(err) - } - var actObj interface{} - require.NoError(t, json.Unmarshal(act, &actObj)) - require.Equal(t, expObj, actObj) - require.Equal(t, len(exp), len(act)) - require.Equal(t, string(exp), string(act)) -} - -func TestNodeAny(t *testing.T) { - empty := Node{} - _,err := empty.SetAny("any", map[string]interface{}{"a": []int{0}}) - if err != nil { - t.Fatal(err) - } - if m, err := empty.Get("any").Interface(); err != nil { - t.Fatal(err) - } else if v, ok := m.(map[string]interface{}); !ok { - t.Fatal(v) - } - if buf, err := empty.MarshalJSON(); err != nil { - t.Fatal(err) - } else if string(buf) != `{"any":{"a":[0]}}` { - t.Fatal(string(buf)) - } - if _, err := empty.Set("any2", Node{}); err != nil { - t.Fatal(err) - } - if err := empty.Get("any2").AddAny(nil); err != nil { - t.Fatal(err) - } - if buf, err := empty.MarshalJSON(); err != nil { - t.Fatal(err) - } else if string(buf) != `{"any":{"a":[0]},"any2":[null]}` { - t.Fatal(string(buf)) - } - if _, err := empty.Get("any2").SetAnyByIndex(0, NewNumber("-0.0")); err != nil { - t.Fatal(err) - } - if buf, err := empty.MarshalJSON(); err != nil { - t.Fatal(err) - } else if string(buf) != `{"any":{"a":[0]},"any2":[-0.0]}` { - t.Fatal(string(buf)) - } -} - - -func TestTypeCast2(t *testing.T) { - type tcase struct { - method string - node Node - exp interface{} - err error - } - var cases = []tcase{ - {"Raw", NewAny(""), "\"\"", nil}, - } - - for i, c := range cases { - fmt.Println(i, c) - rt := reflect.ValueOf(&c.node) - m := rt.MethodByName(c.method) - rets := m.Call([]reflect.Value{}) - if len(rets) != 2 { - t.Fatal(i, rets) - } - require.Equal(t, c.exp, rets[0].Interface()) - v := rets[1].Interface(); - if v != c.err { - t.Fatal(i, v) - } - } -} - -func TestStackAny(t *testing.T) { - var obj = stackObj() - any := NewAny(obj) - fmt.Printf("any: %#v\n", any) - runtime.GC() - debug.FreeOSMemory() - println("finish GC") - buf, err := any.MarshalJSON() - println("finish marshal") - if err != nil { - t.Fatal(err) - } - if string(buf) != "1" { - t.Fatal(string(buf)) - } -} - - -func Test_Export(t *testing.T) { - type args struct { - src string - path []interface{} - } - tests := []struct { - name string - args args - wantStart int - wantEnd int - wantTyp int - wantErr bool - wantValid bool - }{ - {"bool", args{`[true ,2]`, []interface{}{0}}, 1, 5, V_TRUE, false, true}, - {"bool", args{`[t2ue ,2]`, []interface{}{0}}, 1, 5, V_TRUE, false, false}, - {"number", args{`[1 ,2]`, []interface{}{0}}, 1, 2, V_NUMBER, false, true}, - {"number", args{`[1w ,2]`, []interface{}{0}}, 1, 3, V_NUMBER, false, false}, - {"string", args{`[" " ,2]`, []interface{}{0}}, 1, 4, V_STRING, false, true}, - {"string", args{`[" "] ,2]`, []interface{}{0}}, 1, 4, V_STRING, false, true}, - {"object", args{`[{"":""} ,2]`, []interface{}{0}}, 1, 8, V_OBJECT, false, true}, - {"object", args{`[{x} ,2]`, []interface{}{0}}, 1, 4, V_OBJECT, false, false}, - {"arrauy", args{`[[{}] ,2]`, []interface{}{0}}, 1, 5, V_ARRAY, false, true}, - {"arrauy", args{`[[xx] ,2]`, []interface{}{0}}, 1, 5, V_ARRAY, false, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotStart, gotEnd, gotTyp, err := _GetByPath(tt.args.src, tt.args.path...) - if (err != nil) != tt.wantErr { - t.Errorf("_GetByPath() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotStart != tt.wantStart { - t.Errorf("_GetByPath() gotStart = %v, want %v", gotStart, tt.wantStart) - } - if gotEnd != tt.wantEnd { - t.Errorf("_GetByPath() gotEnd = %v, want %v", gotEnd, tt.wantEnd) - } - if gotTyp != tt.wantTyp { - t.Errorf("_GetByPath() gotTyp = %v, want %v", gotTyp, tt.wantTyp) - } - gotStart, gotEnd, err = _SkipFast(tt.args.src, tt.wantStart) - if (err != nil) != tt.wantErr { - t.Errorf("_SkipFast() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotStart != tt.wantStart { - t.Errorf("_SkipFast() gotStart = %v, want %v", gotStart, tt.wantStart) - } - if gotEnd != tt.wantEnd { - t.Errorf("_SkipFast() gotEnd = %v, want %v", gotEnd, tt.wantEnd) - } - valid := _ValidSyntax(tt.args.src[tt.wantStart:tt.wantEnd]) - if valid != tt.wantValid { - t.Errorf("_ValidSyntax() gotValid = %v, want %v", valid, tt.wantValid) - } - }) - } -} diff --git a/ast/asm.s b/ast/asm.s deleted file mode 100644 index e69de29bb..000000000 diff --git a/compat.go b/compat.go index b32342a84..819e0d4d5 100644 --- a/compat.go +++ b/compat.go @@ -1,5 +1,3 @@ -// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 - /* * Copyright 2021 ByteDance Inc. * diff --git a/decode_test.go b/decode_test.go deleted file mode 100644 index f3ed66ecc..000000000 --- a/decode_test.go +++ /dev/null @@ -1,2817 +0,0 @@ -//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - -/* - * Copyright 2021 ByteDance Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sonic - -import ( - `bytes` - `encoding` - `encoding/json` - `errors` - `fmt` - `image` - `math` - `math/big` - `math/rand` - `net` - `reflect` - `strconv` - `strings` - `testing` - `time` - `unsafe` - - `github.com/bytedance/sonic/decoder` - `github.com/bytedance/sonic/internal/native/types` - `github.com/davecgh/go-spew/spew` - `github.com/stretchr/testify/assert` -) - -type T struct { - X string - Y int - Z int `json:"-"` -} - -type U struct { - Alphabet string `json:"alpha"` -} - -type V struct { - F1 interface{} - F2 int32 - F3 json.Number - F4 *VOuter -} - -type VOuter struct { - V V -} - -type W struct { - S SS -} - -type P struct { - PP PP -} - -type PP struct { - T T - Ts []T -} - -type SS string - -func (*SS) UnmarshalJSON(_ []byte) error { - return &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS(""))} -} - -// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and -// without UseNumber -var ifaceNumAsFloat64 = map[string]interface{}{ - "k1": float64(1), - "k2": "s", - "k3": []interface{}{float64(1), 2.0, 3e-3}, - "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)}, -} - -var ifaceNumAsNumber = map[string]interface{}{ - "k1": json.Number("1"), - "k2": "s", - "k3": []interface{}{json.Number("1"), json.Number("2.0"), json.Number("3e-3")}, - "k4": map[string]interface{}{"kk1": "s", "kk2": json.Number("2")}, -} - -type tx struct { - x int -} - -type u8 uint8 - -// A type that can unmarshal itself. - -type unmarshaler struct { - T bool -} - -func (u *unmarshaler) UnmarshalJSON(_ []byte) error { - *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. - return nil -} - -type ustruct struct { - M unmarshaler -} - -type unmarshalerText struct { - A, B string -} - -// needed for re-marshaling tests -func (u unmarshalerText) MarshalText() ([]byte, error) { - return []byte(u.A + ":" + u.B), nil -} - -func (u *unmarshalerText) UnmarshalText(b []byte) error { - pos := bytes.IndexByte(b, ':') - if pos == -1 { - return errors.New("missing separator") - } - u.A, u.B = string(b[:pos]), string(b[pos+1:]) - return nil -} - -var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) - -type ustructText struct { - M unmarshalerText -} - -// u8marshal is an integer type that can marshal/unmarshal itself. -type u8marshal uint8 - -func (u8 u8marshal) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("u%d", u8)), nil -} - -var errMissingU8Prefix = errors.New("missing 'u' prefix") - -func (u8 *u8marshal) UnmarshalText(b []byte) error { - if !bytes.HasPrefix(b, []byte{'u'}) { - return errMissingU8Prefix - } - n, err := strconv.Atoi(string(b[1:])) - if err != nil { - return err - } - *u8 = u8marshal(n) - return nil -} - -var _ encoding.TextUnmarshaler = (*u8marshal)(nil) - -var ( - umtrue = unmarshaler{true} - umslice = []unmarshaler{{true}} - umstruct = ustruct{unmarshaler{true}} - - umtrueXY = unmarshalerText{"x", "y"} - umsliceXY = []unmarshalerText{{"x", "y"}} - umstructXY = ustructText{unmarshalerText{"x", "y"}} - - ummapXY = map[unmarshalerText]bool{{"x", "y"}: true} -) - -// Test data structures for anonymous fields. - -type Point struct { - Z int -} - -type Top struct { - Level0 int - Embed0 - *Embed0a - *Embed0b `json:"e,omitempty"` // treated as named - Embed0c `json:"-"` // ignored - Loop - Embed0p // has Point with X, Y, used - Embed0q // has Point with Z, used - embed // contains exported field -} - -type Embed0 struct { - Level1a int // overridden by Embed0a's Level1a with json tag - Level1b int // used because Embed0a's Level1b is renamed - Level1c int // used because Embed0a's Level1c is ignored - Level1d int // annihilated by Embed0a's Level1d - Level1e int `json:"x"` // annihilated by Embed0a.Level1e -} - -type Embed0a struct { - Level1a int `json:"Level1a,omitempty"` - Level1b int `json:"LEVEL1B,omitempty"` - Level1c int `json:"-"` - Level1d int // annihilated by Embed0's Level1d - Level1f int `json:"x"` // annihilated by Embed0's Level1e -} - -type Embed0b Embed0 - -type Embed0c Embed0 - -type Embed0p struct { - image.Point -} - -type Embed0q struct { - Point -} - -type embed struct { - Q int -} - -type Loop struct { - Loop1 int `json:",omitempty"` - Loop2 int `json:",omitempty"` - *Loop -} - -// From reflect test: -// The X in S6 and S7 annihilate, but they also block the X in S8.S9. -type S5 struct { - S6 - S7 - S8 -} - -type S6 struct { - X int -} - -type S7 S6 - -type S8 struct { - S9 -} - -type S9 struct { - X int - Y int -} - -// From reflect test: -// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. -type S10 struct { - S11 - S12 - S13 -} - -type S11 struct { - S6 -} - -type S12 struct { - S6 -} - -type S13 struct { - S8 -} - -type Ambig struct { - // Given "hello", the first match should win. - First int `json:"HELLO"` - Second int `json:"Hello"` -} - -type XYZ struct { - X interface{} - Y interface{} - Z interface{} -} - -type byteWithMarshalJSON byte - -func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil -} - -func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalJSON(i) - return nil -} - -type byteWithPtrMarshalJSON byte - -func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return byteWithMarshalJSON(*b).MarshalJSON() -} - -func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type byteWithMarshalText byte - -func (b byteWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil -} - -func (b *byteWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalText(i) - return nil -} - -type byteWithPtrMarshalText byte - -func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { - return byteWithMarshalText(*b).MarshalText() -} - -func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*byteWithMarshalText)(b).UnmarshalText(data) -} - -type intWithMarshalJSON int - -func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil -} - -func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalJSON(i) - return nil -} - -type intWithPtrMarshalJSON int - -func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return intWithMarshalJSON(*b).MarshalJSON() -} - -func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*intWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type intWithMarshalText int - -func (b intWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil -} - -func (b *intWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalText(i) - return nil -} - -type intWithPtrMarshalText int - -func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { - return intWithMarshalText(*b).MarshalText() -} - -func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*intWithMarshalText)(b).UnmarshalText(data) -} - -type mapStringToStringData struct { - Data map[string]string `json:"data"` -} - -type unmarshalTest struct { - in string - ptr interface{} // new(type) - out interface{} - err error - useNumber bool - golden bool - disallowUnknownFields bool - validateString bool -} - -type B struct { - B bool `json:",string"` -} - -type DoublePtr struct { - I **int - J **int -} - -type JsonSyntaxError struct { - Msg string - Offset int64 -} - -func (self *JsonSyntaxError) err() *json.SyntaxError { - return (*json.SyntaxError)(unsafe.Pointer(self)) -} - -var unmarshalTests = []unmarshalTest{ - // basic types - {in: `true`, ptr: new(bool), out: true}, - {in: `1`, ptr: new(int), out: 1}, - {in: `1.2`, ptr: new(float64), out: 1.2}, - {in: `-5`, ptr: new(int16), out: int16(-5)}, - {in: `2`, ptr: new(json.Number), out: json.Number("2"), useNumber: true}, - {in: `2`, ptr: new(json.Number), out: json.Number("2")}, - {in: `2`, ptr: new(interface{}), out: 2.0}, - {in: `2`, ptr: new(interface{}), out: json.Number("2"), useNumber: true}, - {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, - {in: `"http:\/\/"`, ptr: new(string), out: "http://"}, - {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, - {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, - {in: "null", ptr: new(interface{}), out: nil}, - {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(""), Offset: 7, Struct: "T", Field: "X"}}, - {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 8, Struct: "T", Field: "X"}}, - {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, - {in: `{"S": 23}`, ptr: new(W), out: W{}, err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS("")), Struct: "W", Field: "S"}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: json.Number("3")}}, - {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: json.Number("1"), F2: int32(2), F3: json.Number("3")}, useNumber: true}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, - {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, - {in: `{"":""}`, ptr: new(struct{}), out: struct{}{}}, - {in: `{"x":""}`, ptr: new(struct{ X json.Number }), err: errors.New("empty string into json number")}, - - // raw values with whitespace - {in: "\n true ", ptr: new(bool), out: true}, - {in: "\t 1 ", ptr: new(int), out: 1}, - {in: "\r 1.2 ", ptr: new(float64), out: 1.2}, - {in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, - {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, - - // Z has a "-" tag. - {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, - {in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, - - {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, - {in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - - // syntax errors - {in: `{"X": "foo", "Y"}`, err: (&JsonSyntaxError{"invalid character '}' after object key", 17}).err()}, - {in: `[1, 2, 3+]`, err: (&JsonSyntaxError{"invalid character '+' after array element", 9}).err()}, - {in: `{"X":12x}`, err: (&JsonSyntaxError{"invalid character 'x' after object key:value pair", 8}).err(), useNumber: true}, - {in: `[2, 3`, err: (&JsonSyntaxError{Msg: "unexpected end of JSON input", Offset: 5}).err()}, - {in: `{"F3": -}`, ptr: new(V), out: V{F3: json.Number("-")}, err: (&JsonSyntaxError{Msg: "invalid character '}' in numeric literal", Offset: 9}).err()}, - - // raw value errors - {in: "\x01 42", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - {in: " 42 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 5}).err()}, - {in: "\x01 true", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - {in: " false \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 8}).err()}, - {in: "\x01 1.2", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - {in: " 3.4 \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 6}).err()}, - {in: "\x01 \"string\"", err: (&JsonSyntaxError{"invalid character '\\x01' looking for beginning of value", 1}).err()}, - {in: " \"string\" \x01", err: (&JsonSyntaxError{"invalid character '\\x01' after top-level value", 11}).err()}, - - // array tests - {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, - {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, - {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, - {in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")}, - - // empty array to interface test - {in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, - {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)}, - {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}}, - {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, - - // composite tests - {in: allValueIndent, ptr: new(All), out: allValue}, - {in: allValueCompact, ptr: new(All), out: allValue}, - {in: allValueIndent, ptr: new(*All), out: &allValue}, - {in: allValueCompact, ptr: new(*All), out: &allValue}, - {in: pallValueIndent, ptr: new(All), out: pallValue}, - {in: pallValueCompact, ptr: new(All), out: pallValue}, - {in: pallValueIndent, ptr: new(*All), out: &pallValue}, - {in: pallValueCompact, ptr: new(*All), out: &pallValue}, - - // unmarshal interface test - {in: `{"T":false}`, ptr: new(unmarshaler), out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called - {in: `{"T":false}`, ptr: new(*unmarshaler), out: &umtrue}, - {in: `[{"T":false}]`, ptr: new([]unmarshaler), out: umslice}, - {in: `[{"T":false}]`, ptr: new(*[]unmarshaler), out: &umslice}, - {in: `{"M":{"T":"x:y"}}`, ptr: new(ustruct), out: umstruct}, - - // UnmarshalText interface test - {in: `"x:y"`, ptr: new(unmarshalerText), out: umtrueXY}, - {in: `"x:y"`, ptr: new(*unmarshalerText), out: &umtrueXY}, - {in: `["x:y"]`, ptr: new([]unmarshalerText), out: umsliceXY}, - {in: `["x:y"]`, ptr: new(*[]unmarshalerText), out: &umsliceXY}, - {in: `{"M":"x:y"}`, ptr: new(ustructText), out: umstructXY}, - - // integer-keyed map test - { - in: `{"-1":"a","0":"b","1":"c"}`, - ptr: new(map[int]string), - out: map[int]string{-1: "a", 0: "b", 1: "c"}, - }, - { - in: `{"0":"a","10":"c","9":"b"}`, - ptr: new(map[u8]string), - out: map[u8]string{0: "a", 9: "b", 10: "c"}, - }, - { - in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, - ptr: new(map[int64]string), - out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, - }, - { - in: `{"18446744073709551615":"max"}`, - ptr: new(map[uint64]string), - out: map[uint64]string{math.MaxUint64: "max"}, - }, - { - in: `{"0":false,"10":true}`, - ptr: new(map[uintptr]bool), - out: map[uintptr]bool{0: false, 10: true}, - }, - - // Check that MarshalText and UnmarshalText take precedence - // over default integer handling in map keys. - { - in: `{"u2":4}`, - ptr: new(map[u8marshal]int), - out: map[u8marshal]int{2: 4}, - }, - { - in: `{"2":4}`, - ptr: new(map[u8marshal]int), - err: errMissingU8Prefix, - }, - - // integer-keyed map errors - { - in: `{"abc":"abc"}`, - ptr: new(map[int]string), - err: &json.UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2}, - }, - { - in: `{"256":"abc"}`, - ptr: new(map[uint8]string), - err: &json.UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2}, - }, - { - in: `{"128":"abc"}`, - ptr: new(map[int8]string), - err: &json.UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2}, - }, - { - in: `{"-1":"abc"}`, - ptr: new(map[uint8]string), - err: &json.UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2}, - }, - { - in: `{"F":{"a":2,"3":4}}`, - ptr: new(map[string]map[int]int), - err: &json.UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(0), Offset: 7}, - }, - { - in: `{"F":{"a":2,"3":4}}`, - ptr: new(map[string]map[uint]int), - err: &json.UnmarshalTypeError{Value: "number a", Type: reflect.TypeOf(uint(0)), Offset: 7}, - }, - - // Map keys can be encoding.TextUnmarshalers. - {in: `{"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY}, - // If multiple values for the same key exists, only the most recent value is used. - {in: `{"x:y":false,"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY}, - - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - out: Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - }, - }, - { - in: `{"hello": 1}`, - ptr: new(Ambig), - out: Ambig{First: 1}, - }, - - { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - out: S5{S8: S8{S9: S9{Y: 2}}}, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, - }, - { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - { - in: `{"I": 0, "I": null, "J": null}`, - ptr: new(DoublePtr), - out: DoublePtr{I: nil, J: nil}, - }, - - // invalid UTF-8 is coerced to valid UTF-8. - { - in: "\"hello\xffworld\"", - ptr: new(string), - out: "hello\xffworld", - validateString: false, - }, - { - in: "\"hello\xc2\xc2world\"", - ptr: new(string), - out: "hello\xc2\xc2world", - validateString: false, - }, - { - in: "\"hello\xc2\xffworld\"", - ptr: new(string), - out: "hello\xc2\xffworld", - }, - { - in: "\"hello\\ud800world\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", - ptr: new(string), - out: "hello\xed\xa0\x80\xed\xb0\x80world", - }, - - // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: new(map[time.Time]string), - out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, - }, - - // issue 8305 - { - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: new(map[Point]string), - err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1}, - }, - { - in: `{"asdf": "hello world"}`, - ptr: new(map[unmarshaler]string), - err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1}, - }, - - // related to issue 13783. - // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, - // similar to marshaling a slice of typed int. - // These tests check that, assuming the byte type also has valid decoding methods, - // either the old base64 string encoding or the new per-element encoding can be - // successfully unmarshaled. The custom unmarshalers were accessible in earlier - // versions of Go, even though the custom marshaler was not. - { - in: `"AQID"`, - ptr: new([]byteWithMarshalJSON), - out: []byteWithMarshalJSON{1, 2, 3}, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithMarshalJSON), - out: []byteWithMarshalJSON{1, 2, 3}, - golden: true, - }, - { - in: `"AQID"`, - ptr: new([]byteWithMarshalText), - out: []byteWithMarshalText{1, 2, 3}, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithMarshalText), - out: []byteWithMarshalText{1, 2, 3}, - golden: true, - }, - { - in: `"AQID"`, - ptr: new([]byteWithPtrMarshalJSON), - out: []byteWithPtrMarshalJSON{1, 2, 3}, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithPtrMarshalJSON), - out: []byteWithPtrMarshalJSON{1, 2, 3}, - golden: true, - }, - { - in: `"AQID"`, - ptr: new([]byteWithPtrMarshalText), - out: []byteWithPtrMarshalText{1, 2, 3}, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithPtrMarshalText), - out: []byteWithPtrMarshalText{1, 2, 3}, - golden: true, - }, - - // ints work with the marshaler but not the base64 []byte case - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithMarshalJSON), - out: []intWithMarshalJSON{1, 2, 3}, - golden: true, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithMarshalText), - out: []intWithMarshalText{1, 2, 3}, - golden: true, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithPtrMarshalJSON), - out: []intWithPtrMarshalJSON{1, 2, 3}, - golden: true, - }, - { - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithPtrMarshalText), - out: []intWithPtrMarshalText{1, 2, 3}, - golden: true, - }, - - {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true}, - {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true}, - {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true}, - {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true}, - {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true}, - {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true}, - {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true}, - {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true}, - {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true}, - {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true}, - {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false}, - - { - in: `{"V": {"F2": "hello"}}`, - ptr: new(VOuter), - err: &json.UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "V.F2", - Type: reflect.TypeOf(int32(0)), - Offset: 20, - }, - }, - { - in: `{"V": {"F4": {}, "F2": "hello"}}`, - ptr: new(VOuter), - err: &json.UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "V.F2", - Type: reflect.TypeOf(int32(0)), - Offset: 30, - }, - }, - - // issue 15146. - // invalid inputs in wrongStringTests below. - {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true}, - {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true}, - {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)}, - {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)}, - {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, - {in: `{"B": "null"}`, ptr: new(B), out: B{false}}, - {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, - {in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)}, - - // additional tests for disallowUnknownFields - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18, - "extra": true - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - { - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12, - "extra": null - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - // issue 26444 - // json.UnmarshalTypeError without field & struct values - { - in: `{"data":{"test1": "bob", "test2": 123}}`, - ptr: new(mapStringToStringData), - err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, - }, - { - in: `{"data":{"test1": 123, "test2": "bob"}}`, - ptr: new(mapStringToStringData), - err: &json.UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, - }, - - // trying to decode JSON arrays or objects via TextUnmarshaler - { - in: `[1, 2, 3]`, - ptr: new(MustNotUnmarshalText), - err: &json.UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - }, - { - in: `{"foo": "bar"}`, - ptr: new(MustNotUnmarshalText), - err: &json.UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1}, - }, - // #22369 - { - in: `{"PP": {"T": {"Y": "bad-type"}}}`, - ptr: new(P), - err: &json.UnmarshalTypeError{ - Value: "string", - Struct: "T", - Field: "PP.T.Y", - Type: reflect.TypeOf(0), - Offset: 29, - }, - }, - { - in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`, - ptr: new(PP), - err: &json.UnmarshalTypeError{ - Value: "string", - Struct: "T", - Field: "Ts.Y", - Type: reflect.TypeOf(0), - Offset: 29, - }, - }, - // #14702 - { - in: `invalid`, - ptr: new(json.Number), - err: (&JsonSyntaxError{ - Msg: "invalid character 'i' looking for beginning of value", - Offset: 1, - }).err(), - }, - { - in: `"invalid"`, - ptr: new(json.Number), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, - { - in: `{"A":"invalid"}`, - ptr: new(struct{ A json.Number }), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, - { - in: `{"A":"invalid"}`, - ptr: new(struct { - A json.Number `json:",string"` - }), - err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into json.Number", `invalid`), - }, - { - in: `{"A":"invalid"}`, - ptr: new(map[string]json.Number), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, - {in: `\u`, ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, - {in: `\u`, ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, - - {in: "\"\x00\"", ptr: new(interface{}), err: fmt.Errorf("json: invald char"), validateString: true}, - {in: "\"\x00\"", ptr: new(string), err: fmt.Errorf("json: invald char"), validateString: true}, - {in: "\"\xff\"", ptr: new(interface{}), out: interface{}("\ufffd"), validateString: true}, - {in: "\"\xff\"", ptr: new(string), out: "\ufffd", validateString: true}, - {in: "\"\x00\"", ptr: new(interface{}), out: interface{}("\x00"), validateString: false}, - {in: "\"\x00\"", ptr: new(string), out: "\x00", validateString: false}, - {in: "\"\xff\"", ptr: new(interface{}), out: interface{}("\xff"), validateString: false}, - {in: "\"\xff\"", ptr: new(string), out: "\xff", validateString: false}, -} - -func trim(b []byte) []byte { - if len(b) > 20 { - return b[0:20] - } - return b -} - -func diff(t *testing.T, a, b []byte) { - for i := 0; ; i++ { - if i >= len(a) || i >= len(b) || a[i] != b[i] { - j := i - 10 - if j < 0 { - j = 0 - } - t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:])) - return - } - } -} - -func TestMarshal(t *testing.T) { - b, err := Marshal(allValue) - if err != nil { - t.Fatalf("Marshal allValue: %v", err) - } - if string(b) != allValueCompact { - t.Errorf("Marshal allValueCompact") - diff(t, b, []byte(allValueCompact)) - return - } - - b, err = Marshal(pallValue) - if err != nil { - t.Fatalf("Marshal pallValue: %v", err) - } - if string(b) != pallValueCompact { - t.Errorf("Marshal pallValueCompact") - diff(t, b, []byte(pallValueCompact)) - return - } -} - -func TestMarshalNumberZeroVal(t *testing.T) { - var n json.Number - out, err := Marshal(n) - if err != nil { - t.Fatal(err) - } - outStr := string(out) - if outStr != "0" { - t.Fatalf("Invalid zero val for json.Number: %q", outStr) - } -} - -func TestMarshalEmbeds(t *testing.T) { - top := &Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - } - b, err := Marshal(top) - if err != nil { - t.Fatal(err) - } - want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}" - if string(b) != want { - t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want) - } -} - -func TestUnmarshal(t *testing.T) { - for i, tt := range unmarshalTests { - if !json.Valid([]byte(tt.in)) { - continue - } - if tt.ptr == nil { - continue - } - - typ := reflect.TypeOf(tt.ptr) - if typ.Kind() != reflect.Ptr { - t.Errorf("#%d: unmarshalTest.ptr %T is not a pointer type", i, tt.ptr) - continue - } - typ = typ.Elem() - - // v = new(right-type) - v := reflect.New(typ) - - if !reflect.DeepEqual(tt.ptr, v.Interface()) { - // There's no reason for ptr to point to non-zero data, - // as we decode into new(right-type), so the data is - // discarded. - // This can easily mean tests that silently don't test - // what they should. To test decoding into existing - // data, see TestPrefilled. - t.Errorf("#%d: unmarshalTest.ptr %#v is not a pointer to a zero value", i, tt.ptr) - continue - } - - dec := decoder.NewDecoder(tt.in) - if tt.useNumber { - dec.UseNumber() - } - if tt.disallowUnknownFields { - dec.DisallowUnknownFields() - } - if tt.validateString { - dec.ValidateString() - } - if err := dec.Decode(v.Interface()); (err == nil) != (tt.err == nil) { - spew.Dump(tt) - t.Fatalf("#%d: %v, want %v", i, err, tt.err) - continue - } else if err != nil { - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out) - data, _ := Marshal(v.Elem().Interface()) - println(string(data)) - data, _ = Marshal(tt.out) - println(string(data)) - continue - } - - // Check round trip also decodes correctly. - if tt.err == nil { - enc, err := Marshal(v.Interface()) - if err != nil { - t.Errorf("#%d: error re-marshaling: %v", i, err) - continue - } - if tt.golden && !bytes.Equal(enc, []byte(tt.in)) { - t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, []byte(tt.in)) - } - vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec = decoder.NewDecoder(string(enc)) - if tt.useNumber { - dec.UseNumber() - } - if err := dec.Decode(vv.Interface()); err != nil { - t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err) - continue - } - if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { - t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface()) - t.Errorf(" In: %q", strings.Map(noSpace, tt.in)) - t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc))) - continue - } - } - } -} - -var jsonBig []byte - -func initBig() { - n := 10000 - if testing.Short() { - n = 100 - } - b, err := Marshal(genValue(n)) - if err != nil { - panic(err) - } - jsonBig = b -} - -func genValue(n int) interface{} { - if n > 1 { - switch rand.Intn(2) { - case 0: - return genArray(n) - case 1: - return genMap(n) - } - } - switch rand.Intn(3) { - case 0: - return rand.Intn(2) == 0 - case 1: - return float64(rand.Uint64()) / 4294967296 - case 2: - return genString(30) - } - panic("unreachable") -} - -func genString(stddev float64) string { - n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2)) - c := make([]rune, n) - for i := range c { - f := math.Abs(rand.NormFloat64()*64 + 32) - if f > 0x10ffff { - f = 0x10ffff - } - c[i] = rune(f) - } - return string(c) -} - -func genArray(n int) []interface{} { - f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) - if f > n { - f = n - } - if f < 1 { - f = 1 - } - x := make([]interface{}, f) - for i := range x { - x[i] = genValue(((i+1)*n)/f - (i*n)/f) - } - return x -} - -func genMap(n int) map[string]interface{} { - f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2))) - if f > n { - f = n - } - if n > 0 && f == 0 { - f = 1 - } - x := make(map[string]interface{}) - x[genString(10)] = genValue(n/f) - return x -} - -func TestUnmarshalMarshal(t *testing.T) { - initBig() - var v interface{} - if err := Unmarshal(jsonBig, &v); err != nil { - if e, ok := err.(decoder.SyntaxError); ok { - println(e.Description()) - } - t.Fatalf("Unmarshal: %v", err) - } - b, err := Marshal(v) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if !bytes.Equal(jsonBig, b) { - t.Errorf("Marshal jsonBig") - diff(t, b, jsonBig) - println(string(b)) - println(string(jsonBig)) - return - } -} - -var numberTests = []struct { - in string - i int64 - intErr string - f float64 - floatErr string -}{ - {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, - {in: "-12", i: -12, f: -12.0}, - {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, -} - -// Independent of Decode, basic coverage of the accessors in json.Number -func TestNumberAccessors(t *testing.T) { - for _, tt := range numberTests { - n := json.Number(tt.in) - if s := n.String(); s != tt.in { - t.Errorf("json.Number(%q).String() is %q", tt.in, s) - } - if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { - t.Errorf("json.Number(%q).Int64() is %d", tt.in, i) - } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { - t.Errorf("json.Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err) - } - if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { - t.Errorf("json.Number(%q).Float64() is %g", tt.in, f) - } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { - t.Errorf("json.Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err) - } - } -} - -func TestLargeByteSlice(t *testing.T) { - s0 := make([]byte, 2000) - for i := range s0 { - s0[i] = byte(i) - } - b, err := Marshal(s0) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - var s1 []byte - if err := Unmarshal(b, &s1); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !bytes.Equal(s0, s1) { - t.Errorf("Marshal large byte slice") - diff(t, s0, s1) - } -} - -type Xint struct { - X int -} - -func TestUnmarshalPtrPtr(t *testing.T) { - var xint Xint - pxint := &xint - if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("Did not write to xint") - } -} - -func isSpace(c byte) bool { - return c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') -} - -func noSpace(c rune) rune { - if isSpace(byte(c)) { // only used for ascii - return -1 - } - return c -} - -type All struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Uintptr uintptr - Float32 float32 - Float64 float64 - - Foo string `json:"bar"` - Foo2 string `json:"bar2,dummyopt"` - - IntStr int64 `json:",string"` - UintptrStr uintptr `json:",string"` - - PBool *bool - PInt *int - PInt8 *int8 - PInt16 *int16 - PInt32 *int32 - PInt64 *int64 - PUint *uint - PUint8 *uint8 - PUint16 *uint16 - PUint32 *uint32 - PUint64 *uint64 - PUintptr *uintptr - PFloat32 *float32 - PFloat64 *float64 - - String string - PString *string - - Map map[string]Small - MapP map[string]*Small - MapPNil map[string]*Small - PMap *map[string]Small - PMapP *map[string]*Small - PMapPNil *map[string]*Small - - EmptyMap map[string]Small - NilMap map[string]Small - - Slice []Small - SliceP []*Small - PSlice *[]Small - PSliceP *[]*Small - - EmptySlice []Small - NilSlice []Small - - StringSlice []string - ByteSlice []byte - - Small Small - PSmall *Small - PPSmall **Small - - Interface interface{} - PInterface *interface{} - - unexported int -} - -type Small struct { - Tag string -} - -var allValue = All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Uintptr: 12, - Float32: 14.25, - Float64: 15.25, - Foo: "foo", - Foo2: "foo2", - IntStr: 42, - UintptrStr: 44, - String: "16", - Map: map[string]Small{ - "17": {Tag: "tag17"}, - }, - MapP: map[string]*Small{ - "18": {Tag: "tag19"}, - }, - MapPNil: map[string]*Small{ - "19": nil, - }, - EmptyMap: map[string]Small{}, - Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, - SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, - EmptySlice: []Small{}, - StringSlice: []string{"str24", "str25", "str26"}, - ByteSlice: []byte{27, 28, 29}, - Small: Small{Tag: "tag30"}, - PSmall: &Small{Tag: "tag31"}, - Interface: 5.2, -} - -var pallValue = All{ - PBool: &allValue.Bool, - PInt: &allValue.Int, - PInt8: &allValue.Int8, - PInt16: &allValue.Int16, - PInt32: &allValue.Int32, - PInt64: &allValue.Int64, - PUint: &allValue.Uint, - PUint8: &allValue.Uint8, - PUint16: &allValue.Uint16, - PUint32: &allValue.Uint32, - PUint64: &allValue.Uint64, - PUintptr: &allValue.Uintptr, - PFloat32: &allValue.Float32, - PFloat64: &allValue.Float64, - PString: &allValue.String, - PMap: &allValue.Map, - PMapP: &allValue.MapP, - PMapPNil: &allValue.MapPNil, - PSlice: &allValue.Slice, - PSliceP: &allValue.SliceP, - PPSmall: &allValue.PSmall, - PInterface: &allValue.Interface, -} - -var allValueIndent = `{ - "Bool": true, - "Int": 2, - "Int8": 3, - "Int16": 4, - "Int32": 5, - "Int64": 6, - "Uint": 7, - "Uint8": 8, - "Uint16": 9, - "Uint32": 10, - "Uint64": 11, - "Uintptr": 12, - "Float32": 14.25, - "Float64": 15.25, - "bar": "foo", - "bar2": "foo2", - "IntStr": "42", - "UintptrStr": "44", - "PBool": null, - "PInt": null, - "PInt8": null, - "PInt16": null, - "PInt32": null, - "PInt64": null, - "PUint": null, - "PUint8": null, - "PUint16": null, - "PUint32": null, - "PUint64": null, - "PUintptr": null, - "PFloat32": null, - "PFloat64": null, - "String": "16", - "PString": null, - "Map": { - "17": { - "Tag": "tag17" - } - }, - "MapP": { - "18": { - "Tag": "tag19" - } - }, - "MapPNil": { - "19": null - }, - "PMap": null, - "PMapP": null, - "PMapPNil": null, - "EmptyMap": {}, - "NilMap": null, - "Slice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "SliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "PSlice": null, - "PSliceP": null, - "EmptySlice": [], - "NilSlice": null, - "StringSlice": [ - "str24", - "str25", - "str26" - ], - "ByteSlice": "Gxwd", - "Small": { - "Tag": "tag30" - }, - "PSmall": { - "Tag": "tag31" - }, - "PPSmall": null, - "Interface": 5.2, - "PInterface": null -}` - -var allValueCompact = strings.Map(noSpace, allValueIndent) - -var pallValueIndent = `{ - "Bool": false, - "Int": 0, - "Int8": 0, - "Int16": 0, - "Int32": 0, - "Int64": 0, - "Uint": 0, - "Uint8": 0, - "Uint16": 0, - "Uint32": 0, - "Uint64": 0, - "Uintptr": 0, - "Float32": 0, - "Float64": 0, - "bar": "", - "bar2": "", - "IntStr": "0", - "UintptrStr": "0", - "PBool": true, - "PInt": 2, - "PInt8": 3, - "PInt16": 4, - "PInt32": 5, - "PInt64": 6, - "PUint": 7, - "PUint8": 8, - "PUint16": 9, - "PUint32": 10, - "PUint64": 11, - "PUintptr": 12, - "PFloat32": 14.25, - "PFloat64": 15.25, - "String": "", - "PString": "16", - "Map": null, - "MapP": null, - "MapPNil": null, - "PMap": { - "17": { - "Tag": "tag17" - } - }, - "PMapP": { - "18": { - "Tag": "tag19" - } - }, - "PMapPNil": { - "19": null - }, - "EmptyMap": null, - "NilMap": null, - "Slice": null, - "SliceP": null, - "PSlice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "PSliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "EmptySlice": null, - "NilSlice": null, - "StringSlice": null, - "ByteSlice": null, - "Small": { - "Tag": "" - }, - "PSmall": null, - "PPSmall": { - "Tag": "tag31" - }, - "Interface": null, - "PInterface": 5.2 -}` - -var pallValueCompact = strings.Map(noSpace, pallValueIndent) - -func TestRefUnmarshal(t *testing.T) { - type S struct { - // Ref is defined in encode_test.go. - R0 Ref - R1 *Ref - R2 RefText - R3 *RefText - } - want := S{ - R0: 12, - R1: new(Ref), - R2: 13, - R3: new(RefText), - } - *want.R1 = 12 - *want.R3 = 13 - - var got S - if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(got, want) { - t.Errorf("got %+v, want %+v", got, want) - } -} - -// Test that the empty string doesn't panic decoding when ,string is specified -// Issue 3450 -func TestEmptyString(t *testing.T) { - type T2 struct { - Number1 int `json:",string"` - Number2 string `json:",string"` - Pass bool `json:",string"` - } - data := `{"Number1":"1", "Number2":"","Pass":"true"}` - var t2, t3 T2 - t2.Number2 = "a" - t3.Number2 = "a" - err := Unmarshal([]byte(data), &t2) - if err == nil { - t.Fatal("Decode: did not return error") - } - println(err.Error()) - err2 := json.Unmarshal([]byte(data), &t3) - assert.Equal(t, err == nil, err2 == nil) - assert.Equal(t, t3, t2) -} - -// Test that a null for ,string is not replaced with the previous quoted string (issue 7046). -// It should also not be an error (issue 2540, issue 8587). -func TestNullString(t *testing.T) { - type T struct { - A int `json:",string"` - B int `json:",string"` - C *int `json:",string"` - } - data := []byte(`{"A": "1", "B": null, "C": null}`) - var s T - s.B = 1 - s.C = new(int) - *s.C = 2 - err := Unmarshal(data, &s) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if s.B != 1 || s.C != nil { - t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) - } -} - -type NullTest struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Float32 float32 - Float64 float64 - String string - PBool *bool - Map map[string]string - Slice []string - Interface interface{} - - PRaw *json.RawMessage - PTime *time.Time - PBigInt *big.Int - PText *MustNotUnmarshalText - PBuffer *bytes.Buffer // has methods, just not relevant ones - PStruct *struct{} - - Raw json.RawMessage - Time time.Time - BigInt big.Int - Text MustNotUnmarshalText - Buffer bytes.Buffer - Struct struct{} -} - -// JSON null values should be ignored for primitives and string values instead of resulting in an error. -// Issue 2540 -func TestUnmarshalNulls(t *testing.T) { - // Unmarshal docs: - // The JSON null value unmarshals into an interface, map, pointer, or slice - // by setting that Go value to nil. Because null is often used in JSON to mean - // ``not present,'' unmarshaling a JSON null into any other Go type has no effect - // on the value and produces no error. - - jsonData := []byte(`{ - "Bool" : null, - "Int" : null, - "Int8" : null, - "Int16" : null, - "Int32" : null, - "Int64" : null, - "Uint" : null, - "Uint8" : null, - "Uint16" : null, - "Uint32" : null, - "Uint64" : null, - "Float32" : null, - "Float64" : null, - "String" : null, - "PBool": null, - "Map": null, - "Slice": null, - "Interface": null, - "PRaw": null, - "PTime": null, - "PBigInt": null, - "PText": null, - "PBuffer": null, - "PStruct": null, - "Raw": null, - "Time": null, - "BigInt": null, - "Text": null, - "Buffer": null, - "Struct": null - }`) - nulls := NullTest{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Float32: 12.1, - Float64: 13.1, - String: "14", - PBool: new(bool), - Map: map[string]string{}, - Slice: []string{}, - Interface: new(MustNotUnmarshalJSON), - PRaw: new(json.RawMessage), - PTime: new(time.Time), - PBigInt: new(big.Int), - PText: new(MustNotUnmarshalText), - PStruct: new(struct{}), - PBuffer: new(bytes.Buffer), - Raw: json.RawMessage("123"), - Time: time.Unix(123456789, 0), - BigInt: *big.NewInt(123), - } - - before := nulls.Time.String() - - err := Unmarshal(jsonData, &nulls) - if err != nil { - t.Errorf("Unmarshal of null values failed: %v", err) - } - if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || - nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || - nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { - t.Errorf("Unmarshal of null values affected primitives") - } - - if nulls.PBool != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBool") - } - if nulls.Map != nil { - t.Errorf("Unmarshal of null did not clear nulls.Map") - } - if nulls.Slice != nil { - t.Errorf("Unmarshal of null did not clear nulls.Slice") - } - if nulls.Interface != nil { - t.Errorf("Unmarshal of null did not clear nulls.Interface") - } - if nulls.PRaw != nil { - t.Errorf("Unmarshal of null did not clear nulls.PRaw") - } - if nulls.PTime != nil { - t.Errorf("Unmarshal of null did not clear nulls.PTime") - } - if nulls.PBigInt != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBigInt") - } - if nulls.PText != nil { - t.Errorf("Unmarshal of null did not clear nulls.PText") - } - if nulls.PBuffer != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBuffer") - } - if nulls.PStruct != nil { - t.Errorf("Unmarshal of null did not clear nulls.PStruct") - } - - if string(nulls.Raw) != "null" { - t.Errorf("Unmarshal of json.RawMessage null did not record null: %v", string(nulls.Raw)) - } - if nulls.Time.String() != before { - t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String()) - } - if nulls.BigInt.String() != "123" { - t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String()) - } -} - -type MustNotUnmarshalJSON struct{} - -func (x MustNotUnmarshalJSON) UnmarshalJSON(_ []byte) error { - return errors.New("MustNotUnmarshalJSON was used") -} - -type MustNotUnmarshalText struct{} - -func (x MustNotUnmarshalText) UnmarshalText(_ []byte) error { - return errors.New("MustNotUnmarshalText was used") -} - -func TestStringKind(t *testing.T) { - type stringKind string - - var m1, m2 map[stringKind]int - m1 = map[stringKind]int{ - "foo": 42, - } - - data, err := Marshal(m1) - if err != nil { - t.Errorf("Unexpected error marshaling: %v", err) - } - - err = Unmarshal(data, &m2) - if err != nil { - t.Errorf("Unexpected error unmarshaling: %v", err) - } - - if !reflect.DeepEqual(m1, m2) { - t.Error("Items should be equal after encoding and then decoding") - } -} - -// Custom types with []byte as underlying type could not be marshaled -// and then unmarshaled. -// Issue 8962. -func TestByteKind(t *testing.T) { - type byteKind []byte - - a := byteKind("hello") - - data, err := Marshal(a) - if err != nil { - t.Error(err) - } - var b byteKind - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Errorf("expected %v == %v", a, b) - } -} - -// The fix for issue 8962 introduced a regression. -// Issue 12921. -func TestSliceOfCustomByte(t *testing.T) { - type Uint8 uint8 - - a := []Uint8("hello") - - data, err := Marshal(a) - if err != nil { - t.Fatal(err) - } - var b []Uint8 - err = Unmarshal(data, &b) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, b) { - t.Fatalf("expected %v == %v", a, b) - } -} - -var decodeTypeErrorTests = []struct { - dest interface{} - src string -}{ - {new(error), `{}`}, // issue 4222 - {new(error), `[]`}, - {new(error), `""`}, - {new(error), `123`}, - {new(error), `true`}, -} - -func TestUnmarshalTypeError(t *testing.T) { - for _, item := range decodeTypeErrorTests { - err := Unmarshal([]byte(item.src), item.dest) - if _, ok := err.(*json.UnmarshalTypeError); !ok { - if _, ok = err.(decoder.SyntaxError); !ok { - t.Errorf("expected type error for Unmarshal(%q, type %T): got %T", - item.src, item.dest, err) - } - } - } -} - -var decodeMismatchErrorTests = []struct { - dest interface{} - src string -}{ - {new(int), `{}`}, - {new(string), `{}`}, - {new(bool), `{}`}, - {new([]byte), `{}`}, -} - -func TestMismatchTypeError(t *testing.T) { - for _, item := range decodeMismatchErrorTests { - err := Unmarshal([]byte(item.src), item.dest) - if _, ok := err.(*decoder.MismatchTypeError); !ok { - if _, ok = err.(decoder.SyntaxError); !ok { - t.Errorf("expected mismatch error for Unmarshal(%q, type %T): got %T", - item.src, item.dest, err) - } - } - } -} - -var unmarshalSyntaxTests = []string{ - "tru", - "fals", - "nul", - "123e", - `"hello`, - `[1,2,3`, - `{"key":1`, - `{"key":1,`, -} - -func TestUnmarshalSyntax(t *testing.T) { - var x interface{} - for _, src := range unmarshalSyntaxTests { - err := Unmarshal([]byte(src), &x) - if _, ok := err.(decoder.SyntaxError); !ok { - t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err) - } - } -} - -// Test handling of unexported fields that should be ignored. -// Issue 4660 -//goland:noinspection GoVetStructTag -type unexportedFields struct { - Name string - m map[string]interface{} `json:"-"` - m2 map[string]interface{} `json:"abcd"` - - s []int `json:"-"` -} - -func TestUnmarshalUnexported(t *testing.T) { - input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}` - want := &unexportedFields{Name: "Bob"} - - out := &unexportedFields{} - err := Unmarshal([]byte(input), out) - if err != nil { - t.Errorf("got error %v, expected nil", err) - } - if !reflect.DeepEqual(out, want) { - t.Errorf("got %q, want %q", out, want) - } -} - -// Time3339 is a time.Time which encodes to and from JSON -// as an RFC 3339 time in UTC. -type Time3339 time.Time - -func (t *Time3339) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) - } - tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) - if err != nil { - return err - } - *t = Time3339(tm) - return nil -} - -func TestUnmarshalJSONLiteralError(t *testing.T) { - var t3 Time3339 - err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3) - if err == nil { - t.Fatalf("expected error; got time %v", time.Time(t3)) - } - if !strings.Contains(err.Error(), "range") { - t.Errorf("got err = %v; want out of range error", err) - } -} - -// Test that extra object elements in an array do not result in a -// "data changing underfoot" error. -// Issue 3717 -func TestSkipArrayObjects(t *testing.T) { - s := `[{}]` - var dest [0]interface{} - - err := Unmarshal([]byte(s), &dest) - if err != nil { - t.Errorf("got error %q, want nil", err) - } -} - -// Test semantics of pre-filled data, such as struct fields, map elements, -// slices, and arrays. -// Issues 4900 and 8837, among others. -func TestPrefilled(t *testing.T) { - // Values here change, cannot reuse table across runs. - var prefillTests = []struct { - in string - ptr interface{} - out interface{} - }{ - { - in: `{"X": 1, "Y": 2}`, - ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, - out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, - }, - { - in: `{"X": 1, "Y": 2}`, - ptr: &map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}, - out: &map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}, - }, - { - in: `[2]`, - ptr: &[]int{1}, - out: &[]int{2}, - }, - { - in: `[2, 3]`, - ptr: &[]int{1}, - out: &[]int{2, 3}, - }, - { - in: `[2, 3]`, - ptr: &[...]int{1}, - out: &[...]int{2}, - }, - { - in: `[3]`, - ptr: &[...]int{1, 2}, - out: &[...]int{3, 0}, - }, - } - - for _, tt := range prefillTests { - ptrstr := fmt.Sprintf("%v", tt.ptr) - err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here - if err != nil { - t.Errorf("Unmarshal: %v", err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out) - } - } -} - -var invalidUnmarshalTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, -} - -func TestInvalidUnmarshal(t *testing.T) { - buf := []byte(`{"a":"1"}`) - for _, tt := range invalidUnmarshalTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - if got := err.Error(); got != tt.want { - t.Errorf("Unmarshal = %q; want %q", got, tt.want) - } - } -} - -var invalidUnmarshalTextTests = []struct { - v interface{} - want string -}{ - {nil, "json: Unmarshal(nil)"}, - {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {(*int)(nil), "json: Unmarshal(nil *int)"}, - {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"}, -} - -func TestInvalidUnmarshalText(t *testing.T) { - buf := []byte(`123`) - for _, tt := range invalidUnmarshalTextTests { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Errorf("Unmarshal expecting error, got nil") - continue - } - } -} - -// Test that string option is ignored for invalid types. -// Issue 9812. -func TestInvalidStringOption(t *testing.T) { - num := 0 - item := struct { - T time.Time `json:",string"` - M map[string]string `json:",string"` - S []string `json:",string"` - A [1]string `json:",string"` - I interface{} `json:",string"` - P *int `json:",string"` - }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} - - data, err := Marshal(item) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - err = Unmarshal(data, &item) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } -} - -func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) { - tests := []struct { - in string - err error - }{{ - in: `1 false null :`, - err: (&JsonSyntaxError{"invalid character ':' looking for beginning of value", 13}).err(), - }, { - in: `1 [] [,]`, - err: (&JsonSyntaxError{"invalid character ',' looking for beginning of value", 6}).err(), - }, { - in: `1 [] [true:]`, - err: (&JsonSyntaxError{"invalid character ':' after array element", 10}).err(), - }, { - in: `1 {} {"x"=}`, - err: (&JsonSyntaxError{"invalid character '=' after object key", 13}).err(), - }, { - in: `falsetruenul#`, - err: (&JsonSyntaxError{"invalid character '#' in literal null (expecting 'l')", 12}).err(), - }} - for i, tt := range tests { - dec := decoder.NewDecoder(tt.in) - var err error - for { - var v interface{} - if err = dec.Decode(&v); err != nil { - break - } - } - if v, ok := err.(decoder.SyntaxError); !ok { - t.Errorf("#%d: got %#v, want %#v", i, err, tt.err) - } else if v.Pos != int(tt.err.(*json.SyntaxError).Offset) { - t.Errorf("#%d: got %#v, want %#v", i, err, tt.err) - println(v.Description()) - } - } -} - -type unmarshalPanic struct{} - -func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) } - -func TestUnmarshalPanic(t *testing.T) { - defer func() { - if got := recover(); !reflect.DeepEqual(got, 0xdead) { - t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) - } - }() - _ = Unmarshal([]byte("{}"), &unmarshalPanic{}) - t.Fatalf("Unmarshal should have panicked") -} - -// The decoder used to hang if decoding into an interface pointing to its own address. -// See golang.org/issues/31740. -func TestUnmarshalRecursivePointer(t *testing.T) { - var v interface{} - v = &v - data := []byte(`{"a": "b"}`) - - if err := Unmarshal(data, v); err != nil { - t.Fatal(err) - } -} - -type textUnmarshalerString string - -func (m *textUnmarshalerString) UnmarshalText(text []byte) error { - *m = textUnmarshalerString(strings.ToLower(string(text))) - return nil -} - -// Test unmarshal to a map, where the map key is a user defined type. -// See golang.org/issues/34437. -func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) { - var p map[textUnmarshalerString]string - if err := Unmarshal([]byte(`{"FOO": "1"}`), &p); err != nil { - t.Fatalf("Unmarshal unexpected error: %v", err) - } - - if _, ok := p["foo"]; !ok { - t.Errorf(`Key "foo" does not exist in map: %v`, p) - } -} - -func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) { - // See golang.org/issues/38105. - var p map[textUnmarshalerString]string - if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil { - t.Fatalf("Unmarshal unexpected error: %v", err) - } - if _, ok := p["开源"]; !ok { - t.Errorf(`Key "开源" does not exist in map: %v`, p) - } - - // See golang.org/issues/38126. - type T struct { - F1 string `json:"F1,string"` - } - t1 := T{"aaa\tbbb"} - - b, err := Marshal(t1) - if err != nil { - t.Fatalf("Marshal unexpected error: %v", err) - } - var t2 T - if err := Unmarshal(b, &t2); err != nil { - t.Fatalf("Unmarshal unexpected error: %v", err) - } - if t1 != t2 { - t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2) - } - - // See golang.org/issues/39555. - input := map[textUnmarshalerString]string{"FOO": "", `"`: ""} - - encoded, err := Marshal(input) - if err != nil { - t.Fatalf("Marshal unexpected error: %v", err) - } - var got map[textUnmarshalerString]string - if err := Unmarshal(encoded, &got); err != nil { - t.Fatalf("Unmarshal unexpected error: %v", err) - } - want := map[textUnmarshalerString]string{"foo": "", `"`: ""} - if !reflect.DeepEqual(want, got) { - t.Fatalf("Unexpected roundtrip result:\nwant: %q\ngot: %q", want, got) - } -} - -func TestUnmarshalMaxDepth(t *testing.T) { - const ( - _MaxDepth = types.MAX_RECURSE - _OverMaxDepth = types.MAX_RECURSE + 1 - _UnderMaxDepth = types.MAX_RECURSE - 2 - ) - testcases := []struct { - name string - data string - errMaxDepth bool - }{ - { - name: "ArrayUnderMaxNestingDepth", - data: `{"a":` + strings.Repeat(`[`, _UnderMaxDepth) + `0` + strings.Repeat(`]`, _UnderMaxDepth) + `}`, - errMaxDepth: false, - }, - { - name: "ArrayOverMaxNestingDepth", - data: `{"a":` + strings.Repeat(`[`, _OverMaxDepth) + `0` + strings.Repeat(`]`, _OverMaxDepth) + `}`, - errMaxDepth: true, - }, - { - name: "ArrayOverStackDepth", - data: `{"a":` + strings.Repeat(`[`, 3000000) + `0` + strings.Repeat(`]`, 3000000) + `}`, - errMaxDepth: true, - }, - { - name: "ObjectUnderMaxNestingDepth", - data: `{"a":` + strings.Repeat(`{"a":`, _UnderMaxDepth) + `0` + strings.Repeat(`}`, _UnderMaxDepth) + `}`, - errMaxDepth: false, - }, - { - name: "ObjectOverMaxNestingDepth", - data: `{"a":` + strings.Repeat(`{"a":`, _OverMaxDepth) + `0` + strings.Repeat(`}`, _OverMaxDepth) + `}`, - errMaxDepth: true, - }, - { - name: "ObjectOverStackDepth", - data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`, - errMaxDepth: true, - }, - } - - targets := []struct { - name string - newValue func() interface{} - }{ - { - name: "unstructured", - newValue: func() interface{} { - var v interface{} - return &v - }, - }, - { - name: "typed named field", - newValue: func() interface{} { - v := struct { - A interface{} `json:"a"` - }{} - return &v - }, - }, - { - name: "typed missing field", - newValue: func() interface{} { - v := struct { - B interface{} `json:"b"` - }{} - return &v - }, - }, - { - name: "custom unmarshaler", - newValue: func() interface{} { - v := unmarshaler{} - return &v - }, - }, - } - - for _, tc := range testcases { - for _, target := range targets { - t.Run(target.name+"-"+tc.name, func(t *testing.T) { - err := Unmarshal([]byte(tc.data), target.newValue()) - if !tc.errMaxDepth { - if err != nil { - t.Errorf("unexpected error: %v", err) - } - } else { - if err == nil { - t.Errorf("expected error containing 'exceeded max depth', got none") - } else if !strings.Contains(err.Error(), "exceeded max depth") { - t.Errorf("expected error containing 'exceeded max depth', got: %v", err) - } - } - }) - } - } -} - -// Issues: map value type larger than 128 bytes are stored by pointer -type ChargeToolPacingBucketItemTcc struct { - _ [128]byte - T string `json:"T"` -} - -type ChargeToolPacingParamsForDataRead struct { - Bucket2Item map[int64]ChargeToolPacingBucketItemTcc `json:"bucket_to_item"` -} - -var panicStr = ` -{ - "bucket_to_item": { - "102" : { - "T": "xxxx" - } - } -} -` - -func TestChangeTool(t *testing.T) { - dataForRaw := ChargeToolPacingParamsForDataRead{} - - err := Unmarshal([]byte(panicStr), &dataForRaw) - if err != nil { - t.Fatalf("err %+v\n", err) - } - t.Logf("%#v\n", dataForRaw) - t.Logf("%#v\n", &dataForRaw.Bucket2Item) - a := dataForRaw.Bucket2Item[102] - if a.T != "xxxx" { - t.Fatalf("exp:%v, got:%v", "xxxx", a.T) - } - -} - -func TestDecoder_LongestInvalidUtf8(t *testing.T) { - for _, data := range([]string{ - "\"" + strings.Repeat("\x80", 4096) + "\"", - "\"" + strings.Repeat("\x80", 4095) + "\"", - "\"" + strings.Repeat("\x80", 4097) + "\"", - "\"" + strings.Repeat("\x80", 12345) + "\"", - }) { - testDecodeInvalidUtf8(t, []byte(data)) - } -} - -func testDecodeInvalidUtf8(t *testing.T, data []byte) { - var sgot, jgot string - serr := ConfigStd.Unmarshal(data, &sgot) - jerr := json.Unmarshal(data, &jgot) - assert.Equal(t, serr != nil, jerr != nil) - if jerr == nil { - assert.Equal(t, sgot, jgot) - } -} - -func needEscape(b byte) bool { - return b == '"' || b == '\\' || b < '\x20' -} - -func genRandJsonBytes(length int) []byte { - var buf bytes.Buffer - buf.WriteByte('"') - for j := 0; j < length; j++ { - r := rand.Intn(0xff + 1) - if needEscape(byte(r)) { - buf.WriteByte('\\') - } - buf.WriteByte(byte(r)) - } - buf.WriteByte('"') - return buf.Bytes() -} - -func genRandJsonRune(length int) []byte { - var buf bytes.Buffer - buf.WriteByte('"') - for j := 0; j < length; j++ { - r := rand.Intn(0x10FFFF + 1) - if r < 0x80 && needEscape(byte(r)) { - buf.WriteByte('\\') - buf.WriteByte(byte(r)) - } else { - buf.WriteRune(rune(r)) - } - } - buf.WriteByte('"') - return buf.Bytes() -} - -func TestDecoder_RandomInvalidUtf8(t *testing.T) { - nums := 1000 - maxLen := 1000 - for i := 0; i < nums; i++ { - length := rand.Intn(maxLen) - testDecodeInvalidUtf8(t, genRandJsonBytes(length)) - testDecodeInvalidUtf8(t, genRandJsonRune(length)) - } -} - - -type atofTest struct { - in string - out string - err error -} - -// Tests from Go strconv package, https://github.com/golang/go/blob/master/src/strconv/atof_test.go -// All tests are passed in Go encoding/json. -var atoftests = []atofTest{ - {"1.234e", "", nil}, // error - {"1i", "1", nil}, // pass - {"1", "1", nil}, - {"1e23", "1e+23", nil}, - {"1E23", "1e+23", nil}, - {"100000000000000000000000", "1e+23", nil}, - {"1e-100", "1e-100", nil}, - {"123456700", "1.234567e+08", nil}, - {"99999999999999974834176", "9.999999999999997e+22", nil}, - {"100000000000000000000001", "1.0000000000000001e+23", nil}, - {"100000000000000008388608", "1.0000000000000001e+23", nil}, - {"100000000000000016777215", "1.0000000000000001e+23", nil}, - {"100000000000000016777216", "1.0000000000000003e+23", nil}, - {"-1", "-1", nil}, - {"-0.1", "-0.1", nil}, - {"-0", "-0", nil}, - {"1e-20", "1e-20", nil}, - {"625e-3", "0.625", nil}, - - // zeros - {"0", "0", nil}, - {"0e0", "0", nil}, - {"-0e0", "-0", nil}, - {"0e-0", "0", nil}, - {"-0e-0", "-0", nil}, - {"0e+0", "0", nil}, - {"-0e+0", "-0", nil}, - {"0e+01234567890123456789", "0", nil}, - {"0.00e-01234567890123456789", "0", nil}, - {"-0e+01234567890123456789", "-0", nil}, - {"-0.00e-01234567890123456789", "-0", nil}, - - {"0e291", "0", nil}, // issue 15364 - {"0e292", "0", nil}, // issue 15364 - {"0e347", "0", nil}, // issue 15364 - {"0e348", "0", nil}, // issue 15364 - {"-0e291", "-0", nil}, - {"-0e292", "-0", nil}, - {"-0e347", "-0", nil}, - {"-0e348", "-0", nil}, - - // largest float64 - {"1.7976931348623157e308", "1.7976931348623157e+308", nil}, - {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil}, - - // the border is ...158079 - // borderline - okay - {"1.7976931348623158e308", "1.7976931348623157e+308", nil}, - {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil}, - - // a little too large - {"1e308", "1e+308", nil}, - - // denormalized - {"1e-305", "1e-305", nil}, - {"1e-306", "1e-306", nil}, - {"1e-307", "1e-307", nil}, - {"1e-308", "1e-308", nil}, - {"1e-309", "1e-309", nil}, - {"1e-310", "1e-310", nil}, - {"1e-322", "1e-322", nil}, - // smallest denormal - {"5e-324", "5e-324", nil}, - {"4e-324", "5e-324", nil}, - {"3e-324", "5e-324", nil}, - // too small - {"2e-324", "0", nil}, - // way too small - {"1e-350", "0", nil}, - {"1e-400000", "0", nil}, - - // try to overflow exponent - {"1e-4294967296", "0", nil}, - {"1e-18446744073709551616", "0", nil}, - - // https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ - {"2.2250738585072012e-308", "2.2250738585072014e-308", nil}, - // https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ - {"2.2250738585072011e-308", "2.225073858507201e-308", nil}, - - // A very large number (initially wrongly parsed by the fast algorithm). - {"4.630813248087435e+307", "4.630813248087435e+307", nil}, - - // A different kind of very large number. - {"22.222222222222222", "22.22222222222222", nil}, - {"2." + strings.Repeat("2", 800) + "e+1", "22.22222222222222", nil}, - - // Exactly halfway between 1 and math.Nextafter(1, 2). - // Round to even (down). - {"1.00000000000000011102230246251565404236316680908203125", "1", nil}, - // Slightly lower; still round down. - {"1.00000000000000011102230246251565404236316680908203124", "1", nil}, - // Slightly higher; round up. - {"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil}, - // Slightly higher, but you have to read all the way to the end. - {"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil}, - - // Halfway between x := math.Nextafter(1, 2) and math.Nextafter(x, 2) - // Round to even (up). - {"1.00000000000000033306690738754696212708950042724609375", "1.0000000000000004", nil}, - - // Halfway between 1090544144181609278303144771584 and 1090544144181609419040633126912 - // (15497564393479157p+46, should round to even 15497564393479156p+46, issue 36657) - {"1090544144181609348671888949248", "1.0905441441816093e+30", nil}, - - // Corner case between int64 and float64 for the input - {"9223372036854775807", "9223372036854775807", nil}, // max int64: (1 << 63) - 1 - {"9223372036854775808", "9223372036854775808", nil}, - {"-9223372036854775808", "-9223372036854775808", nil}, // min int64: 1 << 63 - {"-9223372036854775809", "-9223372036854775809", nil}, -} - -func TestDecodeFloat(t *testing.T) { - for i, tt := range atoftests { - // default float64 - var sonicout, stdout float64 - sonicerr := decoder.NewDecoder(tt.in).Decode(&sonicout) - stderr := json.NewDecoder(strings.NewReader(tt.in)).Decode(&stdout) - if !reflect.DeepEqual(sonicout, stdout) { - t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicout, stdout) - } - if !reflect.DeepEqual(sonicerr == nil, stderr == nil) { - t.Fatalf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sonicerr, stderr) - } - } -} - - -type useInt64Test struct { - in string - out int64 -} - -type useFloatTest struct { - in string - out float64 -} - -var useinttest = []useInt64Test{ - // int64 - {"0", 0}, - {"1", 1}, - {"-1", -1}, - {"100", 100}, - - {"-9223372036854775807", -9223372036854775807}, - {"-9223372036854775808", -9223372036854775808}, //min int64 - {"9223372036854775807", 9223372036854775807}, //max int64 - {"9223372036854775806", 9223372036854775806}, -} - -var usefloattest = []useFloatTest{ - // float64 - {"-9223372036854775809", -9223372036854775809}, // int64 overflow - {"9223372036854775808", 9223372036854775808}, // int64 overflow - {"1e2", 1e2}, - {"1e-20", 1e-20}, - {"1.0", 1}, -} - -func TestUseInt64(t *testing.T) { - for i, tt := range useinttest { - var sout interface{} - dc := decoder.NewDecoder(tt.in) - dc.UseInt64() - serr := dc.Decode(&sout) - if !reflect.DeepEqual(sout, tt.out) { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sout, tt.in) - } - if serr != nil { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n nil\n", i, tt, serr) - } - } - - for i, tt := range usefloattest { - var sout interface{} - dc := decoder.NewDecoder(tt.in) - dc.UseInt64() - //the input string is not int64, still return float64 - serr := dc.Decode(&sout) - if !reflect.DeepEqual(sout, tt.out) { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sout, tt.in) - } - if serr != nil { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n nil\n", i, tt, serr) - } - } -} - -func TestUseNumber(t *testing.T) { - for i, tt := range useinttest { - var sout interface{} - dc := decoder.NewDecoder(tt.in) - dc.UseNumber() - serr := dc.Decode(&sout) - if !reflect.DeepEqual(sout, json.Number(tt.in)) { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sout, tt.out) - } - if serr != nil { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n nil\n", i, tt, serr) - } - } - - for i, tt := range usefloattest { - var sout interface{} - dc := decoder.NewDecoder(tt.in) - dc.UseNumber() - serr := dc.Decode(&sout) - if !reflect.DeepEqual(sout, json.Number(tt.in)) { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n %#v\n", i, tt.in, sout, tt.out) - } - if serr != nil { - t.Errorf("Test %d, %#v\ngot:\n %#v\nexp:\n nil\n", i, tt, serr) - } - } -} diff --git a/decoder/decoder_compat.go b/decoder/decoder_compat.go index b3e634187..472b5264f 100644 --- a/decoder/decoder_compat.go +++ b/decoder/decoder_compat.go @@ -1,5 +1,3 @@ -// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 - /* * Copyright 2023 ByteDance Inc. * @@ -29,10 +27,6 @@ import ( `github.com/bytedance/sonic/option` ) -func init() { - println("WARNING: sonic/decoder only supports (Go1.17~1.23 && CPU amd64) or (go1.20~1.23 && CPU arm64), but your environment is not suitable") -} - const ( _F_use_int64 = 0 _F_disable_urc = 2 diff --git a/decoder/decoder_native.go b/decoder/decoder_native.go deleted file mode 100644 index 9442d028b..000000000 --- a/decoder/decoder_native.go +++ /dev/null @@ -1,70 +0,0 @@ -//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - - -/* -* Copyright 2023 ByteDance Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package decoder - -import ( - `github.com/bytedance/sonic/internal/decoder/api` -) - -// Decoder is the decoder context object -type Decoder = api.Decoder - -// SyntaxError represents json syntax error -type SyntaxError = api.SyntaxError - -// MismatchTypeError represents dismatching between json and object -type MismatchTypeError = api.MismatchTypeError - -// Options for decode. -type Options = api.Options - -const ( - OptionUseInt64 Options = api.OptionUseInt64 - OptionUseNumber Options = api.OptionUseNumber - OptionUseUnicodeErrors Options = api.OptionUseUnicodeErrors - OptionDisableUnknown Options = api.OptionDisableUnknown - OptionCopyString Options = api.OptionCopyString - OptionValidateString Options = api.OptionValidateString -) - -// StreamDecoder is the decoder context object for streaming input. -type StreamDecoder = api.StreamDecoder - -var ( - // NewDecoder creates a new decoder instance. - NewDecoder = api.NewDecoder - - // NewStreamDecoder adapts to encoding/json.NewDecoder API. - // - // NewStreamDecoder returns a new decoder that reads from r. - NewStreamDecoder = api.NewStreamDecoder - - // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in - // order to reduce the first-hit latency. - // - // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is - // a compile option to set the depth of recursive compile for the nested struct type. - Pretouch = api.Pretouch - - // Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid. - // Otherwise, returns negative error code using start and invalid character position using end - Skip = api.Skip -) diff --git a/decoder/decoder_native_test.go b/decoder/decoder_native_test.go deleted file mode 100644 index ffa659b51..000000000 --- a/decoder/decoder_native_test.go +++ /dev/null @@ -1,278 +0,0 @@ -//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - - -/* - * Copyright 2021 ByteDance Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package decoder - -import ( - `encoding/json` - _`strings` - `testing` - _`reflect` - - `github.com/bytedance/sonic/internal/rt` - `github.com/stretchr/testify/assert` -) - -func TestSkipMismatchTypeAmd64Error(t *testing.T) { - // t.Run("struct", func(t *testing.T) { - // println("TestSkipError") - // type skiptype struct { - // A int `json:"a"` - // B string `json:"b"` - - // Pass *int `json:"pass"` - - // C struct{ - - // Pass4 interface{} `json:"pass4"` - - // D struct{ - // E float32 `json:"e"` - // } `json:"d"` - - // Pass2 int `json:"pass2"` - - // } `json:"c"` - - // E bool `json:"e"` - // F []int `json:"f"` - // G map[string]int `json:"g"` - // H bool `json:"h,string"` - - // Pass3 int `json:"pass2"` - - // I json.Number `json:"i"` - // } - // var obj, obj2 = &skiptype{Pass:new(int)}, &skiptype{Pass:new(int)} - // var data = `{"a":"","b":1,"c":{"d":true,"pass2":1,"pass4":true},"e":{},"f":"","g":[],"pass":null,"h":"1.0","i":true,"pass3":1}` - // d := NewDecoder(data) - // err := d.Decode(obj) - // err2 := json.Unmarshal([]byte(data), obj2) - // println(err2.Error()) - // assert.Equal(t, err2 == nil, err == nil) - // // assert.Equal(t, len(data), d.i) - // assert.Equal(t, obj2, obj) - // if te, ok := err.(*MismatchTypeError); ok { - // assert.Equal(t, reflect.TypeOf(obj.I), te.Type) - // assert.Equal(t, strings.Index(data, `"i":t`)+4, te.Pos) - // println(err.Error()) - // } else { - // t.Fatal("invalid error") - // } - // }) - t.Run("short array", func(t *testing.T) { - var obj, obj2 = &[]int{}, &[]int{} - var data = `[""]` - d := NewDecoder(data) - err := d.Decode(obj) - err2 := json.Unmarshal([]byte(data), obj2) - // println(err2.Error()) - assert.Equal(t, err2 == nil, err == nil) - // assert.Equal(t, len(data), d.i) - assert.Equal(t, obj2, obj) - }) - - t.Run("int ", func(t *testing.T) { - var obj int = 123 - var obj2 int = 123 - var data = `[""]` - d := NewDecoder(data) - err := d.Decode(&obj) - err2 := json.Unmarshal([]byte(data), &obj2) - println(err.Error(), obj, obj2) - assert.Equal(t, err2 == nil, err == nil) - // assert.Equal(t, len(data), d.i) - assert.Equal(t, obj2, obj) - }) - - t.Run("array", func(t *testing.T) { - var obj, obj2 = &[]int{}, &[]int{} - var data = `["",true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]` - d := NewDecoder(data) - err := d.Decode(obj) - err2 := json.Unmarshal([]byte(data), obj2) - // println(err2.Error()) - assert.Equal(t, err2 == nil, err == nil) - // assert.Equal(t, len(data), d.i) - assert.Equal(t, obj2, obj) - }) - - t.Run("map", func(t *testing.T) { - var obj, obj2 = &map[int]int{}, &map[int]int{} - var data = `{"true" : { },"1":1,"2" : true,"3":3}` - d := NewDecoder(data) - err := d.Decode(obj) - err2 := json.Unmarshal([]byte(data), obj2) - assert.Equal(t, err2 == nil, err == nil) - // assert.Equal(t, len(data), d.i) - assert.Equal(t, obj2, obj) - }) - t.Run("map error", func(t *testing.T) { - var obj, obj2 = &map[int]int{}, &map[int]int{} - var data = `{"true" : { ],"1":1,"2" : true,"3":3}` - d := NewDecoder(data) - err := d.Decode(obj) - err2 := json.Unmarshal([]byte(data), obj2) - println(err.Error()) - println(err2.Error()) - assert.Equal(t, err2 == nil, err == nil) - // assert.Equal(t, len(data), d.i) - // assert.Equal(t, obj2, obj) - }) -} - -func TestCopyString(t *testing.T) { - var data []byte - var dc *Decoder - var err error - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - dc.CopyString() - var obj struct{ - A string - B string - } - err = dc.Decode(&obj) - if err != nil { - t.Fatal(err) - } - data[6] = '1' - if obj.A != "0" { - t.Fatal(obj) - } - data[14] = '0' - if obj.B != "1" { - t.Fatal(obj) - } - - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - err = dc.Decode(&obj) - if err != nil { - t.Fatal(err) - } - data[6] = '1' - if obj.A != "1" { - t.Fatal(obj) - } - data[14] = '0' - if obj.B != "0" { - t.Fatal(obj) - } - - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - dc.CopyString() - m := map[string]interface{}{} - err = dc.Decode(&m) - if err != nil { - t.Fatal(err) - } - data[2] = 'C' - data[6] = '1' - if m["A"] != "0" { - t.Fatal(m) - } - data[10] = 'D' - data[14] = '0' - if m["B"] != "1" { - t.Fatal(m) - } - - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - m = map[string]interface{}{} - err = dc.Decode(&m) - if err != nil { - t.Fatal(err) - } - data[6] = '1' - if m["A"] != "1" { - t.Fatal(m) - } - data[14] = '0' - if m["B"] != "0" { - t.Fatal(m) - } - - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - dc.CopyString() - var x interface{} - err = dc.Decode(&x) - if err != nil { - t.Fatal(err) - } - data[2] = 'C' - data[6] = '1' - m = x.(map[string]interface{}) - if m["A"] != "0" { - t.Fatal(m) - } - data[10] = 'D' - data[14] = '0' - if m["B"] != "1" { - t.Fatal(m) - } - - data = []byte(`{"A":"0","B":"1"}`) - dc = NewDecoder(rt.Mem2Str(data)) - dc.UseNumber() - var y interface{} - err = dc.Decode(&y) - if err != nil { - t.Fatal(err) - } - m = y.(map[string]interface{}) - data[6] = '1' - if m["A"] != "1" { - t.Fatal(m) - } - data[14] = '0' - if m["B"] != "0" { - t.Fatal(m) - } -} - -func TestDecoder_SetOption(t *testing.T) { - var v interface{} - d := NewDecoder("123") - d.SetOptions(OptionUseInt64) - err := d.Decode(&v) - assert.NoError(t, err) - assert.Equal(t, v, int64(123)) -} - -func BenchmarkSkip_Sonic(b *testing.B) { - var data = rt.Str2Mem(TwitterJson) - if ret, _ := Skip(data); ret < 0 { - b.Fatal() - } - b.SetBytes(int64(len(TwitterJson))) - b.ResetTimer() - for i:=0; i 0; i-- { - sliceNoCycle = []interface{}{sliceNoCycle} - } - recursiveSliceCycle[0] = recursiveSliceCycle -} - -func TestSamePointerNoCycle(t *testing.T) { - if _, err := Marshal(samePointerNoCycle); err != nil { - t.Fatalf("unexpected error: %v", err) - } -} - -func TestSliceNoCycle(t *testing.T) { - if _, err := Marshal(sliceNoCycle); err != nil { - t.Fatalf("unexpected error: %v", err) - } -} - -var unsupportedValues = []interface{}{ - math.NaN(), - math.Inf(-1), - math.Inf(1), - pointerCycle, - pointerCycleIndirect, - mapCycle, - sliceCycle, - recursiveSliceCycle, -} - -func TestUnsupportedValues(t *testing.T) { - for _, v := range unsupportedValues { - if _, err := Marshal(v); err != nil { - if _, ok := err.(*json.UnsupportedValueError); !ok { - t.Errorf("for %v, got %T want UnsupportedValueError", v, err) - } - } else { - t.Errorf("for %v, expected error", v) - } - } -} - -// Ref has Marshaler and Unmarshaler methods with pointer receiver. -type Ref int - -func (*Ref) MarshalJSON() ([]byte, error) { - return []byte(`"ref"`), nil -} - -func (r *Ref) UnmarshalJSON([]byte) error { - *r = 12 - return nil -} - -// Val has Marshaler methods with value receiver. -type Val int - -func (Val) MarshalJSON() ([]byte, error) { - return []byte(`"val"`), nil -} - -// RefText has Marshaler and Unmarshaler methods with pointer receiver. -type RefText int - -func (*RefText) MarshalText() ([]byte, error) { - return []byte(`"ref"`), nil -} - -func (r *RefText) UnmarshalText([]byte) error { - *r = 13 - return nil -} - -// ValText has Marshaler methods with value receiver. -type ValText int - -func (ValText) MarshalText() ([]byte, error) { - return []byte(`"val"`), nil -} - -func TestRefValMarshal(t *testing.T) { - var s = struct { - R0 Ref - R1 *Ref - R2 RefText - R3 *RefText - V0 Val - V1 *Val - V2 ValText - V3 *ValText - }{ - R0: 12, - R1: new(Ref), - R2: 14, - R3: new(RefText), - V0: 13, - V1: new(Val), - V2: 15, - V3: new(ValText), - } - const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}` - b, err := Marshal(&s) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if got := string(b); got != want { - t.Errorf("got %q, want %q", got, want) - } -} - -/* -FIXME: disabling these test cases for now, because Sonic does not implement HTML escape - I don't think there are real usages of the `HTMLEscape` feature in real code - -// C implements Marshaler and returns unescaped JSON. -type C int - -func (C) MarshalJSON() ([]byte, error) { - return []byte(`"<&>"`), nil -} - -// CText implements Marshaler and returns unescaped text. -type CText int - -func (CText) MarshalText() ([]byte, error) { - return []byte(`"<&>"`), nil -} - -func TestMarshalerEscaping(t *testing.T) { - var c C - want := `"\u003c\u0026\u003e"` - b, err := Marshal(c) - if err != nil { - t.Fatalf("Marshal(c): %v", err) - } - if got := string(b); got != want { - t.Errorf("Marshal(c) = %#q, want %#q", got, want) - } - - var ct CText - want = `"\"\u003c\u0026\u003e\""` - b, err = Marshal(ct) - if err != nil { - t.Fatalf("Marshal(ct): %v", err) - } - if got := string(b); got != want { - t.Errorf("Marshal(ct) = %#q, want %#q", got, want) - } -} -*/ - -func TestAnonymousFields(t *testing.T) { - tests := []struct { - label string // Test name - makeInput func() interface{} // Function to create input value - want string // Expected JSON output - }{{ - // Both S1 and S2 have a field named X. From the perspective of S, - // it is ambiguous which one X refers to. - // This should not serialize either field. - label: "AmbiguousField", - makeInput: func() interface{} { - type ( - S1 struct{ x, X int } - S2 struct{ x, X int } - S struct { - S1 - S2 - } - ) - return S{S1{1, 2}, S2{3, 4}} - }, - want: `{}`, - }, { - label: "DominantField", - // Both S1 and S2 have a field named X, but since S has an X field as - // well, it takes precedence over S1.X and S2.X. - makeInput: func() interface{} { - type ( - S1 struct{ x, X int } - S2 struct{ x, X int } - S struct { - S1 - S2 - x, X int - } - ) - return S{S1{1, 2}, S2{3, 4}, 5, 6} - }, - want: `{"X":6}`, - }, { - // Unexported embedded field of non-struct type should not be serialized. - label: "UnexportedEmbeddedInt", - makeInput: func() interface{} { - type ( - myInt int - S struct{ myInt } - ) - return S{5} - }, - want: `{}`, - }, { - // Exported embedded field of non-struct type should be serialized. - label: "ExportedEmbeddedInt", - makeInput: func() interface{} { - type ( - MyInt int - S struct{ MyInt } - ) - return S{5} - }, - want: `{"MyInt":5}`, - }, { - // Unexported embedded field of pointer to non-struct type - // should not be serialized. - label: "UnexportedEmbeddedIntPointer", - makeInput: func() interface{} { - type ( - myInt int - S struct{ *myInt } - ) - s := S{new(myInt)} - *s.myInt = 5 - return s - }, - want: `{}`, - }, { - // Exported embedded field of pointer to non-struct type - // should be serialized. - label: "ExportedEmbeddedIntPointer", - makeInput: func() interface{} { - type ( - MyInt int - S struct{ *MyInt } - ) - s := S{new(MyInt)} - *s.MyInt = 5 - return s - }, - want: `{"MyInt":5}`, - }, { - // Exported fields of embedded structs should have their - // exported fields be serialized regardless of whether the struct types - // themselves are exported. - label: "EmbeddedStruct", - makeInput: func() interface{} { - type ( - s1 struct{ x, X int } - S2 struct{ y, Y int } - S struct { - s1 - S2 - } - ) - return S{s1{1, 2}, S2{3, 4}} - }, - want: `{"X":2,"Y":4}`, - }, { - // Exported fields of pointers to embedded structs should have their - // exported fields be serialized regardless of whether the struct types - // themselves are exported. - label: "EmbeddedStructPointer", - makeInput: func() interface{} { - type ( - s1 struct{ x, X int } - S2 struct{ y, Y int } - S struct { - *s1 - *S2 - } - ) - return S{&s1{1, 2}, &S2{3, 4}} - }, - want: `{"X":2,"Y":4}`, - }, { - // Exported fields on embedded unexported structs at multiple levels - // of nesting should still be serialized. - label: "NestedStructAndInts", - makeInput: func() interface{} { - type ( - MyInt1 int - MyInt2 int - myInt int - s2 struct { - MyInt2 - myInt - } - s1 struct { - MyInt1 - myInt - s2 - } - S struct { - s1 - myInt - } - ) - return S{s1{1, 2, s2{3, 4}}, 6} - }, - want: `{"MyInt1":1,"MyInt2":3}`, - }, { - // If an anonymous struct pointer field is nil, we should ignore - // the embedded fields behind it. Not properly doing so may - // result in the wrong output or reflect panics. - label: "EmbeddedFieldBehindNilPointer", - makeInput: func() interface{} { - type ( - S2 struct{ Field string } - S struct{ *S2 } - ) - return S{} - }, - want: `{}`, - }} - - for _, tt := range tests { - t.Run(tt.label, func(t *testing.T) { - b, err := Marshal(tt.makeInput()) - if err != nil { - t.Fatalf("Marshal() = %v, want nil error", err) - } - if string(b) != tt.want { - t.Fatalf("Marshal() = %q, want %q", b, tt.want) - } - }) - } -} - -type BugA struct { - S string -} - -type BugB struct { - BugA - S string -} - -type BugC struct { - S string -} - -// Legal Go: We never use the repeated embedded field (S). -type BugX struct { - A int - BugA - BugB -} - -// golang.org/issue/16042. -// Even if a nil interface value is passed in, as long as -// it implements Marshaler, it should be marshaled. -type nilJSONMarshaler string - -func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) { - if nm == nil { - return Marshal("0zenil0") - } - return Marshal("zenil:" + string(*nm)) -} - -// golang.org/issue/34235. -// Even if a nil interface value is passed in, as long as -// it implements encoding.TextMarshaler, it should be marshaled. -type nilTextMarshaler string - -func (nm *nilTextMarshaler) MarshalText() ([]byte, error) { - if nm == nil { - return []byte("0zenil0"), nil - } - return []byte("zenil:" + string(*nm)), nil -} - -// See golang.org/issue/16042 and golang.org/issue/34235. -func TestNilMarshal(t *testing.T) { - testCases := []struct { - v interface{} - want string - }{ - {v: nil, want: `null`}, - {v: new(float64), want: `0`}, - {v: []interface{}(nil), want: `null`}, - {v: []string(nil), want: `null`}, - {v: map[string]string(nil), want: `null`}, - {v: []byte(nil), want: `null`}, - {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`}, - {v: struct{ M json.Marshaler }{}, want: `{"M":null}`}, - {v: struct{ M json.Marshaler }{(*nilJSONMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, - {v: struct{ M interface{} }{(*nilJSONMarshaler)(nil)}, want: `{"M":null}`}, - {v: struct{ M encoding.TextMarshaler }{}, want: `{"M":null}`}, - {v: struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, - {v: struct{ M interface{} }{(*nilTextMarshaler)(nil)}, want: `{"M":null}`}, - } - - for _, tt := range testCases { - out, err := Marshal(tt.v) - if err != nil || string(out) != tt.want { - t.Errorf("Marshal(%#v) = %#q, %#v, want %#q, nil", tt.v, out, err, tt.want) - continue - } - } -} - -// Issue 5245. -func TestEmbeddedBug(t *testing.T) { - v := BugB{ - BugA{"A"}, - "B", - } - b, err := Marshal(v) - if err != nil { - t.Fatal("Marshal:", err) - } - want := `{"S":"B"}` - got := string(b) - if got != want { - t.Fatalf("Marshal: got %s want %s", got, want) - } - // Now check that the duplicate field, S, does not appear. - x := BugX{ - A: 23, - } - b, err = Marshal(x) - if err != nil { - t.Fatal("Marshal:", err) - } - want = `{"A":23}` - got = string(b) - if got != want { - t.Fatalf("Marshal: got %s want %s", got, want) - } -} - -type BugD struct { // Same as BugA after tagging. - XXX string `json:"S"` -} - -// BugD's tagged S field should dominate BugA's. -type BugY struct { - BugA - BugD -} - -// Test that a field with a tag dominates untagged fields. -func TestTaggedFieldDominates(t *testing.T) { - v := BugY{ - BugA{"BugA"}, - BugD{"BugD"}, - } - b, err := Marshal(v) - if err != nil { - t.Fatal("Marshal:", err) - } - want := `{"S":"BugD"}` - got := string(b) - if got != want { - t.Fatalf("Marshal: got %s want %s", got, want) - } -} - -// There are no tags here, so S should not appear. -type BugZ struct { - BugA - BugC - BugY // Contains a tagged S field through BugD; should not dominate. -} - -func TestDuplicatedFieldDisappears(t *testing.T) { - v := BugZ{ - BugA{"BugA"}, - BugC{"BugC"}, - BugY{ - BugA{"nested BugA"}, - BugD{"nested BugD"}, - }, - } - b, err := Marshal(v) - if err != nil { - t.Fatal("Marshal:", err) - } - want := `{}` - got := string(b) - if got != want { - t.Fatalf("Marshal: got %s want %s", got, want) - } -} - -func TestStdLibIssue10281(t *testing.T) { - type Foo struct { - N json.Number - } - x := Foo{json.Number(`invalid`)} - - b, err := Marshal(&x) - if err == nil { - t.Errorf("Marshal(&x) = %#q; want error", b) - } -} - -// golang.org/issue/8582 -func TestEncodePointerString(t *testing.T) { - type stringPointer struct { - N *int64 `json:"n,string"` - } - var n int64 = 42 - b, err := Marshal(stringPointer{N: &n}) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if got, want := string(b), `{"n":"42"}`; got != want { - t.Errorf("Marshal = %s, want %s", got, want) - } - var back stringPointer - err = Unmarshal(b, &back) - if err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if back.N == nil { - t.Fatalf("Unmarshaled nil N field") - } - if *back.N != 42 { - t.Fatalf("*N = %d; want 42", *back.N) - } -} - -var encodeStringTests = []struct { - in string - out string -}{ - {"\x00", `"\u0000"`}, - {"\x01", `"\u0001"`}, - {"\x02", `"\u0002"`}, - {"\x03", `"\u0003"`}, - {"\x04", `"\u0004"`}, - {"\x05", `"\u0005"`}, - {"\x06", `"\u0006"`}, - {"\x07", `"\u0007"`}, - {"\x08", `"\u0008"`}, - {"\x09", `"\t"`}, - {"\x0a", `"\n"`}, - {"\x0b", `"\u000b"`}, - {"\x0c", `"\u000c"`}, - {"\x0d", `"\r"`}, - {"\x0e", `"\u000e"`}, - {"\x0f", `"\u000f"`}, - {"\x10", `"\u0010"`}, - {"\x11", `"\u0011"`}, - {"\x12", `"\u0012"`}, - {"\x13", `"\u0013"`}, - {"\x14", `"\u0014"`}, - {"\x15", `"\u0015"`}, - {"\x16", `"\u0016"`}, - {"\x17", `"\u0017"`}, - {"\x18", `"\u0018"`}, - {"\x19", `"\u0019"`}, - {"\x1a", `"\u001a"`}, - {"\x1b", `"\u001b"`}, - {"\x1c", `"\u001c"`}, - {"\x1d", `"\u001d"`}, - {"\x1e", `"\u001e"`}, - {"\x1f", `"\u001f"`}, -} - -func TestEncodeString(t *testing.T) { - for _, tt := range encodeStringTests { - b, err := Marshal(tt.in) - if err != nil { - t.Errorf("Marshal(%q): %v", tt.in, err) - continue - } - out := string(b) - if out != tt.out { - t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out) - } - } -} - -type jsonbyte byte - -func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) } - -type textbyte byte - -func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) } - -type jsonint int - -func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) } - -type textint int - -func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) } - -func tenc(format string, a ...interface{}) ([]byte, error) { - var buf bytes.Buffer - _, _ = fmt.Fprintf(&buf, format, a...) - return buf.Bytes(), nil -} - -// Issue 13783 -func TestEncodeBytekind(t *testing.T) { - testdata := []struct { - data interface{} - want string - }{ - {byte(7), "7"}, - {jsonbyte(7), `{"JB":7}`}, - {textbyte(4), `"TB:4"`}, - {jsonint(5), `{"JI":5}`}, - {textint(1), `"TI:1"`}, - {[]byte{0, 1}, `"AAE="`}, - {[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`}, - {[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`}, - {[]textbyte{2, 3}, `["TB:2","TB:3"]`}, - {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`}, - {[]textint{9, 3}, `["TI:9","TI:3"]`}, - {[]int{9, 3}, `[9,3]`}, - } - for _, d := range testdata { - js, err := Marshal(d.data) - if err != nil { - t.Error(err) - continue - } - got, want := string(js), d.want - if got != want { - t.Errorf("got %s, want %s", got, want) - } - } -} - -// https://golang.org/issue/33675 -func TestNilMarshalerTextMapKey(t *testing.T) { - b, err := Marshal(map[*unmarshalerText]int{ - (*unmarshalerText)(nil): 1, - }) - if err != nil { - t.Fatalf("Failed to Marshal *text.Marshaler: %v", err) - } - const want = `{"":1}` - if string(b) != want { - t.Errorf("Marshal map with *text.Marshaler keys: got %#q, want %#q", b, want) - } -} - -var re = regexp.MustCompile - -// syntactic checks on form of marshaled floating point numbers. -var badFloatREs = []*regexp.Regexp{ - re(`p`), // no binary exponential notation - re(`^\+`), // no leading + sign - re(`^-?0[^.]`), // no unnecessary leading zeros - re(`^-?\.`), // leading zero required before decimal point - re(`\.(e|$)`), // no trailing decimal - re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction - re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa - re(`e[+-]0`), // exponent must not have leading zeros - re(`e-[1-6]$`), // not tiny enough for exponential notation - re(`e+(.|1.|20)$`), // not big enough for exponential notation - re(`^-?0\.0000000`), // too tiny, should use exponential notation - re(`^-?[0-9]{22}`), // too big, should use exponential notation - re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer - re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal -} - -func TestMarshalFloat(t *testing.T) { - t.Parallel() - nfail := 0 - test := func(f float64, bits int) { - vf := interface{}(f) - if bits == 32 { - f = float64(float32(f)) // round - vf = float32(f) - } - bout, err := Marshal(vf) - if err != nil { - t.Errorf("Marshal(%T(%g)): %v", vf, vf, err) - nfail++ - return - } - out := string(bout) - - // result must convert back to the same float - g, err := strconv.ParseFloat(out, bits) - if err != nil { - t.Errorf("Marshal(%T(%g)) = %q, cannot parse back: %v", vf, vf, out, err) - nfail++ - return - } - if f != g { - t.Errorf("Marshal(%T(%g)) = %q (is %g, not %g)", vf, vf, out, float32(g), vf) - nfail++ - return - } - - for _, re := range badFloatREs { - if re.MatchString(out) { - t.Errorf("Marshal(%T(%g)) = %q, must not match /%s/", vf, vf, out, re) - nfail++ - return - } - } - } - - var ( - bigger = math.Inf(+1) - smaller = math.Inf(-1) - ) - - var digits = "1.2345678901234567890123" - for i := len(digits); i >= 2; i-- { - if testing.Short() && i < len(digits)-4 { - break - } - for exp := -30; exp <= 30; exp++ { - for _, sign := range "+-" { - for bits := 32; bits <= 64; bits += 32 { - s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp) - f, err := strconv.ParseFloat(s, bits) - if err != nil { - log.Fatal(err) - } - next := math.Nextafter - if bits == 32 { - next = func(g, h float64) float64 { - return float64(math.Nextafter32(float32(g), float32(h))) - } - } - test(f, bits) - test(next(f, bigger), bits) - test(next(f, smaller), bits) - if nfail > 50 { - t.Fatalf("stopping test early") - } - } - } - } - } - test(0, 64) - test(math.Copysign(0, -1), 64) - test(0, 32) - test(math.Copysign(0, -1), 32) -} - -func TestMarshalRawMessageValue(t *testing.T) { - type ( - T1 struct { - M json.RawMessage `json:",omitempty"` - } - T2 struct { - M *json.RawMessage `json:",omitempty"` - } - ) - - var ( - rawNil = json.RawMessage(nil) - rawEmpty = json.RawMessage([]byte{}) - rawText = json.RawMessage(`"foo"`) - ) - - tests := []struct { - in interface{} - want string - ok bool - }{ - // Test with nil RawMessage. - {rawNil, "null", true}, - {&rawNil, "null", true}, - {[]interface{}{rawNil}, "[null]", true}, - {&[]interface{}{rawNil}, "[null]", true}, - {[]interface{}{&rawNil}, "[null]", true}, - {&[]interface{}{&rawNil}, "[null]", true}, - {struct{ M json.RawMessage }{rawNil}, `{"M":null}`, true}, - {&struct{ M json.RawMessage }{rawNil}, `{"M":null}`, true}, - {struct{ M *json.RawMessage }{&rawNil}, `{"M":null}`, true}, - {&struct{ M *json.RawMessage }{&rawNil}, `{"M":null}`, true}, - {map[string]interface{}{"M": rawNil}, `{"M":null}`, true}, - {&map[string]interface{}{"M": rawNil}, `{"M":null}`, true}, - {map[string]interface{}{"M": &rawNil}, `{"M":null}`, true}, - {&map[string]interface{}{"M": &rawNil}, `{"M":null}`, true}, - {T1{rawNil}, "{}", true}, - {T2{&rawNil}, `{"M":null}`, true}, - {&T1{rawNil}, "{}", true}, - {&T2{&rawNil}, `{"M":null}`, true}, - - // Test with empty, but non-nil, RawMessage. - {rawEmpty, "", false}, - {&rawEmpty, "", false}, - {[]interface{}{rawEmpty}, "", false}, - {&[]interface{}{rawEmpty}, "", false}, - {[]interface{}{&rawEmpty}, "", false}, - {&[]interface{}{&rawEmpty}, "", false}, - {struct{ X json.RawMessage }{rawEmpty}, "", false}, - {&struct{ X json.RawMessage }{rawEmpty}, "", false}, - {struct{ X *json.RawMessage }{&rawEmpty}, "", false}, - {&struct{ X *json.RawMessage }{&rawEmpty}, "", false}, - {map[string]interface{}{"nil": rawEmpty}, "", false}, - {&map[string]interface{}{"nil": rawEmpty}, "", false}, - {map[string]interface{}{"nil": &rawEmpty}, "", false}, - {&map[string]interface{}{"nil": &rawEmpty}, "", false}, - {T1{rawEmpty}, "{}", true}, - {T2{&rawEmpty}, "", false}, - {&T1{rawEmpty}, "{}", true}, - {&T2{&rawEmpty}, "", false}, - - // Test with RawMessage with some text. - // - // The tests below marked with Issue6458 used to generate "ImZvbyI=" instead "foo". - // This behavior was intentionally changed in Go 1.8. - // See https://golang.org/issues/14493#issuecomment-255857318 - {rawText, `"foo"`, true}, // Issue6458 - {&rawText, `"foo"`, true}, - {[]interface{}{rawText}, `["foo"]`, true}, // Issue6458 - {&[]interface{}{rawText}, `["foo"]`, true}, // Issue6458 - {[]interface{}{&rawText}, `["foo"]`, true}, - {&[]interface{}{&rawText}, `["foo"]`, true}, - {struct{ M json.RawMessage }{rawText}, `{"M":"foo"}`, true}, // Issue6458 - {&struct{ M json.RawMessage }{rawText}, `{"M":"foo"}`, true}, - {struct{ M *json.RawMessage }{&rawText}, `{"M":"foo"}`, true}, - {&struct{ M *json.RawMessage }{&rawText}, `{"M":"foo"}`, true}, - {map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458 - {&map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458 - {map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true}, - {&map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true}, - {T1{rawText}, `{"M":"foo"}`, true}, // Issue6458 - {T2{&rawText}, `{"M":"foo"}`, true}, - {&T1{rawText}, `{"M":"foo"}`, true}, - {&T2{&rawText}, `{"M":"foo"}`, true}, - } - - for i, tt := range tests { - b, err := Marshal(tt.in) - if ok := err == nil; ok != tt.ok { - if err != nil { - t.Errorf("test %d, unexpected failure: %v", i, err) - } else { - t.Errorf("test %d, unexpected success", i) - } - } - if got := string(b); got != tt.want { - t.Errorf("test %d, Marshal(%#v) = %q, want %q", i, tt.in, got, tt.want) - } - } -} - -type marshalPanic struct{} - -func (marshalPanic) MarshalJSON() ([]byte, error) { panic(0xdead) } - -func TestMarshalPanic(t *testing.T) { - defer func() { - if got := recover(); !reflect.DeepEqual(got, 0xdead) { - t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) - } - }() - _, _ = Marshal(&marshalPanic{}) - t.Error("Marshal should have panicked") -} - -//goland:noinspection NonAsciiCharacters -func TestMarshalUncommonFieldNames(t *testing.T) { - v := struct { - A0, À, Aβ int - }{} - b, err := Marshal(v) - if err != nil { - t.Fatal("Marshal:", err) - } - want := `{"A0":0,"À":0,"Aβ":0}` - got := string(b) - if got != want { - t.Fatalf("Marshal: got %s want %s", got, want) - } -} - -type DummyMarshalerError struct { - Type reflect.Type - Err error - SourceFunc string -} - -func (self *DummyMarshalerError) err() *json.MarshalerError { - return (*json.MarshalerError)(unsafe.Pointer(self)) -} - -func TestMarshalerError(t *testing.T) { - s := "test variable" - st := reflect.TypeOf(s) - errText := "json: test error" - - tests := []struct { - err *json.MarshalerError - want string - }{ - { - (&DummyMarshalerError{st, fmt.Errorf(errText), ""}).err(), - "json: error calling MarshalJSON for type " + st.String() + ": " + errText, - }, - { - (&DummyMarshalerError{st, fmt.Errorf(errText), "TestMarshalerError"}).err(), - "json: error calling TestMarshalerError for type " + st.String() + ": " + errText, - }, - } - - for i, tt := range tests { - got := tt.err.Error() - if got != tt.want { - t.Errorf("MarshalerError test %d, got: %s, want: %s", i, got, tt.want) - } - } -} - -func TestMarshalNullNil(t *testing.T) { - var v = struct { - A []int - B map[string]int - }{} - o, e := Marshal(v) - assert.Nil(t, e) - assert.Equal(t, `{"A":null,"B":null}`, string(o)) - o, e = Config{ - NoNullSliceOrMap: true, - }.Froze().Marshal(v) - assert.Nil(t, e) - assert.Equal(t, `{"A":[],"B":{}}`, string(o)) -} - -func TestEncoder_LongestInvalidUtf8(t *testing.T) { - for _, data := range([]string{ - "\"" + strings.Repeat("\x80", 4096) + "\"", - "\"" + strings.Repeat("\x80", 4095) + "\"", - "\"" + strings.Repeat("\x80", 4097) + "\"", - "\"" + strings.Repeat("\x80", 12345) + "\"", - }) { - testEncodeInvalidUtf8(t, []byte(data)) - } -} - -func testEncodeInvalidUtf8(t *testing.T, data []byte) { - jgot, jerr := json.Marshal(data) - sgot, serr := ConfigStd.Marshal(data) - assert.Equal(t, serr != nil, jerr != nil) - if jerr == nil { - assert.Equal(t, sgot, jgot) - } -} - -func TestEncoder_RandomInvalidUtf8(t *testing.T) { - nums := 1000 - maxLen := 1000 - for i := 0; i < nums; i++ { - testEncodeInvalidUtf8(t, genRandJsonBytes(maxLen)) - testEncodeInvalidUtf8(t, genRandJsonRune(maxLen)) - } -} - -func TestMarshalInfOrNan(t *testing.T) { - tests := [] interface{}{ - math.Inf(1), math.Inf(-1), math.NaN(), float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.NaN()), []interface{}{math.Inf(1), math.Inf(-1), math.NaN(), float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.NaN())}, - - []float64{math.Inf(1), math.Inf(-1), math.NaN()}, - []float32{float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.NaN())}, - } - - allowNanInf := Config { - EncodeNullForInfOrNan: true, - }.Froze() - for _, tt := range tests { - b, err := allowNanInf.Marshal(tt) - assert.Nil(t, err) - if len(b) == 4 { - assert.Equal(t, string(b), "null") - } else { - println(string(b)) - } - - b, err = Marshal(tt) - assert.NotNil(t, err) - assert.True(t, strings.Contains(err.Error(), "json: unsupported value: NaN or ±Infinite")) - } -} \ No newline at end of file diff --git a/encoder/encoder_compat.go b/encoder/encoder_compat.go index 254defa20..79b1268f1 100644 --- a/encoder/encoder_compat.go +++ b/encoder/encoder_compat.go @@ -1,5 +1,3 @@ -// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 - /* * Copyright 2023 ByteDance Inc. * diff --git a/encoder/encoder_native.go b/encoder/encoder_native.go deleted file mode 100644 index b300ebf08..000000000 --- a/encoder/encoder_native.go +++ /dev/null @@ -1,120 +0,0 @@ -// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 - -/* - * Copyright 2023 ByteDance Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package encoder - -import ( - `github.com/bytedance/sonic/internal/encoder` -) - -// EnableFallback indicates if encoder use fallback -const EnableFallback = false - -// Encoder represents a specific set of encoder configurations. -type Encoder = encoder.Encoder - -// StreamEncoder uses io.Writer as input. -type StreamEncoder = encoder.StreamEncoder - -// Options is a set of encoding options. -type Options = encoder.Options - -const ( - // SortMapKeys indicates that the keys of a map needs to be sorted - // before serializing into JSON. - // WARNING: This hurts performance A LOT, USE WITH CARE. - SortMapKeys Options = encoder.SortMapKeys - - // EscapeHTML indicates encoder to escape all HTML characters - // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape). - // WARNING: This hurts performance A LOT, USE WITH CARE. - EscapeHTML Options = encoder.EscapeHTML - - // CompactMarshaler indicates that the output JSON from json.Marshaler - // is always compact and needs no validation - CompactMarshaler Options = encoder.CompactMarshaler - - // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler - // is always escaped string and needs no quoting - NoQuoteTextMarshaler Options = encoder.NoQuoteTextMarshaler - - // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}', - // instead of 'null' - NoNullSliceOrMap Options = encoder.NoNullSliceOrMap - - // ValidateString indicates that encoder should validate the input string - // before encoding it into JSON. - ValidateString Options = encoder.ValidateString - - // NoValidateJSONMarshaler indicates that the encoder should not validate the output string - // after encoding the JSONMarshaler to JSON. - NoValidateJSONMarshaler Options = encoder.NoValidateJSONMarshaler - - // NoEncoderNewline indicates that the encoder should not add a newline after every message - NoEncoderNewline Options = encoder.NoEncoderNewline - - // CompatibleWithStd is used to be compatible with std encoder. - CompatibleWithStd Options = encoder.CompatibleWithStd - - // Encode Infinity or Nan float into `null`, instead of returning an error. - EncodeNullForInfOrNan Options = encoder.EncodeNullForInfOrNan -) - - -var ( - // Encode returns the JSON encoding of val, encoded with opts. - Encode = encoder.Encode - - // EncodeInto is like Encode but uses a user-supplied buffer instead of allocating a new one. - EncodeIndented = encoder.EncodeIndented - - // EncodeIndented is like Encode but applies Indent to format the output. - // Each JSON element in the output will begin on a new line beginning with prefix - // followed by one or more copies of indent according to the indentation nesting. - EncodeInto = encoder.EncodeInto - - // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 - // characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 - // so that the JSON will be safe to embed inside HTML