/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * 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. */ #include "utils/leb128.h" #include #include namespace panda::leb128::test { template struct TestData { T value; size_t size; uint8_t data[10]; }; // clang-format off static std::vector> unsigned_test_data { {0x00, 1, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x7f, 1, {0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0xff, 2, {0xff, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x2d7f, 2, {0xff, 0x5a, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0xffff, 3, {0xff, 0xff, 0x03, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x192d7f, 3, {0xff, 0xda, 0x64, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x1592d7f, 4, {0xff, 0xda, 0xe4, 0x0a, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x11592d7f, 5, {0xff, 0xda, 0xe4, 0x8a, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0xffffffff, 5, {0xff, 0xff, 0xff, 0xff, 0x0f, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x1011592d7f, 6, {0xff, 0xda, 0xe4, 0x8a, 0x81, 0x02, 0x80, 0x80, 0x80, 0x80}}, {0xc1011592d7f, 7, {0xff, 0xda, 0xe4, 0x8a, 0x81, 0x82, 0x03, 0x80, 0x80, 0x80}}, {0x80c1011592d7f, 8, {0xff, 0xda, 0xe4, 0x8a, 0x81, 0x82, 0x83, 0x04, 0x80, 0x80}}, {0xffffffffffffffff, 10, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01}} }; static std::vector> unsigned_partial_decoding_test_data { {0xffffffffffffffff, 10, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03}}, }; static std::vector> signed_test_data8 { {0x00, 1, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x01, 1, {0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-1, 1, {0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x40, 2, {0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x80), 2, {0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-0x40, 1, {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}} }; static std::vector> signed_test_data16 { {0x00, 1, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x0102, 2, {0x82, 0x02, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-1, 1, {0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-0x40, 1, {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x8000), 3, {0x80, 0x80, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x4001), 3, {0x81, 0x80, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}} }; static std::vector> signed_test_data32 { {0x00, 1, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x01020304, 4, {0x84, 0x86, 0x88, 0x08, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-1, 1, {0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-0x40, 1, {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x80000000), 5, {0x80, 0x80, 0x80, 0x80, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x40000001), 5, {0x81, 0x80, 0x80, 0x80, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80}} }; static std::vector> signed_test_data64 { {0x00, 1, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x40, 2, {0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {0x7f, 2, {0xff, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-1, 1, {0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {static_cast(0x8000000000000000), 10, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f}}, {0x7000000000000001, 10, {0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xf0, 0x00}}, {0x100000000000000, 9, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x00}}, {-0x40, 1, {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}}, {-0x1122, 2, {0xde, 0x5d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}} }; static std::vector> signed_partial_decoding_test_data8 { {1, 10, {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a}} }; static std::vector> signed_partial_decoding_test_data16 { {-0x3eff, 10, {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a}} }; static std::vector> signed_partial_decoding_test_data32 { {0x5080c101, 10, {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a}} }; static std::vector> signed_partial_decoding_test_data64 { {0x9101c305080c101, 10, {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a}}, {static_cast(0x8000000000000000), 10, {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x5f}} }; // clang-format on template static void TestDecodeUnsigned(const std::vector> &data, bool is_partial = false) { for (auto &t : data) { std::ostringstream ss; ss << "Test unsigned decoding "; ss << std::hex << t.value; ss << " with sizeof(T) = "; ss << sizeof(T); constexpr size_t bitwidth = std::numeric_limits::digits; auto [value, size, is_full] = DecodeUnsigned(t.data); EXPECT_EQ(is_full, MinimumBitsToStore(t.value) <= bitwidth && !is_partial) << ss.str(); EXPECT_EQ(size, is_full ? t.size : (bitwidth + 6) / 7) << ss.str(); EXPECT_EQ(value, static_cast(t.value)) << ss.str(); } } TEST(Leb128, DecodeUnsigned) { TestDecodeUnsigned(unsigned_test_data); TestDecodeUnsigned(unsigned_test_data); TestDecodeUnsigned(unsigned_test_data); TestDecodeUnsigned(unsigned_test_data); TestDecodeUnsigned(unsigned_partial_decoding_test_data, true); } template static void TestDecodeSigned(const std::vector> &data, bool is_partial = false) { for (auto &t : data) { std::ostringstream ss; ss << "Test signed decoding "; ss << std::hex << static_cast(t.value); ss << " with sizeof(T) = "; ss << sizeof(T); constexpr size_t bitwidth = std::numeric_limits>::digits; auto [value, size, is_full] = DecodeSigned(t.data); EXPECT_EQ(is_full, !is_partial) << ss.str(); EXPECT_EQ(size, is_full ? t.size : (bitwidth + 6) / 7) << ss.str(); EXPECT_EQ(value, t.value) << ss.str(); } } TEST(Leb128, DecodeSigned) { TestDecodeSigned(signed_test_data8); TestDecodeSigned(signed_test_data16); TestDecodeSigned(signed_test_data32); TestDecodeSigned(signed_test_data64); TestDecodeSigned(signed_partial_decoding_test_data8, true); TestDecodeSigned(signed_partial_decoding_test_data16, true); TestDecodeSigned(signed_partial_decoding_test_data32, true); TestDecodeSigned(signed_partial_decoding_test_data64, true); } TEST(Leb128, EncodeUnsigned) { for (auto &t : unsigned_test_data) { std::ostringstream ss; ss << "Test unsigned encoding "; ss << std::hex << t.value; std::vector data(t.size); size_t n = EncodeUnsigned(t.value, data.data()); EXPECT_EQ(n, t.size) << ss.str(); EXPECT_EQ(UnsignedEncodingSize(t.value), t.size) << ss.str(); EXPECT_THAT(data, ::testing::ElementsAreArray(t.data, t.size)) << ss.str(); } } template void TestEncodeSigned(const std::vector> &data_vec) { for (auto &t : data_vec) { std::ostringstream ss; ss << "Test signed encoding "; ss << std::hex << static_cast(t.value); std::vector data(t.size); size_t n = EncodeSigned(t.value, data.data()); EXPECT_EQ(n, t.size) << ss.str(); EXPECT_EQ(SignedEncodingSize(t.value), t.size) << ss.str(); EXPECT_THAT(data, ::testing::ElementsAreArray(t.data, t.size)) << ss.str(); } } TEST(Leb128, EncodeSigned) { TestEncodeSigned(signed_test_data8); TestEncodeSigned(signed_test_data16); TestEncodeSigned(signed_test_data32); TestEncodeSigned(signed_test_data64); } } // namespace panda::leb128::test