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