Wyatt Hepler | 80c6ee5 | 2020-01-03 09:54:58 -0800 | [diff] [blame] | 1 | // Copyright 2020 The Pigweed Authors |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| 4 | // use this file except in compliance with the License. You may obtain a copy of |
| 5 | // the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 12 | // License for the specific language governing permissions and limitations under |
| 13 | // the License. |
| 14 | |
| 15 | #include "pw_tokenizer/internal/argument_types.h" |
| 16 | |
| 17 | #include <cstddef> |
| 18 | |
| 19 | #include "gtest/gtest.h" |
| 20 | #include "pw_preprocessor/concat.h" |
| 21 | #include "pw_tokenizer_private/argument_types_test.h" |
| 22 | |
| 23 | namespace pw::tokenizer { |
| 24 | namespace { |
| 25 | |
| 26 | struct DummyType {}; |
| 27 | |
| 28 | // Check each relevant type mapping. |
| 29 | #define CHECK_TYPE(c_type, enum_type) \ |
| 30 | static_assert(_PW_VARARGS_TYPE((c_type)0) == enum_type, \ |
| 31 | #c_type " should map to " #enum_type) |
| 32 | |
| 33 | // integral |
| 34 | // clang-format off |
| 35 | CHECK_TYPE(bool, PW_TOKENIZER_ARG_TYPE_INT); |
| 36 | CHECK_TYPE(char, PW_TOKENIZER_ARG_TYPE_INT); |
| 37 | CHECK_TYPE(signed char, PW_TOKENIZER_ARG_TYPE_INT); |
| 38 | CHECK_TYPE(unsigned char, PW_TOKENIZER_ARG_TYPE_INT); |
| 39 | CHECK_TYPE(short, PW_TOKENIZER_ARG_TYPE_INT); |
| 40 | CHECK_TYPE(unsigned short, PW_TOKENIZER_ARG_TYPE_INT); |
| 41 | CHECK_TYPE(int, PW_TOKENIZER_ARG_TYPE_INT); |
| 42 | CHECK_TYPE(unsigned int, PW_TOKENIZER_ARG_TYPE_INT); |
| 43 | CHECK_TYPE(long, _PW_TOKENIZER_SELECT_INT_TYPE(long)); |
| 44 | CHECK_TYPE(unsigned long, _PW_TOKENIZER_SELECT_INT_TYPE(unsigned long)); |
| 45 | CHECK_TYPE(long long, PW_TOKENIZER_ARG_TYPE_INT64); |
| 46 | CHECK_TYPE(unsigned long long, PW_TOKENIZER_ARG_TYPE_INT64); |
| 47 | |
| 48 | // floating point |
| 49 | CHECK_TYPE(float, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| 50 | CHECK_TYPE(double, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| 51 | CHECK_TYPE(long double, PW_TOKENIZER_ARG_TYPE_DOUBLE); |
| 52 | |
| 53 | // strings |
| 54 | CHECK_TYPE(char*, PW_TOKENIZER_ARG_TYPE_STRING); |
| 55 | CHECK_TYPE(const char*, PW_TOKENIZER_ARG_TYPE_STRING); |
| 56 | |
| 57 | // pointers (which should map to the appropriate sized integer) |
| 58 | CHECK_TYPE(void*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 59 | CHECK_TYPE(const void*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 60 | CHECK_TYPE(signed char*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 61 | CHECK_TYPE(unsigned char*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 62 | CHECK_TYPE(int*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 63 | CHECK_TYPE(long long*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 64 | CHECK_TYPE(DummyType*, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 65 | |
| 66 | // nullptr |
| 67 | CHECK_TYPE(std::nullptr_t, _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 68 | static_assert(_PW_VARARGS_TYPE(nullptr) == |
| 69 | _PW_TOKENIZER_SELECT_INT_TYPE(void*)); |
| 70 | |
| 71 | // clang-format on |
| 72 | |
| 73 | // Define a macro that generates expected values for tests. This works with |
| 74 | // either 4-bit or 6-bit argument counts (for encoding types in a uint32_t or |
| 75 | // uint64_t). |
| 76 | #define PACKED_TYPES(...) \ |
| 77 | ((PW_CONCAT(0b, __VA_ARGS__, u) << PW_TOKENIZER_TYPE_COUNT_SIZE_BITS) | \ |
Wyatt Hepler | 5191f58 | 2020-08-24 09:26:23 -0700 | [diff] [blame^] | 78 | PW_MACRO_ARG_COUNT(__VA_ARGS__)) |
Wyatt Hepler | 80c6ee5 | 2020-01-03 09:54:58 -0800 | [diff] [blame] | 79 | |
| 80 | // Test this test macro for both uint32_t and uint64_t. |
| 81 | #if PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 4 |
| 82 | |
| 83 | static_assert(PACKED_TYPES(00) == 0b00'0001u); |
| 84 | static_assert(PACKED_TYPES(11) == 0b11'0001u); |
| 85 | static_assert(PACKED_TYPES(01, 10) == 0b0110'0010u); |
| 86 | static_assert(PACKED_TYPES(11, 01, 10) == 0b110110'0011u); |
| 87 | static_assert(PACKED_TYPES(11, 10, 01, 00) == 0b11'10'01'00'0100u); |
| 88 | |
| 89 | #elif PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 8 |
| 90 | |
| 91 | static_assert(PACKED_TYPES(00) == 0b00'000001u); |
| 92 | static_assert(PACKED_TYPES(11) == 0b11'000001u); |
| 93 | static_assert(PACKED_TYPES(01, 10) == 0b0110'000010u); |
| 94 | static_assert(PACKED_TYPES(11, 01, 10) == 0b110110'000011u); |
| 95 | static_assert(PACKED_TYPES(11, 10, 01, 00) == 0b11'10'01'00'000100u); |
| 96 | |
| 97 | #else |
| 98 | |
| 99 | #error "Unsupported value for PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES" |
| 100 | |
| 101 | #endif // PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES |
| 102 | |
| 103 | #define SOME_OTHER_MACRO(...) PW_TOKENIZER_ARG_TYPES(__VA_ARGS__) |
| 104 | |
| 105 | TEST(ArgumentTypes, Empty) { |
| 106 | static_assert(PW_TOKENIZER_ARG_TYPES() == 0u); |
| 107 | static_assert(PW_TOKENIZER_ARG_TYPES(/* nothing here */) == 0u); |
| 108 | static_assert(SOME_OTHER_MACRO() == 0u); |
| 109 | static_assert(SOME_OTHER_MACRO(/* nothing here */) == 0u); |
| 110 | } |
| 111 | |
| 112 | TEST(ArgumentTypes, Int32) { |
| 113 | static_assert(PW_TOKENIZER_ARG_TYPES(0) == PACKED_TYPES(00)); |
| 114 | static_assert(PW_TOKENIZER_ARG_TYPES('a') == PACKED_TYPES(00)); |
| 115 | static_assert(PW_TOKENIZER_ARG_TYPES(u'X') == PACKED_TYPES(00)); |
| 116 | static_assert(PW_TOKENIZER_ARG_TYPES(static_cast<uint16_t>(1)) == |
| 117 | PACKED_TYPES(00)); |
| 118 | } |
| 119 | |
| 120 | TEST(ArgumentTypes, Int64) { |
| 121 | static_assert(PW_TOKENIZER_ARG_TYPES(-123ll) == PACKED_TYPES(01)); |
| 122 | static_assert(PW_TOKENIZER_ARG_TYPES(123ull) == PACKED_TYPES(01)); |
| 123 | static_assert(PW_TOKENIZER_ARG_TYPES(static_cast<uint64_t>(1)) == |
| 124 | PACKED_TYPES(01)); |
| 125 | } |
| 126 | |
| 127 | TEST(ArgumentTypes, Double) { |
| 128 | static_assert(PW_TOKENIZER_ARG_TYPES(1.0) == PACKED_TYPES(10)); |
| 129 | static_assert(PW_TOKENIZER_ARG_TYPES(5.0f) == PACKED_TYPES(10)); |
| 130 | float number = 9; |
| 131 | static_assert(PW_TOKENIZER_ARG_TYPES(number) == PACKED_TYPES(10)); |
| 132 | } |
| 133 | |
| 134 | TEST(ArgumentTypes, String) { |
| 135 | static_assert(PW_TOKENIZER_ARG_TYPES("string") == PACKED_TYPES(11)); |
| 136 | const char buffer[2] = {'a', 'b'}; |
| 137 | static_assert(PW_TOKENIZER_ARG_TYPES(buffer) == PACKED_TYPES(11)); |
| 138 | char mutable_buffer[8] = {}; |
| 139 | static_assert(PW_TOKENIZER_ARG_TYPES(mutable_buffer) == PACKED_TYPES(11)); |
| 140 | char character = 'a'; |
| 141 | static_assert(PW_TOKENIZER_ARG_TYPES(&character) == PACKED_TYPES(11)); |
| 142 | } |
| 143 | |
| 144 | TEST(ArgumentTypes, Pointer) { |
| 145 | static const bool some_data[8] = {}; |
| 146 | |
| 147 | // For 32-bit systems, non-string pointers show up as int32. |
| 148 | static_assert(sizeof(void*) != sizeof(int32_t) || |
| 149 | PACKED_TYPES(00) == PW_TOKENIZER_ARG_TYPES(nullptr)); |
| 150 | static_assert(sizeof(void*) != sizeof(int32_t) || |
| 151 | PACKED_TYPES(00) == |
| 152 | PW_TOKENIZER_ARG_TYPES(static_cast<void*>(nullptr))); |
| 153 | static_assert(sizeof(void*) != sizeof(int32_t) || |
| 154 | PACKED_TYPES(00) == PW_TOKENIZER_ARG_TYPES(some_data)); |
| 155 | |
| 156 | // For 64-bit systems, non-string pointers show up as int64. |
| 157 | static_assert(sizeof(void*) != sizeof(int64_t) || |
| 158 | PACKED_TYPES(01) == PW_TOKENIZER_ARG_TYPES(nullptr)); |
| 159 | static_assert(sizeof(void*) != sizeof(int64_t) || |
| 160 | PACKED_TYPES(01) == |
| 161 | PW_TOKENIZER_ARG_TYPES(static_cast<void*>(nullptr))); |
| 162 | static_assert(sizeof(void*) != sizeof(int64_t) || |
| 163 | PACKED_TYPES(01) == PW_TOKENIZER_ARG_TYPES(some_data)); |
| 164 | } |
| 165 | |
| 166 | TEST(ArgumentTypes, TwoArgs) { |
| 167 | static_assert(PW_TOKENIZER_ARG_TYPES(-100, 1000) == PACKED_TYPES(00, 00)); |
| 168 | static_assert(PW_TOKENIZER_ARG_TYPES(-100, 10ll) == PACKED_TYPES(01, 00)); |
| 169 | static_assert(PW_TOKENIZER_ARG_TYPES(-100, 1.0f) == PACKED_TYPES(10, 00)); |
| 170 | static_assert(PW_TOKENIZER_ARG_TYPES(-100, "hi") == PACKED_TYPES(11, 00)); |
| 171 | |
| 172 | static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 1000) == PACKED_TYPES(00, 01)); |
| 173 | static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 10ll) == PACKED_TYPES(01, 01)); |
| 174 | static_assert(PW_TOKENIZER_ARG_TYPES(1ull, 1.0f) == PACKED_TYPES(10, 01)); |
| 175 | static_assert(PW_TOKENIZER_ARG_TYPES(1ull, "hi") == PACKED_TYPES(11, 01)); |
| 176 | |
| 177 | static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 1000) == PACKED_TYPES(00, 10)); |
| 178 | static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 10ll) == PACKED_TYPES(01, 10)); |
| 179 | static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, 1.0f) == PACKED_TYPES(10, 10)); |
| 180 | static_assert(PW_TOKENIZER_ARG_TYPES(9.0f, "hi") == PACKED_TYPES(11, 10)); |
| 181 | |
| 182 | static_assert(PW_TOKENIZER_ARG_TYPES("!!", 1000) == PACKED_TYPES(00, 11)); |
| 183 | static_assert(PW_TOKENIZER_ARG_TYPES("!!", 10ll) == PACKED_TYPES(01, 11)); |
| 184 | static_assert(PW_TOKENIZER_ARG_TYPES("!!", 1.0f) == PACKED_TYPES(10, 11)); |
| 185 | static_assert(PW_TOKENIZER_ARG_TYPES("!!", "hi") == PACKED_TYPES(11, 11)); |
| 186 | } |
| 187 | |
| 188 | TEST(ArgumentTypes, MultipleArgs) { |
| 189 | // clang-format off |
| 190 | static_assert(PW_TOKENIZER_ARG_TYPES(1) == 1); // NOLINT |
| 191 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2) == 2); // NOLINT |
| 192 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3) == 3); // NOLINT |
| 193 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4) == 4); // NOLINT |
| 194 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5) == 5); // NOLINT |
| 195 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6) == 6); // NOLINT |
| 196 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7) == 7); // NOLINT |
| 197 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8) == 8); // NOLINT |
| 198 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9) == 9); // NOLINT |
| 199 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 10); // NOLINT |
| 200 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) == 11); // NOLINT |
| 201 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) == 12); // NOLINT |
| 202 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) == 13); // NOLINT |
| 203 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) == 14); // NOLINT |
| 204 | |
| 205 | #if PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES >= 8 |
| 206 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) == 14); // NOLINT |
| 207 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) == 15); // NOLINT |
| 208 | static_assert(PW_TOKENIZER_ARG_TYPES(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == 16); // NOLINT |
| 209 | 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 |
| 210 | 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 |
| 211 | 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 |
| 212 | 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 |
| 213 | 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 |
| 214 | 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 |
| 215 | 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 |
| 216 | 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 |
| 217 | 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 |
| 218 | 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 |
| 219 | 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 |
| 220 | 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 |
| 221 | 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 |
| 222 | #endif // PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES |
| 223 | // clang-format on |
| 224 | } |
| 225 | |
| 226 | // The ArgumentTypesFromC test suite tests the arguments types macro in C. The |
| 227 | // pw_Test* functions are defined in argument_types_c_test.c |
| 228 | TEST(ArgumentTypesFromC, NoArgs) { |
| 229 | EXPECT_EQ(0b0000u, pw_TestTokenizerNoArgs()); |
| 230 | } |
| 231 | |
| 232 | TEST(ArgumentTypesFromC, OneArg_Int32) { |
| 233 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerChar()); |
| 234 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerUint8()); |
| 235 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerUint16()); |
| 236 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerInt32()); |
| 237 | } |
| 238 | |
| 239 | TEST(ArgumentTypesFromC, OneArg_Int64) { |
| 240 | EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerInt64()); |
| 241 | EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerUint64()); |
| 242 | } |
| 243 | |
| 244 | TEST(ArgumentTypesFromC, OneArg_Float) { |
| 245 | EXPECT_EQ(PACKED_TYPES(10), pw_TestTokenizerFloat()); |
| 246 | EXPECT_EQ(PACKED_TYPES(10), pw_TestTokenizerDouble()); |
| 247 | } |
| 248 | |
| 249 | TEST(ArgumentTypesFromC, OneArg_String) { |
| 250 | EXPECT_EQ(PACKED_TYPES(11), pw_TestTokenizerString()); |
| 251 | EXPECT_EQ(PACKED_TYPES(11), pw_TestTokenizerMutableString()); |
| 252 | } |
| 253 | |
| 254 | TEST(ArgumentTypesFromC, MultipleArgs) { |
| 255 | EXPECT_EQ(PACKED_TYPES(10, 00), pw_TestTokenizerIntFloat()); |
| 256 | EXPECT_EQ(PACKED_TYPES(00, 01), pw_TestTokenizerUint64Char()); |
| 257 | EXPECT_EQ(PACKED_TYPES(11, 11), pw_TestTokenizerStringString()); |
| 258 | EXPECT_EQ(PACKED_TYPES(00, 00), pw_TestTokenizerUint16Int()); |
| 259 | EXPECT_EQ(PACKED_TYPES(11, 10), pw_TestTokenizerFloatString()); |
| 260 | } |
| 261 | |
| 262 | TEST(ArgumentTypesFromC, Pointers) { |
| 263 | if constexpr (sizeof(void*) == sizeof(int32_t)) { |
| 264 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerNull()); |
| 265 | EXPECT_EQ(PACKED_TYPES(00), pw_TestTokenizerPointer()); |
| 266 | EXPECT_EQ(PACKED_TYPES(00, 00), pw_TestTokenizerPointerPointer()); |
| 267 | } else { // 64-bit system |
| 268 | EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerNull()); |
| 269 | EXPECT_EQ(PACKED_TYPES(01), pw_TestTokenizerPointer()); |
| 270 | EXPECT_EQ(PACKED_TYPES(01, 01), pw_TestTokenizerPointerPointer()); |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | } // namespace |
| 275 | } // namespace pw::tokenizer |