1 // Copyright 2020 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 // clang-format off
16 #define PW_TRACE_MODULE_NAME "TST"
17
18 #include "pw_trace/trace.h"
19 #include "pw_trace_tokenized/trace_tokenized.h"
20 #include "pw_trace_tokenized/trace_callback.h"
21 // clang-format on
22
23 #include <deque>
24
25 #include "gtest/gtest.h"
26
27 namespace {
28
29 // These are line numbers for the functions below. Moving these functions to
30 // other lines will require updating these macros.
31 #define TRACE_FUNCTION_LINE 35
32 #define TRACE_FUNCTION_GROUP_LINE 36
33 #define TRACE_FUNCTION_ID_LINE 38
34
TraceFunction()35 void TraceFunction() { PW_TRACE_FUNCTION(); }
TraceFunctionGroup()36 void TraceFunctionGroup() { PW_TRACE_FUNCTION("FunctionGroup"); }
TraceFunctionTraceId(uint32_t id)37 void TraceFunctionTraceId(uint32_t id) {
38 PW_TRACE_FUNCTION("FunctionGroup", id);
39 }
40
41 // This trace test interface registers as a trace callback to capture trace
42 // events to verify extpected behaviour. It also supports testing common actions
43 // within the callback.
44 class TraceTestInterface {
45 public:
46 struct TraceInfo {
47 uint32_t trace_ref;
48 pw::trace::EventType event_type;
49 const char* module;
50 uint32_t trace_id;
operator ==__anon591c0e630111::TraceTestInterface::TraceInfo51 bool operator==(const TraceInfo& b) const {
52 return trace_ref == b.trace_ref && event_type == b.event_type &&
53 module == b.module && trace_id == b.trace_id;
54 }
55 };
56
TraceTestInterface()57 TraceTestInterface() {
58 PW_TRACE_SET_ENABLED(true);
59 pw::trace::Callbacks::Instance()
60 .RegisterSink(TraceSinkStartBlock,
61 TraceSinkAddBytes,
62 TraceSinkEndBlock,
63 this,
64 &sink_handle_)
65 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
66 pw::trace::Callbacks::Instance()
67 .RegisterEventCallback(TraceEventCallback,
68 pw::trace::CallbacksImpl::kCallOnlyWhenEnabled,
69 this,
70 &event_callback_handle_)
71 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
72 }
~TraceTestInterface()73 ~TraceTestInterface() {
74 pw::trace::Callbacks::Instance()
75 .UnregisterSink(sink_handle_)
76 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
77 pw::trace::Callbacks::Instance()
78 .UnregisterEventCallback(event_callback_handle_)
79 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
80 }
81 // ActionOnEvent will perform a specific action within the callback when an
82 // event matches one of the characteristics of event_match_.
83 enum class ActionOnEvent { None, Enable, Disable, DisableAfter, Skip };
SetCallbackEventAction(ActionOnEvent action,TraceInfo event)84 void SetCallbackEventAction(ActionOnEvent action, TraceInfo event) {
85 action_ = action;
86 event_match_ = event;
87 }
88
89 // The trace event callback will save the trace event info and add it to
90 // buffer_ in the TraceSink callback, that way it only gets added to the
91 // buffer if tracing is enabled and the sample was not surpressed.
TraceEventCallback(void * user_data,uint32_t trace_ref,pw_trace_EventType event_type,const char * module,uint32_t trace_id,uint8_t)92 static pw_trace_TraceEventReturnFlags TraceEventCallback(
93 void* user_data,
94 uint32_t trace_ref,
95 pw_trace_EventType event_type,
96 const char* module,
97 uint32_t trace_id,
98 uint8_t /* flags */) {
99 TraceTestInterface* test_interface =
100 reinterpret_cast<TraceTestInterface*>(user_data);
101 pw_trace_TraceEventReturnFlags ret = 0;
102 if (test_interface->action_ != ActionOnEvent::None &&
103 (test_interface->event_match_.trace_ref == trace_ref ||
104 test_interface->event_match_.event_type == event_type ||
105 test_interface->event_match_.module == module ||
106 (trace_id != PW_TRACE_TRACE_ID_DEFAULT &&
107 test_interface->event_match_.trace_id == trace_id))) {
108 if (test_interface->action_ == ActionOnEvent::Skip) {
109 ret |= PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT;
110 } else if (test_interface->action_ == ActionOnEvent::Enable) {
111 PW_TRACE_SET_ENABLED(true);
112 } else if (test_interface->action_ == ActionOnEvent::Disable) {
113 PW_TRACE_SET_ENABLED(false);
114 } else if (test_interface->action_ == ActionOnEvent::DisableAfter) {
115 ret |= PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING;
116 }
117 }
118
119 test_interface->current_trace_event_ =
120 TraceInfo{trace_ref, event_type, module, trace_id};
121 return ret;
122 }
123
124 // Only adds the event to buffer if the number of bytes inidcates is what is
125 // provided.
TraceSinkStartBlock(void * user_data,size_t size)126 static void TraceSinkStartBlock(void* user_data, size_t size) {
127 TraceTestInterface* test_interface =
128 reinterpret_cast<TraceTestInterface*>(user_data);
129 test_interface->sink_block_size_ = size;
130 test_interface->sink_bytes_received_ = 0;
131 }
132
TraceSinkAddBytes(void * user_data,const void * bytes,size_t size)133 static void TraceSinkAddBytes(void* user_data,
134 const void* bytes,
135 size_t size) {
136 TraceTestInterface* test_interface =
137 reinterpret_cast<TraceTestInterface*>(user_data);
138 static_cast<void>(bytes);
139 test_interface->sink_bytes_received_ += size;
140 }
141
TraceSinkEndBlock(void * user_data)142 static void TraceSinkEndBlock(void* user_data) {
143 TraceTestInterface* test_interface =
144 reinterpret_cast<TraceTestInterface*>(user_data);
145 if (test_interface->sink_block_size_ ==
146 test_interface->sink_bytes_received_) {
147 test_interface->buffer_.push_back(test_interface->current_trace_event_);
148 }
149 }
150
151 // Get the event buffer.
GetEvents()152 std::deque<TraceInfo>& GetEvents() { return buffer_; }
153
154 // Check that the next event in the buffer is equal to the expected (and pop
155 // that event).
CheckEvent(const TraceInfo & expected)156 bool CheckEvent(const TraceInfo& expected) {
157 if (buffer_.empty()) {
158 return false;
159 }
160 TraceInfo actual = buffer_.front();
161 buffer_.pop_front();
162 return actual == expected;
163 }
164
165 private:
166 ActionOnEvent action_ = ActionOnEvent::None;
167 TraceInfo event_match_;
168 TraceInfo current_trace_event_;
169 size_t sink_block_size_;
170 size_t sink_bytes_received_;
171 std::deque<TraceInfo> buffer_;
172 pw::trace::CallbacksImpl::SinkHandle sink_handle_;
173 pw::trace::CallbacksImpl::EventCallbackHandle event_callback_handle_;
174 };
175
176 } // namespace
177
178 // Helper macro to pop the next trace out of test interface and check it against
179 // expecte values.
180 #define EXPECT_TRACE(...) PW_DELEGATE_BY_ARG_COUNT(_EXPECT_TRACE, __VA_ARGS__)
181 #define _EXPECT_TRACE3(interface, event_type, label) \
182 _EXPECT_TRACE7(interface, \
183 event_type, \
184 label, \
185 PW_TRACE_GROUP_LABEL_DEFAULT, \
186 PW_TRACE_TRACE_ID_DEFAULT, \
187 PW_TRACE_MODULE_NAME, \
188 PW_TRACE_FLAGS_DEFAULT)
189 #define _EXPECT_TRACE4(interface, event_type, label, group) \
190 _EXPECT_TRACE7(interface, \
191 event_type, \
192 label, \
193 group, \
194 PW_TRACE_TRACE_ID_DEFAULT, \
195 PW_TRACE_MODULE_NAME, \
196 PW_TRACE_FLAGS_DEFAULT)
197 #define _EXPECT_TRACE5(interface, event_type, label, group, trace_id) \
198 _EXPECT_TRACE7(interface, \
199 event_type, \
200 label, \
201 group, \
202 trace_id, \
203 PW_TRACE_MODULE_NAME, \
204 PW_TRACE_FLAGS_DEFAULT)
205 #define _EXPECT_TRACE6(interface, event_type, label, group, trace_id, module) \
206 _EXPECT_TRACE7(interface, \
207 event_type, \
208 label, \
209 group, \
210 trace_id, \
211 module, \
212 PW_TRACE_FLAGS_DEFAULT)
213 #define _EXPECT_TRACE7( \
214 interface, event_type, label, group, trace_id, module, flags) \
215 do { \
216 static uint32_t _label_token = \
217 PW_TRACE_REF(event_type, module, label, flags, group); \
218 EXPECT_TRUE( \
219 interface.CheckEvent({_label_token, event_type, module, trace_id})); \
220 } while (0)
221
222 #define EXPECT_TRACE_DATA(...) \
223 PW_DELEGATE_BY_ARG_COUNT(_EXPECT_TRACE_DATA, __VA_ARGS__)
224 #define _EXPECT_TRACE_DATA4(interface, event_type, label, data_type) \
225 _EXPECT_TRACE_DATA8(interface, \
226 event_type, \
227 label, \
228 PW_TRACE_GROUP_LABEL_DEFAULT, \
229 PW_TRACE_TRACE_ID_DEFAULT, \
230 data_type, \
231 PW_TRACE_MODULE_NAME, \
232 PW_TRACE_FLAGS_DEFAULT)
233 #define _EXPECT_TRACE_DATA5(interface, event_type, label, group, data_type) \
234 _EXPECT_TRACE_DATA8(interface, \
235 event_type, \
236 label, \
237 group, \
238 PW_TRACE_TRACE_ID_DEFAULT, \
239 data_type, \
240 PW_TRACE_MODULE_NAME, \
241 PW_TRACE_FLAGS_DEFAULT)
242 #define _EXPECT_TRACE_DATA6( \
243 interface, event_type, label, group, trace_id, data_type) \
244 _EXPECT_TRACE_DATA8(interface, \
245 event_type, \
246 label, \
247 group, \
248 trace_id, \
249 data_type, \
250 PW_TRACE_MODULE_NAME, \
251 PW_TRACE_FLAGS_DEFAULT)
252 #define _EXPECT_TRACE_DATA7( \
253 interface, event_type, label, group, trace_id, data_type, module) \
254 _EXPECT_TRACE_DATA8(interface, \
255 event_type, \
256 label, \
257 group, \
258 trace_id, \
259 data_type, \
260 module, \
261 PW_TRACE_FLAGS_DEFAULT)
262 #define _EXPECT_TRACE_DATA8( \
263 interface, event_type, label, group, trace_id, data_type, module, flags) \
264 do { \
265 static uint32_t _label_token = \
266 PW_TRACE_REF_DATA(event_type, module, label, flags, group, data_type); \
267 EXPECT_TRUE( \
268 interface.CheckEvent({_label_token, event_type, module, trace_id})); \
269 } while (0)
270
271 // Start of tests
272
TEST(TokenizedTrace,Instant)273 TEST(TokenizedTrace, Instant) {
274 TraceTestInterface test_interface;
275
276 PW_TRACE_INSTANT("Test");
277 PW_TRACE_INSTANT("Test2", "g");
278 PW_TRACE_INSTANT("Test3", "g", 2);
279
280 // Check results
281 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test");
282 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT_GROUP, "Test2", "g");
283 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_ASYNC_INSTANT, "Test3", "g", 2);
284 EXPECT_TRUE(test_interface.GetEvents().empty());
285 }
286
TEST(TokenizedTrace,Duration)287 TEST(TokenizedTrace, Duration) {
288 TraceTestInterface test_interface;
289
290 PW_TRACE_START("Test");
291 PW_TRACE_END("Test");
292
293 // Check results
294 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_DURATION_START, "Test");
295 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_DURATION_END, "Test");
296 EXPECT_TRUE(test_interface.GetEvents().empty());
297 }
298
TEST(TokenizedTrace,DurationGroup)299 TEST(TokenizedTrace, DurationGroup) {
300 TraceTestInterface test_interface;
301
302 PW_TRACE_START("Parent", "group");
303 PW_TRACE_START("Child", "group");
304 PW_TRACE_END("Child", "group");
305 PW_TRACE_END("Parent", "group");
306
307 // Check results
308 EXPECT_TRACE(
309 test_interface, PW_TRACE_TYPE_DURATION_GROUP_START, "Parent", "group");
310 EXPECT_TRACE(
311 test_interface, PW_TRACE_TYPE_DURATION_GROUP_START, "Child", "group");
312 EXPECT_TRACE(
313 test_interface, PW_TRACE_TYPE_DURATION_GROUP_END, "Child", "group");
314 EXPECT_TRACE(
315 test_interface, PW_TRACE_TYPE_DURATION_GROUP_END, "Parent", "group");
316 EXPECT_TRUE(test_interface.GetEvents().empty());
317 }
318
TEST(TokenizedTrace,Async)319 TEST(TokenizedTrace, Async) {
320 TraceTestInterface test_interface;
321
322 uint32_t trace_id = 1;
323 PW_TRACE_START("label for async", "group", trace_id);
324 PW_TRACE_INSTANT("label for step", "group", trace_id);
325 PW_TRACE_END("label for async", "group", trace_id);
326
327 // Check results
328 EXPECT_TRACE(test_interface,
329 PW_TRACE_TYPE_ASYNC_START,
330 "label for async",
331 "group",
332 trace_id);
333 EXPECT_TRACE(test_interface,
334 PW_TRACE_TYPE_ASYNC_INSTANT,
335 "label for step",
336 "group",
337 trace_id);
338 EXPECT_TRACE(test_interface,
339 PW_TRACE_TYPE_ASYNC_END,
340 "label for async",
341 "group",
342 trace_id);
343 EXPECT_TRUE(test_interface.GetEvents().empty());
344 }
345
TEST(TokenizedTrace,SkipEvent)346 TEST(TokenizedTrace, SkipEvent) {
347 TraceTestInterface test_interface;
348
349 // Set trace interface to use skip flag in callback for a specific event.
350 TraceTestInterface::TraceInfo skip_event{
351 0, PW_TRACE_EVENT_TYPE_INVALID, "", PW_TRACE_TRACE_ID_DEFAULT};
352 skip_event.trace_ref = PW_TRACE_REF(PW_TRACE_TYPE_INSTANT,
353 "TST",
354 "Test2",
355 PW_TRACE_FLAGS_DEFAULT,
356 PW_TRACE_GROUP_LABEL_DEFAULT);
357 test_interface.SetCallbackEventAction(TraceTestInterface::ActionOnEvent::Skip,
358 skip_event);
359
360 PW_TRACE_INSTANT("Test");
361 PW_TRACE_INSTANT("Test2");
362
363 // Check results
364 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test");
365 EXPECT_TRUE(test_interface.GetEvents().empty());
366 }
367
TEST(TokenizedTrace,SkipModule)368 TEST(TokenizedTrace, SkipModule) {
369 TraceTestInterface test_interface;
370 // Set trace interface to use skip flag in callback for a module.
371 TraceTestInterface::TraceInfo skip_event{
372 0, PW_TRACE_EVENT_TYPE_INVALID, "", PW_TRACE_TRACE_ID_DEFAULT};
373 skip_event.module = "SkipModule";
374 test_interface.SetCallbackEventAction(TraceTestInterface::ActionOnEvent::Skip,
375 skip_event);
376
377 #undef PW_TRACE_MODULE_NAME
378 #define PW_TRACE_MODULE_NAME "SkipModule"
379 PW_TRACE_INSTANT("Test");
380 #undef PW_TRACE_MODULE_NAME
381 #define PW_TRACE_MODULE_NAME "TST"
382 PW_TRACE_INSTANT("Test2");
383
384 // Check results
385 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test2");
386 EXPECT_TRUE(test_interface.GetEvents().empty());
387 }
388
TEST(TokenizedTrace,DisableBeforeTrace)389 TEST(TokenizedTrace, DisableBeforeTrace) {
390 TraceTestInterface test_interface;
391
392 // Set trace interface to disable when a specific event happens.
393 TraceTestInterface::TraceInfo trigger{
394 0, PW_TRACE_EVENT_TYPE_INVALID, "", PW_TRACE_TRACE_ID_DEFAULT};
395 // Stop capturing when Test2 event shows up.
396 trigger.trace_ref = PW_TRACE_REF(PW_TRACE_TYPE_INSTANT,
397 "TST", // Module
398 "Test2", // Label
399 PW_TRACE_FLAGS_DEFAULT,
400 PW_TRACE_GROUP_LABEL_DEFAULT);
401 test_interface.SetCallbackEventAction(
402 TraceTestInterface::ActionOnEvent::Disable, trigger);
403
404 PW_TRACE_INSTANT("Test1");
405 PW_TRACE_INSTANT("Test2");
406 PW_TRACE_INSTANT("Test3");
407
408 // Check results
409 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test1");
410 EXPECT_TRUE(test_interface.GetEvents().empty());
411 }
412
TEST(TokenizedTrace,DisableAfterTrace)413 TEST(TokenizedTrace, DisableAfterTrace) {
414 TraceTestInterface test_interface;
415
416 // Set trace interface to use flag to disable after a specific event happens.
417 TraceTestInterface::TraceInfo trigger{
418 0, PW_TRACE_EVENT_TYPE_INVALID, "", PW_TRACE_TRACE_ID_DEFAULT};
419 // Stop capturing after Test2 event shows up.
420 trigger.trace_ref = PW_TRACE_REF(PW_TRACE_TYPE_INSTANT,
421 "TST", // Module
422 "Test2", // Label
423 PW_TRACE_FLAGS_DEFAULT,
424 PW_TRACE_GROUP_LABEL_DEFAULT);
425 test_interface.SetCallbackEventAction(
426 TraceTestInterface::ActionOnEvent::DisableAfter, trigger);
427
428 PW_TRACE_INSTANT("Test1");
429 PW_TRACE_INSTANT("Test2");
430 PW_TRACE_INSTANT("Test3");
431
432 // Check results
433 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test1");
434 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_INSTANT, "Test2");
435 EXPECT_TRUE(test_interface.GetEvents().empty());
436 }
437
TEST(TokenizedTrace,Scope)438 TEST(TokenizedTrace, Scope) {
439 TraceTestInterface test_interface;
440
441 { PW_TRACE_SCOPE("scoped trace"); }
442
443 // Check results
444 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_DURATION_START, "scoped trace");
445 EXPECT_TRACE(test_interface, PW_TRACE_TYPE_DURATION_END, "scoped trace");
446 EXPECT_TRUE(test_interface.GetEvents().empty());
447 }
448
TEST(TokenizedTrace,ScopeGroup)449 TEST(TokenizedTrace, ScopeGroup) {
450 TraceTestInterface test_interface;
451
452 { PW_TRACE_SCOPE("scoped group trace", "group"); }
453
454 // Check results
455 EXPECT_TRACE(test_interface,
456 PW_TRACE_TYPE_DURATION_GROUP_START,
457 "scoped group trace",
458 "group");
459 EXPECT_TRACE(test_interface,
460 PW_TRACE_TYPE_DURATION_GROUP_END,
461 "scoped group trace",
462 "group");
463 EXPECT_TRUE(test_interface.GetEvents().empty());
464 }
465
TEST(TokenizedTrace,ScopeLoop)466 TEST(TokenizedTrace, ScopeLoop) {
467 TraceTestInterface test_interface;
468
469 for (uint32_t i = 0; i < 10; i++) {
470 PW_TRACE_SCOPE("scoped loop", "group", i);
471 }
472 // Check results
473 for (uint32_t i = 0; i < 10; i++) {
474 EXPECT_TRACE(
475 test_interface, PW_TRACE_TYPE_ASYNC_START, "scoped loop", "group", i);
476 EXPECT_TRACE(
477 test_interface, PW_TRACE_TYPE_ASYNC_END, "scoped loop", "group", i);
478 }
479 EXPECT_TRUE(test_interface.GetEvents().empty());
480 }
481
TEST(TokenizedTrace,Function)482 TEST(TokenizedTrace, Function) {
483 TraceTestInterface test_interface;
484
485 TraceFunction();
486
487 // Check results
488 EXPECT_TRACE(
489 test_interface,
490 PW_TRACE_TYPE_DURATION_START,
491 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_LINE));
492 EXPECT_TRACE(
493 test_interface,
494 PW_TRACE_TYPE_DURATION_END,
495 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_LINE));
496 EXPECT_TRUE(test_interface.GetEvents().empty());
497 }
498
TEST(TokenizedTrace,FunctionGroup)499 TEST(TokenizedTrace, FunctionGroup) {
500 TraceTestInterface test_interface;
501
502 TraceFunctionGroup();
503
504 // Check results
505 EXPECT_TRACE(
506 test_interface,
507 PW_TRACE_TYPE_DURATION_GROUP_START,
508 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_GROUP_LINE),
509 "FunctionGroup");
510 EXPECT_TRACE(
511 test_interface,
512 PW_TRACE_TYPE_DURATION_GROUP_END,
513 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_GROUP_LINE),
514 "FunctionGroup");
515 EXPECT_TRUE(test_interface.GetEvents().empty());
516 }
517
TEST(TokenizedTrace,FunctionTraceId)518 TEST(TokenizedTrace, FunctionTraceId) {
519 TraceTestInterface test_interface;
520 static constexpr uint32_t kTraceId = 5;
521 TraceFunctionTraceId(kTraceId);
522
523 // Check results
524 EXPECT_TRACE(
525 test_interface,
526 PW_TRACE_TYPE_ASYNC_START,
527 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_ID_LINE),
528 "FunctionGroup",
529 kTraceId);
530 EXPECT_TRACE(
531 test_interface,
532 PW_TRACE_TYPE_ASYNC_END,
533 PW_TRACE_FUNCTION_LABEL_FILE_LINE(__FILE__, TRACE_FUNCTION_ID_LINE),
534 "FunctionGroup",
535 kTraceId);
536 EXPECT_TRUE(test_interface.GetEvents().empty());
537 }
538
TEST(TokenizedTrace,Data)539 TEST(TokenizedTrace, Data) {
540 TraceTestInterface test_interface;
541 int value = 5;
542 PW_TRACE_INSTANT_DATA("label", "i", &value, sizeof(value));
543 // Check results
544 EXPECT_TRACE_DATA(test_interface,
545 PW_TRACE_TYPE_INSTANT,
546 "label",
547 "i"); // TODO(rgoliver): check data
548 EXPECT_TRUE(test_interface.GetEvents().empty());
549 }
550
551 // Create some helper macros that generated some test trace data based from a
552 // number, and can check that it is correct.
553 constexpr std::byte kTestData[] = {
554 std::byte{0}, std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4}};
555 #define QUEUE_TESTS_ARGS(num) \
556 (num), static_cast<pw_trace_EventType>((num) % 10), \
557 "module_" PW_STRINGIFY(num), (num), (num), kTestData, \
558 (num) % PW_ARRAY_SIZE(kTestData)
559 #define QUEUE_CHECK_RESULT(queue_size, result, num) \
560 result && ((result->trace_token) == (num)) && \
561 ((result->event_type) == static_cast<pw_trace_EventType>((num) % 10)) && \
562 (strncmp(result->module, \
563 "module_" PW_STRINGIFY(num), \
564 strlen("module_" PW_STRINGIFY(num))) == 0) && \
565 ((result->trace_id) == (num)) && ((result->flags) == (num)) && \
566 (memcmp(const_cast<const pw::trace::internal::TraceQueue< \
567 queue_size>::QueueEventBlock*>(result) \
568 ->data_buffer, \
569 kTestData, \
570 result->data_size) == 0) && \
571 (result->data_size == (num) % PW_ARRAY_SIZE(kTestData))
572
TEST(TokenizedTrace,QueueSimple)573 TEST(TokenizedTrace, QueueSimple) {
574 constexpr size_t kQueueSize = 5;
575 pw::trace::internal::TraceQueue<kQueueSize> queue;
576 constexpr size_t kTestNum = 1;
577 queue.TryPushBack(QUEUE_TESTS_ARGS(kTestNum))
578 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
579 EXPECT_FALSE(queue.IsEmpty());
580 EXPECT_FALSE(queue.IsFull());
581 EXPECT_TRUE(QUEUE_CHECK_RESULT(kQueueSize, queue.PeekFront(), kTestNum));
582 queue.PopFront();
583 EXPECT_TRUE(queue.IsEmpty());
584 EXPECT_TRUE(queue.PeekFront() == nullptr);
585 EXPECT_FALSE(queue.IsFull());
586 }
587
TEST(TokenizedTrace,QueueFull)588 TEST(TokenizedTrace, QueueFull) {
589 constexpr size_t kQueueSize = 5;
590 pw::trace::internal::TraceQueue<kQueueSize> queue;
591 for (size_t i = 0; i < kQueueSize; i++) {
592 EXPECT_EQ(queue.TryPushBack(QUEUE_TESTS_ARGS(i)), pw::OkStatus());
593 }
594 EXPECT_FALSE(queue.IsEmpty());
595 EXPECT_TRUE(queue.IsFull());
596 EXPECT_EQ(queue.TryPushBack(QUEUE_TESTS_ARGS(1)),
597 pw::Status::ResourceExhausted());
598
599 for (size_t i = 0; i < kQueueSize; i++) {
600 EXPECT_TRUE(QUEUE_CHECK_RESULT(kQueueSize, queue.PeekFront(), i));
601 queue.PopFront();
602 }
603 EXPECT_TRUE(queue.IsEmpty());
604 EXPECT_TRUE(queue.PeekFront() == nullptr);
605 EXPECT_FALSE(queue.IsFull());
606 }
607
TEST(TokenizedTrace,Clear)608 TEST(TokenizedTrace, Clear) {
609 constexpr size_t kQueueSize = 5;
610 pw::trace::internal::TraceQueue<kQueueSize> queue;
611 for (size_t i = 0; i < kQueueSize; i++) {
612 EXPECT_EQ(queue.TryPushBack(QUEUE_TESTS_ARGS(i)), pw::OkStatus());
613 }
614 EXPECT_FALSE(queue.IsEmpty());
615 EXPECT_TRUE(queue.IsFull());
616 queue.Clear();
617 EXPECT_TRUE(queue.IsEmpty());
618 EXPECT_TRUE(queue.PeekFront() == nullptr);
619 EXPECT_FALSE(queue.IsFull());
620 }
621