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