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