• 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 "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(&timestamp).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(&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::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