Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_tokenizer / simple_tokenize_test.cc
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 <algorithm>
16 #include <array>
17
18 #include "gtest/gtest.h"
19 #include "pw_tokenizer/tokenize.h"
20 #include "pw_tokenizer/tokenize_to_global_handler.h"
21 #include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
22
23 namespace pw {
24 namespace tokenizer {
25 namespace {
26
27 template <size_t kSize>
28 uint32_t TestHash(const char (&str)[kSize])
29     PW_NO_SANITIZE("unsigned-integer-overflow") {
30   static_assert(kSize > 0u, "Must have at least a null terminator");
31
32   static constexpr uint32_t k65599HashConstant = 65599u;
33
34   // The length is hashed as if it were the first character.
35   uint32_t hash = kSize - 1;
36   uint32_t coefficient = k65599HashConstant;
37
38   size_t length =
39       std::min(static_cast<size_t>(PW_TOKENIZER_CFG_C_HASH_LENGTH), kSize - 1);
40
41   // Hash all of the characters in the string as unsigned ints.
42   // The coefficient calculation is done modulo 0x100000000, so the unsigned
43   // integer overflows are intentional.
44   for (size_t i = 0; i < length; ++i) {
45     hash += coefficient * str[i];
46     coefficient *= k65599HashConstant;
47   }
48
49   return hash;
50 }
51
52 TEST(TokenizeStringLiteral, EmptyString_IsZero) {
53   constexpr pw_tokenizer_Token token = PW_TOKENIZE_STRING("");
54   EXPECT_TRUE(0u == token);
55 }
56
57 TEST(TokenizeStringLiteral, String_MatchesHash) {
58   constexpr uint32_t token = PW_TOKENIZE_STRING("[:-)");
59   EXPECT_TRUE(TestHash("[:-)") == token);
60 }
61
62 constexpr uint32_t kGlobalToken = PW_TOKENIZE_STRING(">:-[]");
63
64 TEST(TokenizeStringLiteral, GlobalVariable_MatchesHash) {
65   EXPECT_TRUE(TestHash(">:-[]") == kGlobalToken);
66 }
67
68 class TokenizeToBuffer : public ::testing::Test {
69  public:
70   TokenizeToBuffer() : buffer_{} {}
71
72  protected:
73   uint8_t buffer_[64];
74 };
75
76 // Test fixture for callback and global handler. Both of these need a global
77 // message buffer. To keep the message buffers separate, template this on the
78 // derived class type.
79 template <typename Impl>
80 class GlobalMessage : public ::testing::Test {
81  public:
82   static void SetMessage(const uint8_t* message, size_t size) {
83     ASSERT_TRUE(size <= sizeof(message_));
84     std::memcpy(message_, message, size);
85     message_size_bytes_ = size;
86   }
87
88  protected:
89   GlobalMessage() {
90     std::memset(message_, 0, sizeof(message_));
91     message_size_bytes_ = 0;
92   }
93
94   static uint8_t message_[256];
95   static size_t message_size_bytes_;
96 };
97
98 template <typename Impl>
99 uint8_t GlobalMessage<Impl>::message_[256] = {};
100 template <typename Impl>
101 size_t GlobalMessage<Impl>::message_size_bytes_ = 0;
102
103 class TokenizeToCallback : public GlobalMessage<TokenizeToCallback> {};
104
105 template <uint8_t... kData, size_t kSize>
106 std::array<uint8_t, sizeof(uint32_t) + sizeof...(kData)> ExpectedData(
107     const char (&format)[kSize]) {
108   const uint32_t value = TestHash(format);
109   return std::array<uint8_t, sizeof(uint32_t) + sizeof...(kData)>{
110       static_cast<uint8_t>(value & 0xff),
111       static_cast<uint8_t>(value >> 8 & 0xff),
112       static_cast<uint8_t>(value >> 16 & 0xff),
113       static_cast<uint8_t>(value >> 24 & 0xff),
114       kData...};
115 }
116
117 TEST_F(TokenizeToCallback, Variety) {
118   PW_TOKENIZE_TO_CALLBACK(
119       SetMessage, "%s there are %x (%.2f) of them%c", "Now", 2u, 2.0f, '.');
120   const auto expected =  // clang-format off
121       ExpectedData<3, 'N', 'o', 'w',        // string "Now"
122                    0x04,                    // unsigned 2 (zig-zag encoded)
123                    0x00, 0x00, 0x00, 0x40,  // float 2.0
124                    0x5C                     // char '.' (0x2E, zig-zag encoded)
125                    >("%s there are %x (%.2f) of them%c");
126   // clang-format on
127   ASSERT_TRUE(expected.size() == message_size_bytes_);
128   EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0);
129 }
130
131 class TokenizeToGlobalHandler : public GlobalMessage<TokenizeToGlobalHandler> {
132 };
133
134 TEST_F(TokenizeToGlobalHandler, Variety) {
135   PW_TOKENIZE_TO_GLOBAL_HANDLER("%x%lld%1.2f%s", 0, 0ll, -0.0, "");
136   const auto expected =
137       ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
138   ASSERT_TRUE(expected.size() == message_size_bytes_);
139   EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0);
140 }
141
142 extern "C" void pw_tokenizer_HandleEncodedMessage(
143     const uint8_t* encoded_message, size_t size_bytes) {
144   TokenizeToGlobalHandler::SetMessage(encoded_message, size_bytes);
145 }
146
147 class TokenizeToGlobalHandlerWithPayload
148     : public GlobalMessage<TokenizeToGlobalHandlerWithPayload> {
149  public:
150   static void SetPayload(pw_tokenizer_Payload payload) {
151     payload_ = static_cast<intptr_t>(payload);
152   }
153
154  protected:
155   TokenizeToGlobalHandlerWithPayload() { payload_ = {}; }
156
157   static intptr_t payload_;
158 };
159
160 intptr_t TokenizeToGlobalHandlerWithPayload::payload_;
161
162 TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) {
163   ASSERT_TRUE(payload_ != 123);
164
165   const auto expected =
166       ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
167
168   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
169       static_cast<pw_tokenizer_Payload>(123),
170       "%x%lld%1.2f%s",
171       0,
172       0ll,
173       -0.0,
174       "");
175   ASSERT_TRUE(expected.size() == message_size_bytes_);
176   EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0);
177   EXPECT_TRUE(payload_ == 123);
178
179   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
180       static_cast<pw_tokenizer_Payload>(-543),
181       "%x%lld%1.2f%s",
182       0,
183       0ll,
184       -0.0,
185       "");
186   ASSERT_TRUE(expected.size() == message_size_bytes_);
187   EXPECT_TRUE(std::memcmp(expected.data(), message_, expected.size()) == 0);
188   EXPECT_TRUE(payload_ == -543);
189 }
190
191 extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
192     pw_tokenizer_Payload payload,
193     const uint8_t* encoded_message,
194     size_t size_bytes) {
195   TokenizeToGlobalHandlerWithPayload::SetMessage(encoded_message, size_bytes);
196   TokenizeToGlobalHandlerWithPayload::SetPayload(payload);
197 }
198
199 }  // namespace
200 }  // namespace tokenizer
201 }  // namespace pw