| // Copyright 2020 The Pigweed Authors |
| // |
| // 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 |
| // |
| // https://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 "pw_tokenizer/internal/argument_types.h" |
| |
| #include <cstddef> |
| |
| #include "gtest/gtest.h" |
| #include "pw_preprocessor/concat.h" |
| #include "pw_tokenizer_private/argument_types_test.h" |
| |
| namespace pw::tokenizer { |
| namespace { |
| |
| struct DummyType {}; |
| |
| // Check each relevant type mapping. |
| #define CHECK_TYPE(c_type, enum_type) \ |
| static_assert(_PW_VARARGS_TYPE((c_type)0) == enum_type, \ |
| #c_type " should map to " #enum_type) |
| |
| // integral |
| // clang-format off |
| CHECK_TYPE(bool, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(char, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(signed char, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(unsigned char, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(short, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(unsigned short, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(int, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(unsigned int, PW_TOKENIZER_ARG_TYPE_INT); |
| CHECK_TYPE(long, _PW_TOKENIZER_SELECT_INT_TYPE(long)); |
| CHECK_TYPE(unsigned long, _PW_TOKENIZER_SELECT_INT_TYPE(unsigned long)); |
| CHECK_TYPE(long long, PW_TOKENIZER_ARG_TYPE_INT64); |
| CHECK_TYPE(unsigned long long, PW_TOKENIZER_ARG_TYPE_INT64); |
| |
| // floating point |
| CHECK_TYPE(float, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| CHECK_TYPE(double, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| CHECK_TYPE(long double, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| |
| // strings |
| CHECK_TYPE(char*, PW_TOKENIZER_ARG_TYPE_STRING); |
| CHECK_TYPE(const char*, PW_TOKENIZER_ARG_TYPE_STRING); |
| |
| // pointers (which should map to the appropriate sized integer) |
| CHECK_TYPE(void*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(const void*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(signed char*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(unsigned char*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(int*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(long long*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| CHECK_TYPE(DummyType*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| |
| // nullptr |
| CHECK_TYPE(std::nullptr_t, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| static_assert(_PW_VARARGS_TYPE(nullptr) == |
| _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| |
| // clang-format on |
| |
| // Define a macro that generates expected values for tests. This works with |
| // either 4-bit or 6-bit argument counts (for encoding types in a uint32_t or |
| // uint64_t). |
| #define PACKED_TYPES(...) \ |
| ((PW_CONCAT(0b, __VA_ARGS__, u) << PW_TOKENIZER_TYPE_COUNT_SIZE_BITS) | \ |
| PW_MACRO_ARG_COUNT(__VA_ARGS__)) |
| |
| // Test this test macro for both uint32_t and uint64_t. |
| #if PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 4 |
| |
| static_assert(PACKED_TYPES(00) == 0b00'0001u); |
| static_assert(PACKED_TYPES(11) == 0b11'0001u); |
| static_assert(PACKED_TYPES(01, 10) == 0b0110'0010u); |
| static_assert(PACKED_TYPES(11, 01, 10) == 0b110110'0011u); |
| static_assert(PACKED_TYPES(11, 10, 01, 00) == 0b11'10'01'00'0100u); |
| |
| #elif PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 8 |
| |
| static_assert(PACKED_TYPES(00) == 0b00'000001u); |
| static_assert(PACKED_TYPES(11) == 0b11'000001u); |
| static_assert(PACKED_TYPES(01, 10) == 0b0110'000010u); |
| static_assert(PACKED_TYPES(11, 01, 10) == 0b110110'000011u); |
| static_assert(PACKED_TYPES(11, 10, 01, 00) == 0b11'10'01'00'000100u); |
| |
| #else |
| |
| #error "Unsupported value for PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES" |
| |
| #endif // PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES |
| |
| #define SOME_OTHER_MACRO(...) PW_TOKENIZER_ARG_TYPES(__VA_ARGS__) |
| |
| TEST(ArgumentTypes, Empty) { |
| static_assert(PW_TOKENIZER_ARG_TYPES() == 0u); |
| static_assert(PW_TOKENIZER_ARG_TYPES(/* nothing here */) == 0u); |
| static_assert(SOME_OTHER_MACRO() == 0u); |
| static_assert(SOME_OTHER_MACRO(/* nothing here */) == 0u); |
| } |
| |
| TEST(ArgumentTypes, Int32) { |
| static_assert(PW_TOKENIZER_ARG_TYPES(0) == PACKED_TYPES(00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES('a') == PACKED_TYPES(00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(u'X') == PACKED_TYPES(00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(static_cast<uint16_t>(1)) == |
| PACKED_TYPES(00)); |
| } |
| |
| TEST(ArgumentTypes, Int64) { |
| static_assert(PW_TOKENIZER_ARG_TYPES(-123ll) == PACKED_TYPES(01)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(123ull) == PACKED_TYPES(01)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(static_cast<uint64_t>(1)) == |
| PACKED_TYPES(01)); |
| } |
| |
| TEST(ArgumentTypes, Double) { |
| static_assert(PW_TOKENIZER_ARG_TYPES(1.0) == PACKED_TYPES(10)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(5.0f) == PACKED_TYPES(10)); |
| float number = 9; |
| static_assert(PW_TOKENIZER_ARG_TYPES(number) == PACKED_TYPES(10)); |
| } |
| |
| TEST(ArgumentTypes, String) { |
| static_assert(PW_TOKENIZER_ARG_TYPES("string") == PACKED_TYPES(11)); |
| const char buffer[2] = {'a', 'b'}; |
| static_assert(PW_TOKENIZER_ARG_TYPES(buffer) == PACKED_TYPES(11)); |
| char mutable_buffer[8] = {}; |
| static_assert(PW_TOKENIZER_ARG_TYPES(mutable_buffer) == PACKED_TYPES(11)); |
| char character = 'a'; |
| static_assert(PW_TOKENIZER_ARG_TYPES(&character) == PACKED_TYPES(11)); |
| } |
| |
| TEST(ArgumentTypes, Pointer) { |
| static const bool some_data[8] = {}; |
| |
| // For 32-bit systems, non-string pointers show up as int32. |
| static_assert(sizeof(void*) != sizeof(int32_t) || |
| PACKED_TYPES(00) == PW_TOKENIZER_ARG_TYPES(nullptr)); |
| static_assert(sizeof(void*) != sizeof(int32_t) || |
| PACKED_TYPES(00) == |
| PW_TOKENIZER_ARG_TYPES(static_cast<void*>(nullptr))); |
| static_assert(sizeof(void*) != sizeof(int32_t) || |
| PACKED_TYPES(00) == PW_TOKENIZER_ARG_TYPES(some_data)); |
| |
| // For 64-bit systems, non-string pointers show up as int64. |
| static_assert(sizeof(void*) != sizeof(int64_t) || |
| PACKED_TYPES(01) == PW_TOKENIZER_ARG_TYPES(nullptr)); |
| static_assert(sizeof(void*) != sizeof(int64_t) || |
| PACKED_TYPES(01) == |
| PW_TOKENIZER_ARG_TYPES(static_cast<void*>(nullptr))); |
| static_assert(sizeof(void*) != sizeof(int64_t) || |
| PACKED_TYPES(01) == PW_TOKENIZER_ARG_TYPES(some_data)); |
| } |
| |
| TEST(ArgumentTypes, TwoArgs) { |
| static_assert(PW_TOKENIZER_ARG_TYPES(-100, 1000) == PACKED_TYPES(00, 00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(-100, 10ll) == PACKED_TYPES(01, 00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(-100, 1.0f) == PACKED_TYPES(10, 00)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(-100, "hi") == PACKED_TYPES(11, 00)); |
| |
| static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 1000) == PACKED_TYPES(00, 01)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 10ll) == PACKED_TYPES(01, 01)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 1.0f) == PACKED_TYPES(10, 01)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(1ull, "hi") == PACKED_TYPES(11, 01)); |
| |
| static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 1000) == PACKED_TYPES(00, 10)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 10ll) == PACKED_TYPES(01, 10)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 1.0f) == PACKED_TYPES(10, 10)); |
| static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, "hi") == PACKED_TYPES(11, 10)); |
| |
| static_assert(PW_TOKENIZER_ARG_TYPES("!!", 1000) == PACKED_TYPES(00, 11)); |
| static_assert(PW_TOKENIZER_ARG_TYPES("!!", 10ll) == PACKED_TYPES(01, 11)); |
| static_assert(PW_TOKENIZER_ARG_TYPES("!!", 1.0f) == PACKED_TYPES(10, 11)); |
| static_assert(PW_TOKENIZER_ARG_TYPES("!!", "hi") == PACKED_TYPES(11, 11)); |
| } |
| |
| TEST(ArgumentTypes, MultipleArgs) { |
| // clang-format off |
| static_assert(PW_TOKENIZER_ARG_TYPES(1) == 1); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2) == 2); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3) == 3); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4) == 4); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5) == 5); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6) == 6); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7) == 7); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8) == 8); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9) == 9); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 10); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) == 11); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) == 12); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) == 13); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) == 14); // NOLINT |
| |
| #if PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES >= 8 |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) == 14); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) == 15); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == 16); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) == 17); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) == 18); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) == 19); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) == 20); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) == 21); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22) == 22); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) == 23); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) == 24); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25) == 25); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26) == 26); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27) == 27); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28) == 28); // NOLINT |
| static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29) == 29); // NOLINT |
| #endif // PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES |
| // clang-format on |
| } |
| |
| // The ArgumentTypesFromC test suite tests the arguments types macro in C. The |
| // pw_Test* functions are defined in argument_types_c_test.c |
| TEST(ArgumentTypesFromC, NoArgs) { |
| EXPECT_EQ(0b0000u, pw_TestTokenizerNoArgs()); |
| } |
| |
| TEST(ArgumentTypesFromC, OneArg_Int32) { |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerChar()); |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerUint8()); |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerUint16()); |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerInt32()); |
| } |
| |
| TEST(ArgumentTypesFromC, OneArg_Int64) { |
| EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerInt64()); |
| EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerUint64()); |
| } |
| |
| TEST(ArgumentTypesFromC, OneArg_Float) { |
| EXPECT_EQ(PACKED_TYPES(10), pw_TestTokenizerFloat()); |
| EXPECT_EQ(PACKED_TYPES(10), pw_TestTokenizerDouble()); |
| } |
| |
| TEST(ArgumentTypesFromC, OneArg_String) { |
| EXPECT_EQ(PACKED_TYPES(11), pw_TestTokenizerString()); |
| EXPECT_EQ(PACKED_TYPES(11), pw_TestTokenizerMutableString()); |
| } |
| |
| TEST(ArgumentTypesFromC, MultipleArgs) { |
| EXPECT_EQ(PACKED_TYPES(10, 00), pw_TestTokenizerIntFloat()); |
| EXPECT_EQ(PACKED_TYPES(00, 01), pw_TestTokenizerUint64Char()); |
| EXPECT_EQ(PACKED_TYPES(11, 11), pw_TestTokenizerStringString()); |
| EXPECT_EQ(PACKED_TYPES(00, 00), pw_TestTokenizerUint16Int()); |
| EXPECT_EQ(PACKED_TYPES(11, 10), pw_TestTokenizerFloatString()); |
| } |
| |
| TEST(ArgumentTypesFromC, Pointers) { |
| if constexpr (sizeof(void*) == sizeof(int32_t)) { |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerNull()); |
| EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerPointer()); |
| EXPECT_EQ(PACKED_TYPES(00, 00), pw_TestTokenizerPointerPointer()); |
| } else { // 64-bit system |
| EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerNull()); |
| EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerPointer()); |
| EXPECT_EQ(PACKED_TYPES(01, 01), pw_TestTokenizerPointerPointer()); |
| } |
| } |
| |
| } // namespace |
| } // namespace pw::tokenizer |