1 // Copyright 2024 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_thread/deprecated_or_new_thread_function.h"
16
17 #include "pw_unit_test/framework.h"
18
19 namespace {
20
21 using ::pw::Function;
22 using ::pw::thread::DeprecatedFnPtrAndArg;
23 using ::pw::thread::DeprecatedOrNewThreadFn;
24
TEST(DeprecatedOrNewThreadFunction,CallInvokesLambda)25 TEST(DeprecatedOrNewThreadFunction, CallInvokesLambda) {
26 int call_count = 0;
27 DeprecatedOrNewThreadFn fn;
28 fn = Function<void()>([&call_count]() { ++call_count; });
29 EXPECT_EQ(call_count, 0);
30 fn();
31 EXPECT_EQ(call_count, 1);
32 }
33
TEST(DeprecatedOrNewThreadFunction,CallMovedInvokesLambda)34 TEST(DeprecatedOrNewThreadFunction, CallMovedInvokesLambda) {
35 int call_count = 0;
36 DeprecatedOrNewThreadFn fn;
37 fn = Function<void()>([&call_count]() { ++call_count; });
38 DeprecatedOrNewThreadFn fn2;
39 fn2 = std::move(fn);
40 EXPECT_EQ(call_count, 0);
41 fn2();
42 EXPECT_EQ(call_count, 1);
43 }
44
45 class DestroyCounter {
46 public:
DestroyCounter(int & counter)47 DestroyCounter(int& counter) : counter_(&counter) {}
48 DestroyCounter(const DestroyCounter&) = delete;
49 DestroyCounter& operator=(const DestroyCounter&) = delete;
DestroyCounter(DestroyCounter && other)50 DestroyCounter(DestroyCounter&& other) : counter_(other.counter_) {
51 other.counter_ = nullptr;
52 }
operator =(DestroyCounter && other)53 DestroyCounter& operator=(DestroyCounter&& other) {
54 CounterIncrement();
55 counter_ = other.counter_;
56 other.counter_ = nullptr;
57 return *this;
58 }
~DestroyCounter()59 ~DestroyCounter() { CounterIncrement(); }
60
61 private:
CounterIncrement()62 void CounterIncrement() {
63 if (counter_ != nullptr) {
64 ++(*counter_);
65 }
66 }
67 int* counter_;
68 };
69
TEST(DeprecatedOrNewThreadFunction,DestructionInvokesLambdasDestructor)70 TEST(DeprecatedOrNewThreadFunction, DestructionInvokesLambdasDestructor) {
71 int counter = 0;
72 {
73 DeprecatedOrNewThreadFn fn;
74 fn = Function<void()>([_unused = DestroyCounter(counter)]() {});
75 EXPECT_EQ(counter, 0);
76 }
77 EXPECT_EQ(counter, 1);
78 }
79
TEST(DeprecatedOrNewThreadFunction,DestructionMovedInvokesLambdasDestructor)80 TEST(DeprecatedOrNewThreadFunction, DestructionMovedInvokesLambdasDestructor) {
81 int counter = 0;
82 {
83 DeprecatedOrNewThreadFn fn;
84 {
85 fn = Function<void()>([_unused = DestroyCounter(counter)]() {});
86 DeprecatedOrNewThreadFn scoped_fn;
87 scoped_fn = std::move(fn);
88 EXPECT_EQ(counter, 0);
89 }
90 EXPECT_EQ(counter, 1);
91 }
92 EXPECT_EQ(counter, 1);
93 }
94
TEST(DeprecatedOrNewThreadFunction,NullptrAssignmentInvokesLambdasDestructor)95 TEST(DeprecatedOrNewThreadFunction, NullptrAssignmentInvokesLambdasDestructor) {
96 int counter = 0;
97 {
98 DeprecatedOrNewThreadFn fn;
99 fn = Function<void()>([_unused = DestroyCounter(counter)]() {});
100 EXPECT_EQ(counter, 0);
101 fn = nullptr;
102 EXPECT_EQ(counter, 1);
103 }
104 EXPECT_EQ(counter, 1);
105 }
106
increment(void * int_to_increment)107 void increment(void* int_to_increment) {
108 int& value = *static_cast<int*>(int_to_increment);
109 ++value;
110 }
111
TEST(DeprecatedOrNewThreadFunction,CallInvokesFnPtrWithArg)112 TEST(DeprecatedOrNewThreadFunction, CallInvokesFnPtrWithArg) {
113 int call_count = 0;
114 DeprecatedOrNewThreadFn fn;
115 fn = DeprecatedFnPtrAndArg{increment, static_cast<void*>(&call_count)};
116 EXPECT_EQ(call_count, 0);
117 fn();
118 EXPECT_EQ(call_count, 1);
119 }
120
TEST(DeprecatedOrNewThreadFunction,CallMovedInvokesFnPtrWithArg)121 TEST(DeprecatedOrNewThreadFunction, CallMovedInvokesFnPtrWithArg) {
122 int call_count = 0;
123 DeprecatedOrNewThreadFn fn;
124 fn = DeprecatedFnPtrAndArg{increment, static_cast<void*>(&call_count)};
125 DeprecatedOrNewThreadFn fn2;
126 fn2 = std::move(fn);
127 EXPECT_EQ(call_count, 0);
128 fn2();
129 EXPECT_EQ(call_count, 1);
130 }
131
132 } // namespace
133