1 // Copyright 2021 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_function/function.h"
16
17 #include "gtest/gtest.h"
18 #include "pw_polyfill/language_feature_macros.h"
19
20 namespace pw {
21 namespace {
22
23 // TODO(pwbug/47): Convert this to a compilation failure test.
24 #if defined(PW_COMPILE_FAIL_TEST_CannotInstantiateWithNonFunction)
25
26 [[maybe_unused]] Function<int> function_pointer;
27
28 #elif defined(PW_COMPILE_FAIL_TEST_CannotInstantiateWithFunctionPointer1)
29
30 [[maybe_unused]] Function<void (*)()> function_pointer;
31
32 #elif defined(PW_COMPILE_FAIL_TEST_CannotInstantiateWithFunctionPointer2)
33
34 [[maybe_unused]] void SomeFunction(int);
35
36 [[maybe_unused]] Function<decltype(&SomeFunction)> function_pointer;
37
38 #elif defined(PW_COMPILE_FAIL_TEST_CannotInstantiateWithFunctionReference)
39
40 [[maybe_unused]] Function<void (&)()> function_pointer;
41
42 #endif // compile fail tests
43
44 // Ensure that Function can be constant initialized.
45 [[maybe_unused]] PW_CONSTINIT Function<void()> can_be_constant_initialized;
46
Multiply(int a,int b)47 int Multiply(int a, int b) { return a * b; }
48
TEST(Function,OperatorCall)49 TEST(Function, OperatorCall) {
50 Function<int(int, int)> multiply(Multiply);
51 EXPECT_EQ(multiply(3, 7), 21);
52 }
53
CallbackAdd(int a,int b,pw::Function<void (int sum)> callback)54 void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
55 callback(a + b);
56 }
57
58 int add_result = -1;
59
free_add_callback(int sum)60 void free_add_callback(int sum) { add_result = sum; }
61
TEST(Function,ConstructInPlace_FreeFunction)62 TEST(Function, ConstructInPlace_FreeFunction) {
63 add_result = -1;
64 CallbackAdd(25, 17, free_add_callback);
65 EXPECT_EQ(add_result, 42);
66 }
67
TEST(Function,ConstructInPlace_NonCapturingLambda)68 TEST(Function, ConstructInPlace_NonCapturingLambda) {
69 add_result = -1;
70 CallbackAdd(25, 18, [](int sum) { add_result = sum; });
71 EXPECT_EQ(add_result, 43);
72 }
73
TEST(Function,ConstructInPlace_CapturingLambda)74 TEST(Function, ConstructInPlace_CapturingLambda) {
75 int result = -1;
76 CallbackAdd(25, 19, [&](int sum) { result = sum; });
77 EXPECT_EQ(result, 44);
78 }
79
80 class CallableObject {
81 public:
CallableObject(int * result)82 CallableObject(int* result) : result_(result) {}
83
84 CallableObject(CallableObject&& other) = default;
85 CallableObject& operator=(CallableObject&& other) = default;
86
operator ()(int sum)87 void operator()(int sum) { *result_ = sum; }
88
89 private:
90 int* result_;
91 };
92
TEST(Function,ConstructInPlace_CallableObject)93 TEST(Function, ConstructInPlace_CallableObject) {
94 int result = -1;
95 CallbackAdd(25, 20, CallableObject(&result));
96 EXPECT_EQ(result, 45);
97 }
98
99 class MemberFunctionTest : public ::testing::Test {
100 protected:
MemberFunctionTest()101 MemberFunctionTest() : result_(-1) {}
102
set_result(int result)103 void set_result(int result) { result_ = result; }
104
105 int result_;
106 };
107
TEST_F(MemberFunctionTest,ConstructInPlace_Lambda)108 TEST_F(MemberFunctionTest, ConstructInPlace_Lambda) {
109 CallbackAdd(25, 21, [this](int sum) { set_result(sum); });
110 EXPECT_EQ(result_, 46);
111 }
112
TEST(Function,Null_OperatorBool)113 TEST(Function, Null_OperatorBool) {
114 Closure implicit_null;
115 Closure explicit_null(nullptr);
116 Closure assigned_null = nullptr;
117 Closure not_null([]() {});
118
119 EXPECT_FALSE(bool(implicit_null));
120 EXPECT_FALSE(bool(explicit_null));
121 EXPECT_FALSE(bool(assigned_null));
122 EXPECT_TRUE(bool(not_null));
123
124 EXPECT_TRUE(!implicit_null);
125 EXPECT_TRUE(!explicit_null);
126 EXPECT_TRUE(!assigned_null);
127 EXPECT_FALSE(!not_null);
128 }
129
TEST(Function,Null_OperatorEquals)130 TEST(Function, Null_OperatorEquals) {
131 Closure implicit_null;
132 Closure explicit_null(nullptr);
133 Closure assigned_null = nullptr;
134 Closure not_null([]() {});
135
136 EXPECT_TRUE(implicit_null == nullptr);
137 EXPECT_TRUE(explicit_null == nullptr);
138 EXPECT_TRUE(assigned_null == nullptr);
139 EXPECT_TRUE(not_null != nullptr);
140
141 EXPECT_FALSE(implicit_null != nullptr);
142 EXPECT_FALSE(explicit_null != nullptr);
143 EXPECT_FALSE(assigned_null != nullptr);
144 EXPECT_FALSE(not_null == nullptr);
145 }
146
TEST(Function,Null_Set)147 TEST(Function, Null_Set) {
148 Closure function = []() {};
149 EXPECT_NE(function, nullptr);
150 function = nullptr;
151 EXPECT_EQ(function, nullptr);
152 }
153
DoNothing()154 void DoNothing() {}
155
TEST(Function,Null_FunctionPointer)156 TEST(Function, Null_FunctionPointer) {
157 void (*ptr)() = DoNothing;
158 Closure not_null(ptr);
159 EXPECT_NE(not_null, nullptr);
160 ptr = nullptr;
161 Closure is_null(ptr);
162 EXPECT_EQ(is_null, nullptr);
163 }
164
TEST(Function,Move_Null)165 TEST(Function, Move_Null) {
166 Closure moved;
167 EXPECT_EQ(moved, nullptr);
168 Closure function(std::move(moved));
169 EXPECT_EQ(function, nullptr);
170
171 // Ignore use-after-move.
172 #ifndef __clang_analyzer__
173 EXPECT_EQ(moved, nullptr);
174 #endif // __clang_analyzer__
175 }
176
TEST(Function,MoveAssign_Null)177 TEST(Function, MoveAssign_Null) {
178 Closure moved;
179 EXPECT_EQ(moved, nullptr);
180 Closure function = std::move(moved);
181 EXPECT_EQ(function, nullptr);
182
183 // Ignore use-after-move.
184 #ifndef __clang_analyzer__
185 EXPECT_EQ(moved, nullptr);
186 #endif // __clang_analyzer__
187 }
188
TEST(Function,Move_Inline)189 TEST(Function, Move_Inline) {
190 Function<int(int, int)> moved(Multiply);
191 EXPECT_NE(moved, nullptr);
192 Function<int(int, int)> multiply(std::move(moved));
193 EXPECT_EQ(multiply(3, 3), 9);
194
195 // Ignore use-after-move.
196 #ifndef __clang_analyzer__
197 EXPECT_EQ(moved, nullptr);
198 #endif // __clang_analyzer__
199 }
200
TEST(Function,MoveAssign_Inline)201 TEST(Function, MoveAssign_Inline) {
202 Function<int(int, int)> moved(Multiply);
203 EXPECT_NE(moved, nullptr);
204 Function<int(int, int)> multiply = std::move(moved);
205 EXPECT_EQ(multiply(3, 3), 9);
206
207 // Ignore use-after-move.
208 #ifndef __clang_analyzer__
209 EXPECT_EQ(moved, nullptr);
210 #endif // __clang_analyzer__
211 }
212
TEST(Function,MoveAssign_Callable)213 TEST(Function, MoveAssign_Callable) {
214 Function<int(int, int)> operation = Multiply;
215 EXPECT_EQ(operation(3, 3), 9);
216 operation = [](int a, int b) -> int { return a + b; };
217 EXPECT_EQ(operation(3, 3), 6);
218 }
219
220 class MoveTracker {
221 public:
MoveTracker()222 MoveTracker() : move_count_(0) {}
223
MoveTracker(MoveTracker && other)224 MoveTracker(MoveTracker&& other) : move_count_(other.move_count_ + 1) {}
225 MoveTracker& operator=(MoveTracker&& other) = default;
226
operator ()() const227 int operator()() const { return move_count_; }
228
229 private:
230 int move_count_;
231 };
232
TEST(Function,Move_CustomObject)233 TEST(Function, Move_CustomObject) {
234 Function<int()> moved((MoveTracker()));
235 EXPECT_EQ(moved(), 2); // internally moves twice on construction
236 Function<int()> tracker(std::move(moved));
237 EXPECT_EQ(tracker(), 3);
238
239 // Ignore use-after-move.
240 #ifndef __clang_analyzer__
241 EXPECT_EQ(moved, nullptr);
242 #endif // __clang_analyzer__
243 }
244
TEST(Function,MoveAssign_CustomObject)245 TEST(Function, MoveAssign_CustomObject) {
246 Function<int()> moved((MoveTracker()));
247 EXPECT_EQ(moved(), 2); // internally moves twice on construction
248 Function<int()> tracker = std::move(moved);
249 EXPECT_EQ(tracker(), 3);
250
251 // Ignore use-after-move.
252 #ifndef __clang_analyzer__
253 EXPECT_EQ(moved, nullptr);
254 #endif // __clang_analyzer__
255 }
256
TEST(Function,MoveOnlyType)257 TEST(Function, MoveOnlyType) {
258 class MoveOnlyType {
259 public:
260 MoveOnlyType() = default;
261
262 MoveOnlyType(const MoveOnlyType& other) = delete;
263 MoveOnlyType& operator=(const MoveOnlyType& other) = delete;
264
265 MoveOnlyType(MoveOnlyType&&) = default;
266 MoveOnlyType& operator=(MoveOnlyType&&) = default;
267
268 bool ItsWorking() const { return true; }
269 };
270
271 pw::Function<bool(MoveOnlyType)> function = [](MoveOnlyType value) {
272 return value.ItsWorking();
273 };
274
275 MoveOnlyType move_only;
276 EXPECT_TRUE(function(std::move(move_only)));
277 }
278
279 } // namespace
280 } // namespace pw
281
282 namespace obscure_different_namespace_which_should_never_collide {
283 namespace {
284
TEST(Function,Null_OperatorEquals_DifferentNamespace)285 TEST(Function, Null_OperatorEquals_DifferentNamespace) {
286 pw::Closure implicit_null;
287 pw::Closure explicit_null(nullptr);
288 pw::Closure assigned_null = nullptr;
289 pw::Closure not_null([]() {});
290
291 EXPECT_TRUE(implicit_null == nullptr);
292 EXPECT_TRUE(explicit_null == nullptr);
293 EXPECT_TRUE(assigned_null == nullptr);
294 EXPECT_TRUE(not_null != nullptr);
295
296 EXPECT_FALSE(implicit_null != nullptr);
297 EXPECT_FALSE(explicit_null != nullptr);
298 EXPECT_FALSE(assigned_null != nullptr);
299 EXPECT_FALSE(not_null == nullptr);
300 }
301
302 } // namespace
303 } // namespace obscure_different_namespace_which_should_never_collide
304