• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&timestamp).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(&timestamp).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