blob: bef914e656dd3a84884ad6c4e6ffcfeba10a76c7 [file] [log] [blame]
Wyatt Hepler6639c452020-05-06 11:43:07 -07001// 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
24namespace pw::tokenizer {
25namespace {
26
Wyatt Hepler6639c452020-05-06 11:43:07 -070027// Constructs an array with the hashed string followed by the provided bytes.
Ewout van Bekkum5ea33402021-03-31 11:00:02 -070028template <uint8_t... data, size_t kSize>
Wyatt Hepler4b62b892021-03-04 10:03:43 -080029constexpr auto ExpectedData(
Ewout van Bekkum5ea33402021-03-31 11:00:02 -070030 const char (&format)[kSize],
Wyatt Hepler4b62b892021-03-04 10:03:43 -080031 uint32_t token_mask = std::numeric_limits<uint32_t>::max()) {
32 const uint32_t value = Hash(format) & token_mask;
33 return std::array<uint8_t, sizeof(uint32_t) + sizeof...(data)>{
Wyatt Hepler6639c452020-05-06 11:43:07 -070034 static_cast<uint8_t>(value & 0xff),
35 static_cast<uint8_t>(value >> 8 & 0xff),
36 static_cast<uint8_t>(value >> 16 & 0xff),
37 static_cast<uint8_t>(value >> 24 & 0xff),
Wyatt Hepler4b62b892021-03-04 10:03:43 -080038 data...};
Wyatt Hepler6639c452020-05-06 11:43:07 -070039}
40
41// Test fixture for both global handler functions. Both need a global message
42// buffer. To keep the message buffers separate, template this on the derived
43// class type.
44template <typename Impl>
45class GlobalMessage : public ::testing::Test {
46 public:
47 static void SetMessage(const uint8_t* message, size_t size) {
48 ASSERT_LE(size, sizeof(message_));
49 std::memcpy(message_, message, size);
50 message_size_bytes_ = size;
51 }
52
53 protected:
54 GlobalMessage() {
55 std::memset(message_, 0, sizeof(message_));
56 message_size_bytes_ = 0;
57 }
58
59 static uint8_t message_[256];
60 static size_t message_size_bytes_;
61};
62
63template <typename Impl>
64uint8_t GlobalMessage<Impl>::message_[256] = {};
65template <typename Impl>
66size_t GlobalMessage<Impl>::message_size_bytes_ = 0;
67
68class TokenizeToGlobalHandler : public GlobalMessage<TokenizeToGlobalHandler> {
69};
70
71TEST_F(TokenizeToGlobalHandler, Variety) {
72 PW_TOKENIZE_TO_GLOBAL_HANDLER("%x%lld%1.2f%s", 0, 0ll, -0.0, "");
73 const auto expected =
74 ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
75 ASSERT_EQ(expected.size(), message_size_bytes_);
76 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
77}
78
79TEST_F(TokenizeToGlobalHandler, Strings) {
80 PW_TOKENIZE_TO_GLOBAL_HANDLER("The answer is: %s", "5432!");
81 constexpr std::array<uint8_t, 10> expected =
82 ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
83 ASSERT_EQ(expected.size(), message_size_bytes_);
84 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
85}
86
Wyatt Heplerd58eef92020-05-08 10:39:56 -070087TEST_F(TokenizeToGlobalHandler, Domain_Strings) {
88 PW_TOKENIZE_TO_GLOBAL_HANDLER_DOMAIN(
89 "TEST_DOMAIN", "The answer is: %s", "5432!");
90 constexpr std::array<uint8_t, 10> expected =
91 ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
92 ASSERT_EQ(expected.size(), message_size_bytes_);
93 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
94}
95
Wyatt Hepler4b62b892021-03-04 10:03:43 -080096TEST_F(TokenizeToGlobalHandler, Mask) {
97 PW_TOKENIZE_TO_GLOBAL_HANDLER_MASK(
98 "TEST_DOMAIN", 0x00FFF000, "The answer is: %s", "5432!");
99 constexpr std::array<uint8_t, 10> expected =
100 ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s", 0x00FFF000);
101 ASSERT_EQ(expected.size(), message_size_bytes_);
102 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
103}
104
Wyatt Hepler6639c452020-05-06 11:43:07 -0700105TEST_F(TokenizeToGlobalHandler, C_SequentialZigZag) {
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700106 pw_tokenizer_ToGlobalHandlerTest_SequentialZigZag();
Wyatt Hepler6639c452020-05-06 11:43:07 -0700107
108 constexpr std::array<uint8_t, 18> expected =
109 ExpectedData<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13>(
110 TEST_FORMAT_SEQUENTIAL_ZIG_ZAG);
111 ASSERT_EQ(expected.size(), message_size_bytes_);
112 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
113}
114
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700115extern "C" void pw_tokenizer_HandleEncodedMessage(
116 const uint8_t* encoded_message, size_t size_bytes) {
Wyatt Hepler6639c452020-05-06 11:43:07 -0700117 TokenizeToGlobalHandler::SetMessage(encoded_message, size_bytes);
118}
119
120class TokenizeToGlobalHandlerWithPayload
121 : public GlobalMessage<TokenizeToGlobalHandlerWithPayload> {
122 public:
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700123 static void SetPayload(pw_tokenizer_Payload payload) {
Wyatt Hepler6639c452020-05-06 11:43:07 -0700124 payload_ = static_cast<intptr_t>(payload);
125 }
126
127 protected:
128 TokenizeToGlobalHandlerWithPayload() { payload_ = {}; }
129
130 static intptr_t payload_;
131};
132
133intptr_t TokenizeToGlobalHandlerWithPayload::payload_;
134
135TEST_F(TokenizeToGlobalHandlerWithPayload, Variety) {
136 ASSERT_NE(payload_, 123);
137
138 const auto expected =
139 ExpectedData<0, 0, 0x00, 0x00, 0x00, 0x80, 0>("%x%lld%1.2f%s");
140
141 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700142 static_cast<pw_tokenizer_Payload>(123),
143 "%x%lld%1.2f%s",
144 0,
145 0ll,
146 -0.0,
147 "");
Wyatt Hepler6639c452020-05-06 11:43:07 -0700148 ASSERT_EQ(expected.size(), message_size_bytes_);
149 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
150 EXPECT_EQ(payload_, 123);
151
152 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700153 static_cast<pw_tokenizer_Payload>(-543),
Wyatt Hepler6639c452020-05-06 11:43:07 -0700154 "%x%lld%1.2f%s",
155 0,
156 0ll,
157 -0.0,
158 "");
159 ASSERT_EQ(expected.size(), message_size_bytes_);
160 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
161 EXPECT_EQ(payload_, -543);
162}
163
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700164constexpr std::array<uint8_t, 10> kExpected =
165 ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s");
Wyatt Hepler6639c452020-05-06 11:43:07 -0700166
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700167TEST_F(TokenizeToGlobalHandlerWithPayload, Strings_ZeroPayload) {
168 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD({}, "The answer is: %s", "5432!");
169
170 ASSERT_EQ(kExpected.size(), message_size_bytes_);
171 EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
172 EXPECT_EQ(payload_, 0);
173}
174
175TEST_F(TokenizeToGlobalHandlerWithPayload, Strings_NonZeroPayload) {
Wyatt Hepler6639c452020-05-06 11:43:07 -0700176 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700177 static_cast<pw_tokenizer_Payload>(5432), "The answer is: %s", "5432!");
Wyatt Hepler6639c452020-05-06 11:43:07 -0700178
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700179 ASSERT_EQ(kExpected.size(), message_size_bytes_);
180 EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
Wyatt Hepler6639c452020-05-06 11:43:07 -0700181 EXPECT_EQ(payload_, 5432);
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700182}
Wyatt Hepler6639c452020-05-06 11:43:07 -0700183
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700184TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Strings) {
185 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD_DOMAIN(
186 "TEST_DOMAIN",
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700187 static_cast<pw_tokenizer_Payload>(5432),
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700188 "The answer is: %s",
189 "5432!");
190 ASSERT_EQ(kExpected.size(), message_size_bytes_);
191 EXPECT_EQ(std::memcmp(kExpected.data(), message_, kExpected.size()), 0);
192 EXPECT_EQ(payload_, 5432);
Wyatt Hepler6639c452020-05-06 11:43:07 -0700193}
194
Wyatt Hepler4b62b892021-03-04 10:03:43 -0800195TEST_F(TokenizeToGlobalHandlerWithPayload, Mask) {
196 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD_MASK(
197 "TEST_DOMAIN",
198 0x12345678,
199 static_cast<pw_tokenizer_Payload>(5432),
200 "The answer is: %s",
201 "5432!");
202 constexpr std::array<uint8_t, 10> expected =
203 ExpectedData<5, '5', '4', '3', '2', '!'>("The answer is: %s", 0x12345678);
204 ASSERT_EQ(expected.size(), message_size_bytes_);
205 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
206 EXPECT_EQ(payload_, 5432);
207}
208
Wyatt Hepler6639c452020-05-06 11:43:07 -0700209struct Foo {
210 unsigned char a;
211 bool b;
212};
213
214TEST_F(TokenizeToGlobalHandlerWithPayload, PointerToStack) {
215 Foo foo{254u, true};
216
217 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700218 reinterpret_cast<pw_tokenizer_Payload>(&foo), "Boring!");
Wyatt Hepler6639c452020-05-06 11:43:07 -0700219
220 constexpr auto expected = ExpectedData("Boring!");
221 static_assert(expected.size() == 4);
222 ASSERT_EQ(expected.size(), message_size_bytes_);
223 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
224
225 Foo* payload_foo = reinterpret_cast<Foo*>(payload_);
226 ASSERT_EQ(&foo, payload_foo);
227 EXPECT_EQ(payload_foo->a, 254u);
228 EXPECT_TRUE(payload_foo->b);
229}
230
231TEST_F(TokenizeToGlobalHandlerWithPayload, C_SequentialZigZag) {
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700232 pw_tokenizer_ToGlobalHandlerWithPayloadTest_SequentialZigZag();
Wyatt Hepler6639c452020-05-06 11:43:07 -0700233
234 constexpr std::array<uint8_t, 18> expected =
235 ExpectedData<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13>(
236 TEST_FORMAT_SEQUENTIAL_ZIG_ZAG);
237 ASSERT_EQ(expected.size(), message_size_bytes_);
238 EXPECT_EQ(std::memcmp(expected.data(), message_, expected.size()), 0);
239 EXPECT_EQ(payload_, 600613);
240}
241
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700242extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
243 pw_tokenizer_Payload payload,
Wyatt Hepler6639c452020-05-06 11:43:07 -0700244 const uint8_t* encoded_message,
245 size_t size_bytes) {
246 TokenizeToGlobalHandlerWithPayload::SetMessage(encoded_message, size_bytes);
247 TokenizeToGlobalHandlerWithPayload::SetPayload(payload);
248}
249
Wyatt Heplereb020a12020-10-28 14:01:51 -0700250// Hijack an internal macro to capture the tokenizer domain.
251#undef _PW_TOKENIZER_RECORD_ORIGINAL_STRING
252#define _PW_TOKENIZER_RECORD_ORIGINAL_STRING(token, domain, string) \
253 tokenizer_domain = domain; \
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700254 string_literal = string
255
256TEST_F(TokenizeToGlobalHandler, Domain_Default) {
257 const char* tokenizer_domain = nullptr;
258 const char* string_literal = nullptr;
259
260 PW_TOKENIZE_TO_GLOBAL_HANDLER("404");
261
262 EXPECT_STREQ(tokenizer_domain, PW_TOKENIZER_DEFAULT_DOMAIN);
263 EXPECT_STREQ(string_literal, "404");
264}
265
266TEST_F(TokenizeToGlobalHandler, Domain_Specified) {
267 const char* tokenizer_domain = nullptr;
268 const char* string_literal = nullptr;
269
270 PW_TOKENIZE_TO_GLOBAL_HANDLER_DOMAIN("www.google.com", "404");
271
272 EXPECT_STREQ(tokenizer_domain, "www.google.com");
273 EXPECT_STREQ(string_literal, "404");
274}
275
276TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Default) {
277 const char* tokenizer_domain = nullptr;
278 const char* string_literal = nullptr;
279
280 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700281 static_cast<pw_tokenizer_Payload>(123), "Wow%s", "???");
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700282
283 EXPECT_STREQ(tokenizer_domain, PW_TOKENIZER_DEFAULT_DOMAIN);
284 EXPECT_STREQ(string_literal, "Wow%s");
285}
286
287TEST_F(TokenizeToGlobalHandlerWithPayload, Domain_Specified) {
288 const char* tokenizer_domain = nullptr;
289 const char* string_literal = nullptr;
290
291 PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD_DOMAIN(
Wyatt Hepler7a5e4d62020-08-31 08:39:16 -0700292 "THEDOMAIN", static_cast<pw_tokenizer_Payload>(123), "1234567890");
Wyatt Heplerd58eef92020-05-08 10:39:56 -0700293
294 EXPECT_STREQ(tokenizer_domain, "THEDOMAIN");
295 EXPECT_STREQ(string_literal, "1234567890");
296}
297
Wyatt Hepler6639c452020-05-06 11:43:07 -0700298} // namespace
299} // namespace pw::tokenizer