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