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