1 // Copyright 2021 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_log/proto_utils.h"
16
17 #include "pw_bytes/span.h"
18 #include "pw_containers/algorithm.h"
19 #include "pw_log/levels.h"
20 #include "pw_log/proto/log.pwpb.h"
21 #include "pw_protobuf/bytes_utils.h"
22 #include "pw_protobuf/decoder.h"
23 #include "pw_unit_test/framework.h"
24
25 namespace pw::log {
26
VerifyTokenizedLogEntry(pw::protobuf::Decoder & entry_decoder,pw::log_tokenized::Metadata expected_metadata,ConstByteSpan expected_tokenized_data,const int64_t expected_timestamp,ConstByteSpan expected_thread_name)27 void VerifyTokenizedLogEntry(pw::protobuf::Decoder& entry_decoder,
28 pw::log_tokenized::Metadata expected_metadata,
29 ConstByteSpan expected_tokenized_data,
30 const int64_t expected_timestamp,
31 ConstByteSpan expected_thread_name) {
32 ConstByteSpan tokenized_data;
33 EXPECT_TRUE(entry_decoder.Next().ok()); // message [tokenized]
34 EXPECT_EQ(entry_decoder.FieldNumber(),
35 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kMessage));
36 EXPECT_TRUE(entry_decoder.ReadBytes(&tokenized_data).ok());
37 EXPECT_TRUE(std::memcmp(tokenized_data.data(),
38 expected_tokenized_data.data(),
39 expected_tokenized_data.size()) == 0);
40
41 uint32_t line_level;
42 EXPECT_TRUE(entry_decoder.Next().ok()); // line_level
43 EXPECT_EQ(entry_decoder.FieldNumber(),
44 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kLineLevel));
45 EXPECT_TRUE(entry_decoder.ReadUint32(&line_level).ok());
46
47 uint32_t line_number;
48 uint8_t level;
49 std::tie(line_number, level) = UnpackLineLevel(line_level);
50 EXPECT_EQ(expected_metadata.level(), level);
51 EXPECT_EQ(expected_metadata.line_number(), line_number);
52
53 if (expected_metadata.flags() != 0) {
54 uint32_t flags;
55 EXPECT_TRUE(entry_decoder.Next().ok()); // flags
56 EXPECT_EQ(entry_decoder.FieldNumber(),
57 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kFlags));
58 EXPECT_TRUE(entry_decoder.ReadUint32(&flags).ok());
59 EXPECT_EQ(expected_metadata.flags(), flags);
60 }
61
62 int64_t timestamp;
63 EXPECT_TRUE(entry_decoder.Next().ok()); // timestamp
64 EXPECT_TRUE(
65 entry_decoder.FieldNumber() ==
66 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kTimestamp) ||
67 entry_decoder.FieldNumber() ==
68 static_cast<uint32_t>(
69 log::pwpb::LogEntry::Fields::kTimeSinceLastEntry));
70 EXPECT_TRUE(entry_decoder.ReadInt64(×tamp).ok());
71 EXPECT_EQ(expected_timestamp, timestamp);
72
73 if (expected_metadata.module() != 0) {
74 EXPECT_TRUE(entry_decoder.Next().ok()); // module name
75 EXPECT_EQ(entry_decoder.FieldNumber(),
76 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kModule));
77 const Result<uint32_t> module =
78 protobuf::DecodeBytesToUint32(entry_decoder);
79 ASSERT_TRUE(module.ok());
80 EXPECT_EQ(expected_metadata.module(), module.value());
81 }
82
83 if (!expected_thread_name.empty()) {
84 ConstByteSpan tokenized_thread_name;
85 EXPECT_TRUE(entry_decoder.Next().ok()); // thread [tokenized]
86 EXPECT_EQ(entry_decoder.FieldNumber(),
87 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kThread));
88 EXPECT_TRUE(entry_decoder.ReadBytes(&tokenized_thread_name).ok());
89 EXPECT_TRUE(std::memcmp(tokenized_thread_name.data(),
90 expected_thread_name.data(),
91 expected_thread_name.size()) == 0);
92 }
93 }
94
VerifyLogEntry(pw::protobuf::Decoder & entry_decoder,int expected_level,unsigned int expected_flags,std::string_view expected_module,std::string_view expected_thread_name,std::string_view expected_file_name,int expected_line_number,int64_t expected_ticks_since_epoch,std::string_view expected_message)95 void VerifyLogEntry(pw::protobuf::Decoder& entry_decoder,
96 int expected_level,
97 unsigned int expected_flags,
98 std::string_view expected_module,
99 std::string_view expected_thread_name,
100 std::string_view expected_file_name,
101 int expected_line_number,
102 int64_t expected_ticks_since_epoch,
103 std::string_view expected_message) {
104 std::string_view message;
105 EXPECT_TRUE(entry_decoder.Next().ok()); // message
106 EXPECT_EQ(entry_decoder.FieldNumber(),
107 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kMessage));
108 EXPECT_TRUE(entry_decoder.ReadString(&message).ok());
109 EXPECT_TRUE(pw::containers::Equal(message, expected_message));
110
111 uint32_t line_level;
112 EXPECT_TRUE(entry_decoder.Next().ok()); // line_level
113 EXPECT_EQ(entry_decoder.FieldNumber(),
114 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kLineLevel));
115 EXPECT_TRUE(entry_decoder.ReadUint32(&line_level).ok());
116 uint32_t line_number;
117 uint8_t level;
118 std::tie(line_number, level) = UnpackLineLevel(line_level);
119 EXPECT_EQ(static_cast<unsigned int>(expected_line_number), line_number);
120 EXPECT_EQ(expected_level, level);
121
122 if (expected_flags != 0) {
123 uint32_t flags;
124 EXPECT_TRUE(entry_decoder.Next().ok()); // flags
125 EXPECT_EQ(entry_decoder.FieldNumber(),
126 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kFlags));
127 EXPECT_TRUE(entry_decoder.ReadUint32(&flags).ok());
128 EXPECT_EQ(expected_flags, flags);
129 }
130
131 int64_t timestamp;
132 EXPECT_TRUE(entry_decoder.Next().ok()); // timestamp
133 EXPECT_TRUE(
134 entry_decoder.FieldNumber() ==
135 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kTimestamp) ||
136 entry_decoder.FieldNumber() ==
137 static_cast<uint32_t>(
138 log::pwpb::LogEntry::Fields::kTimeSinceLastEntry));
139 EXPECT_TRUE(entry_decoder.ReadInt64(×tamp).ok());
140 EXPECT_EQ(expected_ticks_since_epoch, timestamp);
141
142 if (!expected_module.empty()) {
143 std::string_view module_name;
144 EXPECT_TRUE(entry_decoder.Next().ok()); // module
145 EXPECT_EQ(entry_decoder.FieldNumber(),
146 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kModule));
147 EXPECT_TRUE(entry_decoder.ReadString(&module_name).ok());
148 EXPECT_TRUE(pw::containers::Equal(module_name, expected_module));
149 }
150
151 if (!expected_file_name.empty()) {
152 std::string_view file_name;
153 EXPECT_TRUE(entry_decoder.Next().ok()); // file
154 EXPECT_EQ(entry_decoder.FieldNumber(),
155 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kFile));
156 EXPECT_TRUE(entry_decoder.ReadString(&file_name).ok());
157 EXPECT_TRUE(pw::containers::Equal(file_name, expected_file_name));
158 }
159
160 if (!expected_thread_name.empty()) {
161 std::string_view thread_name;
162 EXPECT_TRUE(entry_decoder.Next().ok()); // file
163 EXPECT_EQ(entry_decoder.FieldNumber(),
164 static_cast<uint32_t>(log::pwpb::LogEntry::Fields::kThread));
165 EXPECT_TRUE(entry_decoder.ReadString(&thread_name).ok());
166 EXPECT_TRUE(pw::containers::Equal(thread_name, expected_thread_name));
167 }
168 }
169
TEST(UtilsTest,LineLevelPacking)170 TEST(UtilsTest, LineLevelPacking) {
171 constexpr uint8_t kExpectedLevel = PW_LOG_LEVEL_ERROR;
172 constexpr uint32_t kExpectedLine = 1234567;
173 constexpr uint32_t kExpectedLineLevel =
174 (kExpectedLine << PW_LOG_LEVEL_BITS) |
175 (kExpectedLevel & PW_LOG_LEVEL_BITMASK);
176
177 EXPECT_EQ(kExpectedLineLevel, PackLineLevel(kExpectedLine, kExpectedLevel));
178 }
179
TEST(UtilsTest,LineLevelUnpacking)180 TEST(UtilsTest, LineLevelUnpacking) {
181 constexpr uint8_t kExpectedLevel = PW_LOG_LEVEL_ERROR;
182 constexpr uint32_t kExpectedLine = 1234567;
183 constexpr uint32_t kExpectedLineLevel =
184 (kExpectedLine << PW_LOG_LEVEL_BITS) |
185 (kExpectedLevel & PW_LOG_LEVEL_BITMASK);
186
187 uint32_t line_number;
188 uint8_t level;
189 std::tie(line_number, level) = UnpackLineLevel(kExpectedLineLevel);
190
191 EXPECT_EQ(kExpectedLine, line_number);
192 EXPECT_EQ(kExpectedLevel, level);
193 }
194
TEST(UtilsTest,LineLevelPackAndUnpack)195 TEST(UtilsTest, LineLevelPackAndUnpack) {
196 constexpr uint8_t kExpectedLevel = PW_LOG_LEVEL_ERROR;
197 constexpr uint32_t kExpectedLine = 1234567;
198
199 uint32_t line_number;
200 uint8_t level;
201 std::tie(line_number, level) =
202 UnpackLineLevel(PackLineLevel(kExpectedLine, kExpectedLevel));
203
204 EXPECT_EQ(kExpectedLine, line_number);
205 EXPECT_EQ(kExpectedLevel, level);
206 }
207
TEST(UtilsTest,EncodeTokenizedLog)208 TEST(UtilsTest, EncodeTokenizedLog) {
209 constexpr std::byte kTokenizedData[1] = {std::byte(0x01)};
210 constexpr int64_t kExpectedTimestamp = 1;
211 constexpr std::byte kExpectedThreadName[1] = {std::byte(0x02)};
212 std::byte encode_buffer[32];
213
214 pw::log_tokenized::Metadata metadata =
215 pw::log_tokenized::Metadata::Set<1, 2, 3, 4>();
216
217 Result<ConstByteSpan> result = EncodeTokenizedLog(metadata,
218 kTokenizedData,
219 kExpectedTimestamp,
220 kExpectedThreadName,
221 encode_buffer);
222 EXPECT_TRUE(result.ok());
223
224 pw::protobuf::Decoder log_decoder(result.value());
225 VerifyTokenizedLogEntry(log_decoder,
226 metadata,
227 kTokenizedData,
228 kExpectedTimestamp,
229 kExpectedThreadName);
230
231 result = EncodeTokenizedLog(metadata,
232 reinterpret_cast<const uint8_t*>(kTokenizedData),
233 sizeof(kTokenizedData),
234 kExpectedTimestamp,
235 kExpectedThreadName,
236 encode_buffer);
237 EXPECT_TRUE(result.ok());
238
239 log_decoder.Reset(result.value());
240 VerifyTokenizedLogEntry(log_decoder,
241 metadata,
242 kTokenizedData,
243 kExpectedTimestamp,
244 kExpectedThreadName);
245 }
246
TEST(UtilsTest,EncodeTokenizedLog_EmptyFlags)247 TEST(UtilsTest, EncodeTokenizedLog_EmptyFlags) {
248 constexpr std::byte kTokenizedData[1] = {std::byte(0x01)};
249 constexpr int64_t kExpectedTimestamp = 1;
250 constexpr std::byte kExpectedThreadName[1] = {std::byte(0x02)};
251 std::byte encode_buffer[32];
252
253 // Create an empty flags set.
254 pw::log_tokenized::Metadata metadata =
255 pw::log_tokenized::Metadata::Set<1, 2, 0, 4>();
256
257 Result<ConstByteSpan> result = EncodeTokenizedLog(metadata,
258 kTokenizedData,
259 kExpectedTimestamp,
260 kExpectedThreadName,
261 encode_buffer);
262 EXPECT_TRUE(result.ok());
263
264 pw::protobuf::Decoder log_decoder(result.value());
265 VerifyTokenizedLogEntry(log_decoder,
266 metadata,
267 kTokenizedData,
268 kExpectedTimestamp,
269 kExpectedThreadName);
270 }
271
TEST(UtilsTest,EncodeTokenizedLog_InsufficientSpace)272 TEST(UtilsTest, EncodeTokenizedLog_InsufficientSpace) {
273 constexpr std::byte kTokenizedData[1] = {std::byte(0x01)};
274 constexpr int64_t kExpectedTimestamp = 1;
275 constexpr std::byte kExpectedThreadName[1] = {std::byte(0x02)};
276 std::byte encode_buffer[1];
277
278 pw::log_tokenized::Metadata metadata =
279 pw::log_tokenized::Metadata::Set<1, 2, 3, 4>();
280
281 Result<ConstByteSpan> result = EncodeTokenizedLog(metadata,
282 kTokenizedData,
283 kExpectedTimestamp,
284 kExpectedThreadName,
285 encode_buffer);
286 EXPECT_TRUE(result.status().IsResourceExhausted());
287 }
288
TEST(UtilsTest,EncodeLog)289 TEST(UtilsTest, EncodeLog) {
290 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
291 constexpr unsigned int kExpectedFlags = 2;
292 constexpr std::string_view kExpectedModule("TST");
293 constexpr std::string_view kExpectedThread("thread");
294 constexpr std::string_view kExpectedFile("proto_test.cc");
295 constexpr int kExpectedLine = 14;
296 constexpr int64_t kExpectedTimestamp = 1;
297 constexpr std::string_view kExpectedMessage("msg");
298 std::byte encode_buffer[64];
299
300 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
301 kExpectedFlags,
302 kExpectedModule,
303 kExpectedThread,
304 kExpectedFile,
305 kExpectedLine,
306 kExpectedTimestamp,
307 kExpectedMessage,
308 encode_buffer);
309 EXPECT_TRUE(result.ok());
310
311 pw::protobuf::Decoder log_decoder(result.value());
312 VerifyLogEntry(log_decoder,
313 kExpectedLevel,
314 kExpectedFlags,
315 kExpectedModule,
316 kExpectedThread,
317 kExpectedFile,
318 kExpectedLine,
319 kExpectedTimestamp,
320 kExpectedMessage);
321 }
322
TEST(UtilsTest,EncodeLog_EmptyFlags)323 TEST(UtilsTest, EncodeLog_EmptyFlags) {
324 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
325 constexpr unsigned int kExpectedFlags = 0;
326 constexpr std::string_view kExpectedModule("TST");
327 constexpr std::string_view kExpectedThread("thread");
328 constexpr std::string_view kExpectedFile("proto_test.cc");
329 constexpr int kExpectedLine = 14;
330 constexpr int64_t kExpectedTimestamp = 1;
331 constexpr std::string_view kExpectedMessage("msg");
332 std::byte encode_buffer[64];
333
334 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
335 kExpectedFlags,
336 kExpectedModule,
337 kExpectedThread,
338 kExpectedFile,
339 kExpectedLine,
340 kExpectedTimestamp,
341 kExpectedMessage,
342 encode_buffer);
343 EXPECT_TRUE(result.ok());
344
345 pw::protobuf::Decoder log_decoder(result.value());
346 VerifyLogEntry(log_decoder,
347 kExpectedLevel,
348 kExpectedFlags,
349 kExpectedModule,
350 kExpectedThread,
351 kExpectedFile,
352 kExpectedLine,
353 kExpectedTimestamp,
354 kExpectedMessage);
355 }
356
TEST(UtilsTest,EncodeLog_EmptyFile)357 TEST(UtilsTest, EncodeLog_EmptyFile) {
358 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
359 constexpr unsigned int kExpectedFlags = 0;
360 constexpr std::string_view kExpectedModule("TST");
361 constexpr std::string_view kExpectedThread("thread");
362 constexpr std::string_view kExpectedFile;
363 constexpr int kExpectedLine = 14;
364 constexpr int64_t kExpectedTimestamp = 1;
365 constexpr std::string_view kExpectedMessage("msg");
366 std::byte encode_buffer[64];
367
368 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
369 kExpectedFlags,
370 kExpectedModule,
371 kExpectedThread,
372 kExpectedFile,
373 kExpectedLine,
374 kExpectedTimestamp,
375 kExpectedMessage,
376 encode_buffer);
377 EXPECT_TRUE(result.ok());
378
379 pw::protobuf::Decoder log_decoder(result.value());
380 VerifyLogEntry(log_decoder,
381 kExpectedLevel,
382 kExpectedFlags,
383 kExpectedModule,
384 kExpectedThread,
385 kExpectedFile,
386 kExpectedLine,
387 kExpectedTimestamp,
388 kExpectedMessage);
389 }
390
TEST(UtilsTest,EncodeLog_EmptyModule)391 TEST(UtilsTest, EncodeLog_EmptyModule) {
392 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
393 constexpr unsigned int kExpectedFlags = 3;
394 constexpr std::string_view kExpectedModule;
395 constexpr std::string_view kExpectedThread("thread");
396 constexpr std::string_view kExpectedFile("test.cc");
397 constexpr int kExpectedLine = 14;
398 constexpr int64_t kExpectedTimestamp = 1;
399 constexpr std::string_view kExpectedMessage("msg");
400 std::byte encode_buffer[64];
401
402 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
403 kExpectedFlags,
404 kExpectedModule,
405 kExpectedThread,
406 kExpectedFile,
407 kExpectedLine,
408 kExpectedTimestamp,
409 kExpectedMessage,
410 encode_buffer);
411 EXPECT_TRUE(result.ok());
412
413 pw::protobuf::Decoder log_decoder(result.value());
414 VerifyLogEntry(log_decoder,
415 kExpectedLevel,
416 kExpectedFlags,
417 kExpectedModule,
418 kExpectedThread,
419 kExpectedFile,
420 kExpectedLine,
421 kExpectedTimestamp,
422 kExpectedMessage);
423 }
424
TEST(UtilsTest,EncodeLog_EmptyThread)425 TEST(UtilsTest, EncodeLog_EmptyThread) {
426 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
427 constexpr unsigned int kExpectedFlags = 2;
428 constexpr std::string_view kExpectedModule("TST");
429 constexpr std::string_view kExpectedThread;
430 constexpr std::string_view kExpectedFile("proto_test.cc");
431 constexpr int kExpectedLine = 14;
432 constexpr int64_t kExpectedTimestamp = 1;
433 constexpr std::string_view kExpectedMessage("msg");
434 std::byte encode_buffer[64];
435
436 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
437 kExpectedFlags,
438 kExpectedModule,
439 kExpectedThread,
440 kExpectedFile,
441 kExpectedLine,
442 kExpectedTimestamp,
443 kExpectedMessage,
444 encode_buffer);
445 EXPECT_TRUE(result.ok());
446
447 pw::protobuf::Decoder log_decoder(result.value());
448 VerifyLogEntry(log_decoder,
449 kExpectedLevel,
450 kExpectedFlags,
451 kExpectedModule,
452 kExpectedThread,
453 kExpectedFile,
454 kExpectedLine,
455 kExpectedTimestamp,
456 kExpectedMessage);
457 }
458
TEST(UtilsTest,EncodeLog_EmptyMessage)459 TEST(UtilsTest, EncodeLog_EmptyMessage) {
460 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
461 constexpr unsigned int kExpectedFlags = 0;
462 constexpr std::string_view kExpectedModule;
463 constexpr std::string_view kExpectedThread;
464 constexpr std::string_view kExpectedFile;
465 constexpr int kExpectedLine = 14;
466 constexpr int64_t kExpectedTimestamp = 1;
467 constexpr std::string_view kExpectedMessage;
468 std::byte encode_buffer[64];
469
470 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
471 kExpectedFlags,
472 kExpectedModule,
473 kExpectedThread,
474 kExpectedFile,
475 kExpectedLine,
476 kExpectedTimestamp,
477 kExpectedMessage,
478 encode_buffer);
479
480 EXPECT_TRUE(result.status().IsInvalidArgument());
481 }
482
TEST(UtilsTest,EncodeLog_InsufficientSpace)483 TEST(UtilsTest, EncodeLog_InsufficientSpace) {
484 constexpr int kExpectedLevel = PW_LOG_LEVEL_INFO;
485 constexpr unsigned int kExpectedFlags = 0;
486 constexpr std::string_view kExpectedModule;
487 constexpr std::string_view kExpectedThread;
488 constexpr std::string_view kExpectedFile;
489 constexpr int kExpectedLine = 14;
490 constexpr int64_t kExpectedTimestamp = 1;
491 constexpr std::string_view kExpectedMessage("msg");
492 std::byte encode_buffer[1];
493
494 Result<ConstByteSpan> result = EncodeLog(kExpectedLevel,
495 kExpectedFlags,
496 kExpectedModule,
497 kExpectedThread,
498 kExpectedFile,
499 kExpectedLine,
500 kExpectedTimestamp,
501 kExpectedMessage,
502 encode_buffer);
503
504 EXPECT_TRUE(result.status().IsResourceExhausted());
505 }
506
507 } // namespace pw::log
508