Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_tokenizer / global_handlers_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 <cinttypes>
16 #include <cstdint>
17 #include <cstring>
18
19 #include "gtest/gtest.h"
20 #include "pw_tokenizer/tokenize_to_global_handler.h"
21 #include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
22 #include "pw_tokenizer_private/tokenize_test.h"
23
24 namespace pw::tokenizer {
25 namespace {
26
27 // Constructs an array with the hashed string followed by the provided bytes.
28 template <uint8_t... kData, size_t kSize>
29 constexpr auto ExpectedData(const char (&format)[kSize]) {
30   const uint32_t value = Hash(format);
31   return std::array<uint8_t, sizeof(uint32_t) + sizeof...(kData)>{
32       static_cast<uint8_t>(value & 0xff),
33       static_cast<uint8_t>(value >> 8 & 0xff),
34       static_cast<uint8_t>(value >> 16 & 0xff),
35       static_cast<uint8_t>(value >> 24 & 0xff),
36       kData...};
37 }
38
39 // Test fixture for both global handler functions. Both need a global message
40 // buffer. To keep the message buffers separate, template this on the derived
41 // class type.
42 template <typename Impl>
43 class GlobalMessage : public ::testing::Test {
44  public:
45   static void SetMessage(const uint8_t* message, size_t size) {
46     ASSERT_LE(size, sizeof(message_));
47     std::memcpy(message_, message, size);
48     message_size_bytes_ = size;
49   }
50
51  protected:
52   GlobalMessage() {
53     std::memset(message_, 0, sizeof(message_));
54     message_size_bytes_ = 0;
55   }
56
57   static uint8_t message_[256];
58   static size_t message_size_bytes_;
59 };
60
61 template <typename Impl>
62 uint8_t GlobalMessage<Impl>::message_[256] = {};
63 template <typename Impl>
64 size_t GlobalMessage<Impl>::message_size_bytes_ = 0;
65
66 class TokenizeToGlobalHandler : public GlobalMessage<TokenizeToGlobalHandler> {
67 };
68
69 TEST_F(TokenizeToGlobalHandler, Variety) {
70   PW_TOKENIZE_TO_GLOBAL_HANDLER("%x%lld%1.2f%s", 0, 0ll, -0.0, "");
71   const auto expected =
72       ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
73   ASSERT_EQ(expected.size(), message_size_bytes_);
74   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
75 }
76
77 TEST_F(TokenizeToGlobalHandler, Strings) {
78   PW_TOKENIZE_TO_GLOBAL_HANDLER("The answer is: %s", "5432!");
79   constexpr std::array<uint8_t, 10> expected =
80       ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
81   ASSERT_EQ(expected.size(), message_size_bytes_);
82   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
83 }
84
85 TEST_F(TokenizeToGlobalHandler, Domain_Strings) {
86   PW_TOKENIZE_TO_GLOBAL_HANDLER_DOMAIN(
87       "TEST_DOMAIN", "The answer is: %s", "5432!");
88   constexpr std::array<uint8_t, 10> expected =
89       ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
90   ASSERT_EQ(expected.size(), message_size_bytes_);
91   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
92 }
93
94 TEST_F(TokenizeToGlobalHandler, C_SequentialZigZag) {
95   pw_tokenizer_ToGlobalHandlerTest_SequentialZigZag();
96
97   constexpr std::array<uint8_t, 18> expected =
98       ExpectedData<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13>(
99           TEST_FORMAT_SEQUENTIAL_ZIG_ZAG);
100   ASSERT_EQ(expected.size(), message_size_bytes_);
101   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
102 }
103
104 extern "C" void pw_tokenizer_HandleEncodedMessage(
105     const uint8_t* encoded_message, size_t size_bytes) {
106   TokenizeToGlobalHandler::SetMessage(encoded_message, size_bytes);
107 }
108
109 class TokenizeToGlobalHandlerWithPayload
110     : public GlobalMessage<TokenizeToGlobalHandlerWithPayload> {
111  public:
112   static void SetPayload(pw_tokenizer_Payload payload) {
113     payload_ = static_cast<intptr_t>(payload);
114   }
115
116  protected:
117   TokenizeToGlobalHandlerWithPayload() { payload_ = {}; }
118
119   static intptr_t payload_;
120 };
121
122 intptr_t TokenizeToGlobalHandlerWithPayload::payload_;
123
124 TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) {
125   ASSERT_NE(payload_, 123);
126
127   const auto expected =
128       ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
129
130   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
131       static_cast<pw_tokenizer_Payload>(123),
132       "%x%lld%1.2f%s",
133       0,
134       0ll,
135       -0.0,
136       "");
137   ASSERT_EQ(expected.size(), message_size_bytes_);
138   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
139   EXPECT_EQ(payload_, 123);
140
141   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
142       static_cast<pw_tokenizer_Payload>(-543),
143       "%x%lld%1.2f%s",
144       0,
145       0ll,
146       -0.0,
147       "");
148   ASSERT_EQ(expected.size(), message_size_bytes_);
149   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
150   EXPECT_EQ(payload_, -543);
151 }
152
153 constexpr std::array<uint8_t, 10> kExpected =
154     ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
155
156 TEST_F(TokenizeToGlobalHandlerWithPayload, Strings_ZeroPayload) {
157   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD({}, "The answer is: %s", "5432!");
158
159   ASSERT_EQ(kExpected.size(), message_size_bytes_);
160   EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
161   EXPECT_EQ(payload_, 0);
162 }
163
164 TEST_F(TokenizeToGlobalHandlerWithPayload, Strings_NonZeroPayload) {
165   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
166       static_cast<pw_tokenizer_Payload>(5432), "The answer is: %s", "5432!");
167
168   ASSERT_EQ(kExpected.size(), message_size_bytes_);
169   EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
170   EXPECT_EQ(payload_, 5432);
171 }
172
173 TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Strings) {
174   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD_DOMAIN(
175       "TEST_DOMAIN",
176       static_cast<pw_tokenizer_Payload>(5432),
177       "The answer is: %s",
178       "5432!");
179   ASSERT_EQ(kExpected.size(), message_size_bytes_);
180   EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
181   EXPECT_EQ(payload_, 5432);
182 }
183
184 struct Foo {
185   unsigned char a;
186   bool b;
187 };
188
189 TEST_F(TokenizeToGlobalHandlerWithPayload, PointerToStack) {
190   Foo foo{254u, true};
191
192   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
193       reinterpret_cast<pw_tokenizer_Payload>(&foo), "Boring!");
194
195   constexpr auto expected = ExpectedData("Boring!");
196   static_assert(expected.size() == 4);
197   ASSERT_EQ(expected.size(), message_size_bytes_);
198   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
199
200   Foo* payload_foo = reinterpret_cast<Foo*>(payload_);
201   ASSERT_EQ(&foo, payload_foo);
202   EXPECT_EQ(payload_foo->a, 254u);
203   EXPECT_TRUE(payload_foo->b);
204 }
205
206 TEST_F(TokenizeToGlobalHandlerWithPayload, C_SequentialZigZag) {
207   pw_tokenizer_ToGlobalHandlerWithPayloadTest_SequentialZigZag();
208
209   constexpr std::array<uint8_t, 18> expected =
210       ExpectedData<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13>(
211           TEST_FORMAT_SEQUENTIAL_ZIG_ZAG);
212   ASSERT_EQ(expected.size(), message_size_bytes_);
213   EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
214   EXPECT_EQ(payload_, 600613);
215 }
216
217 extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
218     pw_tokenizer_Payload payload,
219     const uint8_t* encoded_message,
220     size_t size_bytes) {
221   TokenizeToGlobalHandlerWithPayload::SetMessage(encoded_message, size_bytes);
222   TokenizeToGlobalHandlerWithPayload::SetPayload(payload);
223 }
224
225 // Hijack an internal macro to capture the tokenizer domain.
226 #undef _PW_TOKENIZER_RECORD_ORIGINAL_STRING
227 #define _PW_TOKENIZER_RECORD_ORIGINAL_STRING(token, domain, string) \
228   tokenizer_domain = domain;                                        \
229   string_literal = string
230
231 TEST_F(TokenizeToGlobalHandler, Domain_Default) {
232   const char* tokenizer_domain = nullptr;
233   const char* string_literal = nullptr;
234
235   PW_TOKENIZE_TO_GLOBAL_HANDLER("404");
236
237   EXPECT_STREQ(tokenizer_domain, PW_TOKENIZER_DEFAULT_DOMAIN);
238   EXPECT_STREQ(string_literal, "404");
239 }
240
241 TEST_F(TokenizeToGlobalHandler, Domain_Specified) {
242   const char* tokenizer_domain = nullptr;
243   const char* string_literal = nullptr;
244
245   PW_TOKENIZE_TO_GLOBAL_HANDLER_DOMAIN("www.google.com", "404");
246
247   EXPECT_STREQ(tokenizer_domain, "www.google.com");
248   EXPECT_STREQ(string_literal, "404");
249 }
250
251 TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Default) {
252   const char* tokenizer_domain = nullptr;
253   const char* string_literal = nullptr;
254
255   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
256       static_cast<pw_tokenizer_Payload>(123), "Wow%s", "???");
257
258   EXPECT_STREQ(tokenizer_domain, PW_TOKENIZER_DEFAULT_DOMAIN);
259   EXPECT_STREQ(string_literal, "Wow%s");
260 }
261
262 TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Specified) {
263   const char* tokenizer_domain = nullptr;
264   const char* string_literal = nullptr;
265
266   PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD_DOMAIN(
267       "THEDOMAIN", static_cast<pw_tokenizer_Payload>(123), "1234567890");
268
269   EXPECT_STREQ(tokenizer_domain, "THEDOMAIN");
270   EXPECT_STREQ(string_literal, "1234567890");
271 }
272
273 }  // namespace
274 }  // namespace pw::tokenizer