blob: 8ba01d93e1c321cd94b409cc002b5d458db1bdcf [file] [log] [blame]
Alexei Frolov99de52d2021-05-11 19:58:01 -07001// 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"
Wyatt Heplerf5cdd932021-06-14 13:53:23 -070018#include "pw_polyfill/language_feature_macros.h"
Alexei Frolov99de52d2021-05-11 19:58:01 -070019
20namespace pw {
21namespace {
22
Wyatt Heplerf4bac502021-10-15 14:48:01 -070023// 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
Wyatt Heplerf5cdd932021-06-14 13:53:23 -070044// Ensure that Function can be constant initialized.
45[[maybe_unused]] PW_CONSTINIT Function<void()> can_be_constant_initialized;
46
Alexei Frolov99de52d2021-05-11 19:58:01 -070047int Multiply(int a, int b) { return a * b; }
48
49TEST(Function, OperatorCall) {
50 Function<int(int, int)> multiply(Multiply);
51 EXPECT_EQ(multiply(3, 7), 21);
52}
53
54void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
55 callback(a + b);
56}
57
58int add_result = -1;
59
60void free_add_callback(int sum) { add_result = sum; }
61
62TEST(Function, ConstructInPlace_FreeFunction) {
63 add_result = -1;
64 CallbackAdd(25, 17, free_add_callback);
65 EXPECT_EQ(add_result, 42);
66}
67
68TEST(Function, ConstructInPlace_NonCapturingLambda) {
69 add_result = -1;
70 CallbackAdd(25, 18, [](int sum) { add_result = sum; });
71 EXPECT_EQ(add_result, 43);
72}
73
74TEST(Function, ConstructInPlace_CapturingLambda) {
75 int result = -1;
76 CallbackAdd(25, 19, [&](int sum) { result = sum; });
77 EXPECT_EQ(result, 44);
78}
79
80class CallableObject {
81 public:
82 CallableObject(int* result) : result_(result) {}
83
84 CallableObject(CallableObject&& other) = default;
85 CallableObject& operator=(CallableObject&& other) = default;
86
87 void operator()(int sum) { *result_ = sum; }
88
89 private:
90 int* result_;
91};
92
93TEST(Function, ConstructInPlace_CallableObject) {
94 int result = -1;
95 CallbackAdd(25, 20, CallableObject(&result));
96 EXPECT_EQ(result, 45);
97}
98
99class MemberFunctionTest : public ::testing::Test {
100 protected:
101 MemberFunctionTest() : result_(-1) {}
102
103 void set_result(int result) { result_ = result; }
104
105 int result_;
106};
107
108TEST_F(MemberFunctionTest, ConstructInPlace_Lambda) {
109 CallbackAdd(25, 21, [this](int sum) { set_result(sum); });
110 EXPECT_EQ(result_, 46);
111}
112
113TEST(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
130TEST(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
147TEST(Function, Null_Set) {
148 Closure function = []() {};
149 EXPECT_NE(function, nullptr);
150 function = nullptr;
151 EXPECT_EQ(function, nullptr);
152}
153
154void DoNothing() {}
155
156TEST(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
165TEST(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
177TEST(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
189TEST(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
201TEST(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
Ewout van Bekkum87ca34c2022-02-10 09:41:12 -0800213TEST(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
Alexei Frolov99de52d2021-05-11 19:58:01 -0700220class MoveTracker {
221 public:
222 MoveTracker() : move_count_(0) {}
223
224 MoveTracker(MoveTracker&& other) : move_count_(other.move_count_ + 1) {}
225 MoveTracker& operator=(MoveTracker&& other) = default;
226
227 int operator()() const { return move_count_; }
228
229 private:
230 int move_count_;
231};
232
233TEST(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
245TEST(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
Wyatt Hepler1af214d2022-01-19 10:42:47 -0800257TEST(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
Alexei Frolov99de52d2021-05-11 19:58:01 -0700279} // namespace
280} // namespace pw
Ewout van Bekkumc4a786a2021-07-27 17:05:12 -0700281
282namespace obscure_different_namespace_which_should_never_collide {
283namespace {
284
285TEST(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