• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_compilation_testing/negative_compilation.h"
19 #include "pw_polyfill/language_feature_macros.h"
20 
21 namespace pw {
22 namespace {
23 
24 #if PW_NC_TEST(CannotInstantiateWithNonFunction)
25 PW_NC_EXPECT("must be instantiated with a function type");
26 
27 [[maybe_unused]] Function<int> function_pointer;
28 
29 #elif PW_NC_TEST(CannotInstantiateWithFunctionPointer1)
30 PW_NC_EXPECT("must be instantiated with a function type");
31 
32 [[maybe_unused]] Function<void (*)()> function_pointer;
33 
34 #elif PW_NC_TEST(CannotInstantiateWithFunctionPointer2)
35 PW_NC_EXPECT("must be instantiated with a function type");
36 
37 [[maybe_unused]] void SomeFunction(int);
38 
39 [[maybe_unused]] Function<decltype(&SomeFunction)> function_pointer;
40 
41 #elif PW_NC_TEST(CannotInstantiateWithFunctionReference)
42 PW_NC_EXPECT("must be instantiated with a function type");
43 
44 [[maybe_unused]] Function<void (&)()> function_pointer;
45 
46 #endif  // PW_NC_TEST
47 
48 // Ensure that Function can be constant initialized.
49 [[maybe_unused]] PW_CONSTINIT Function<void()> can_be_constant_initialized;
50 
Multiply(int a,int b)51 int Multiply(int a, int b) { return a * b; }
52 
TEST(Function,OperatorCall)53 TEST(Function, OperatorCall) {
54   Function<int(int, int)> multiply(Multiply);
55   EXPECT_EQ(multiply(3, 7), 21);
56 }
57 
CallbackAdd(int a,int b,pw::Function<void (int sum)> callback)58 void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
59   callback(a + b);
60 }
61 
InlineCallbackAdd(int a,int b,pw::InlineFunction<void (int sum)> callback)62 void InlineCallbackAdd(int a,
63                        int b,
64                        pw::InlineFunction<void(int sum)> callback) {
65   callback(a + b);
66 }
67 
68 int add_result = -1;
69 
free_add_callback(int sum)70 void free_add_callback(int sum) { add_result = sum; }
71 
TEST(Function,ConstructInPlace_FreeFunction)72 TEST(Function, ConstructInPlace_FreeFunction) {
73   add_result = -1;
74   CallbackAdd(25, 17, free_add_callback);
75   EXPECT_EQ(add_result, 42);
76 }
77 
TEST(Function,ConstructInPlace_NonCapturingLambda)78 TEST(Function, ConstructInPlace_NonCapturingLambda) {
79   add_result = -1;
80   CallbackAdd(25, 18, [](int sum) { add_result = sum; });
81   EXPECT_EQ(add_result, 43);
82 }
83 
TEST(Function,ConstructInPlace_CapturingLambda)84 TEST(Function, ConstructInPlace_CapturingLambda) {
85   int result = -1;
86   CallbackAdd(25, 19, [&](int sum) { result = sum; });
87   EXPECT_EQ(result, 44);
88 }
89 
TEST(InlineFunction,ConstructInPlace_FreeFunction)90 TEST(InlineFunction, ConstructInPlace_FreeFunction) {
91   add_result = -1;
92   InlineCallbackAdd(25, 17, free_add_callback);
93   EXPECT_EQ(add_result, 42);
94 }
95 
TEST(InlineFunction,ConstructInPlace_NonCapturingLambda)96 TEST(InlineFunction, ConstructInPlace_NonCapturingLambda) {
97   add_result = -1;
98   InlineCallbackAdd(25, 18, [](int sum) { add_result = sum; });
99   EXPECT_EQ(add_result, 43);
100 }
101 
TEST(InlineFunction,ConstructInPlace_CapturingLambda)102 TEST(InlineFunction, ConstructInPlace_CapturingLambda) {
103   int result = -1;
104   InlineCallbackAdd(25, 19, [&](int sum) { result = sum; });
105   EXPECT_EQ(result, 44);
106 }
107 
108 class CallableObject {
109  public:
CallableObject(int * result)110   CallableObject(int* result) : result_(result) {}
111 
112   CallableObject(CallableObject&& other) = default;
113   CallableObject& operator=(CallableObject&& other) = default;
114 
operator ()(int sum)115   void operator()(int sum) { *result_ = sum; }
116 
117  private:
118   int* result_;
119 };
120 
TEST(Function,ConstructInPlace_CallableObject)121 TEST(Function, ConstructInPlace_CallableObject) {
122   int result = -1;
123   CallbackAdd(25, 20, CallableObject(&result));
124   EXPECT_EQ(result, 45);
125 }
126 
TEST(InlineFunction,ConstructInPlace_CallableObject)127 TEST(InlineFunction, ConstructInPlace_CallableObject) {
128   int result = -1;
129   InlineCallbackAdd(25, 20, CallableObject(&result));
130   EXPECT_EQ(result, 45);
131 }
132 
133 class MemberFunctionTest : public ::testing::Test {
134  protected:
MemberFunctionTest()135   MemberFunctionTest() : result_(-1) {}
136 
set_result(int result)137   void set_result(int result) { result_ = result; }
138 
139   int result_;
140 };
141 
TEST_F(MemberFunctionTest,ConstructInPlace_Lambda)142 TEST_F(MemberFunctionTest, ConstructInPlace_Lambda) {
143   CallbackAdd(25, 21, [this](int sum) { set_result(sum); });
144   EXPECT_EQ(result_, 46);
145 }
146 
TEST(Function,Null_OperatorBool)147 TEST(Function, Null_OperatorBool) {
148   Closure implicit_null;
149   Closure explicit_null(nullptr);
150   Closure assigned_null = nullptr;
151   Closure not_null([]() {});
152 
153   EXPECT_FALSE(bool(implicit_null));
154   EXPECT_FALSE(bool(explicit_null));
155   EXPECT_FALSE(bool(assigned_null));
156   EXPECT_TRUE(bool(not_null));
157 
158   EXPECT_TRUE(!implicit_null);
159   EXPECT_TRUE(!explicit_null);
160   EXPECT_TRUE(!assigned_null);
161   EXPECT_FALSE(!not_null);
162 }
163 
TEST(Function,Null_OperatorEquals)164 TEST(Function, Null_OperatorEquals) {
165   Closure implicit_null;
166   Closure explicit_null(nullptr);
167   Closure assigned_null = nullptr;
168   Closure not_null([]() {});
169 
170   EXPECT_TRUE(implicit_null == nullptr);
171   EXPECT_TRUE(explicit_null == nullptr);
172   EXPECT_TRUE(assigned_null == nullptr);
173   EXPECT_TRUE(not_null != nullptr);
174 
175   EXPECT_FALSE(implicit_null != nullptr);
176   EXPECT_FALSE(explicit_null != nullptr);
177   EXPECT_FALSE(assigned_null != nullptr);
178   EXPECT_FALSE(not_null == nullptr);
179 }
180 
TEST(Function,Null_Set)181 TEST(Function, Null_Set) {
182   Closure function = []() {};
183   EXPECT_NE(function, nullptr);
184   function = nullptr;
185   EXPECT_EQ(function, nullptr);
186 }
187 
DoNothing()188 void DoNothing() {}
189 
TEST(Function,Null_FunctionPointer)190 TEST(Function, Null_FunctionPointer) {
191   void (*ptr)() = DoNothing;
192   Closure not_null(ptr);
193   EXPECT_NE(not_null, nullptr);
194   ptr = nullptr;
195   Closure is_null(ptr);
196   EXPECT_EQ(is_null, nullptr);
197 }
198 
TEST(Function,Move_Null)199 TEST(Function, Move_Null) {
200   Closure moved;
201   EXPECT_EQ(moved, nullptr);
202   Closure function(std::move(moved));
203   EXPECT_EQ(function, nullptr);
204 
205 // Ignore use-after-move.
206 #ifndef __clang_analyzer__
207   EXPECT_EQ(moved, nullptr);
208 #endif  // __clang_analyzer__
209 }
210 
TEST(Function,MoveAssign_Null)211 TEST(Function, MoveAssign_Null) {
212   Closure moved;
213   EXPECT_EQ(moved, nullptr);
214   Closure function = std::move(moved);
215   EXPECT_EQ(function, nullptr);
216 
217 // Ignore use-after-move.
218 #ifndef __clang_analyzer__
219   EXPECT_EQ(moved, nullptr);
220 #endif  // __clang_analyzer__
221 }
222 
TEST(Function,Move_Inline)223 TEST(Function, Move_Inline) {
224   Function<int(int, int)> moved(Multiply);
225   EXPECT_NE(moved, nullptr);
226   Function<int(int, int)> multiply(std::move(moved));
227   EXPECT_EQ(multiply(3, 3), 9);
228 
229 // Ignore use-after-move.
230 #ifndef __clang_analyzer__
231   EXPECT_EQ(moved, nullptr);
232 #endif  // __clang_analyzer__
233 }
234 
TEST(InlineFunction,Move_InlineFunctionToFunction)235 TEST(InlineFunction, Move_InlineFunctionToFunction) {
236   InlineFunction<int(int, int)> moved(Multiply);
237   EXPECT_NE(moved, nullptr);
238   Function<int(int, int)> multiply(std::move(moved));
239   EXPECT_EQ(multiply(3, 3), 9);
240 
241 // Ignore use-after-move.
242 #ifndef __clang_analyzer__
243   EXPECT_EQ(moved, nullptr);
244 #endif  // __clang_analyzer__
245 }
246 
TEST(Function,MoveAssign_Inline)247 TEST(Function, MoveAssign_Inline) {
248   Function<int(int, int)> moved(Multiply);
249   EXPECT_NE(moved, nullptr);
250   Function<int(int, int)> multiply = std::move(moved);
251   EXPECT_EQ(multiply(3, 3), 9);
252 
253 // Ignore use-after-move.
254 #ifndef __clang_analyzer__
255   EXPECT_EQ(moved, nullptr);
256 #endif  // __clang_analyzer__
257 }
258 
TEST(InlineFunction,MoveAssign_InlineFunctionToFunction)259 TEST(InlineFunction, MoveAssign_InlineFunctionToFunction) {
260   InlineFunction<int(int, int)> moved(Multiply);
261   EXPECT_NE(moved, nullptr);
262   Function<int(int, int)> multiply = std::move(moved);
263   EXPECT_EQ(multiply(3, 3), 9);
264 
265 // Ignore use-after-move.
266 #ifndef __clang_analyzer__
267   EXPECT_EQ(moved, nullptr);
268 #endif  // __clang_analyzer__
269 }
270 
TEST(Function,MoveAssign_Callable)271 TEST(Function, MoveAssign_Callable) {
272   Function<int(int, int)> operation = Multiply;
273   EXPECT_EQ(operation(3, 3), 9);
274   operation = [](int a, int b) -> int { return a + b; };
275   EXPECT_EQ(operation(3, 3), 6);
276 }
277 
TEST(InlineFunction,MoveAssign_Callable)278 TEST(InlineFunction, MoveAssign_Callable) {
279   InlineFunction<int(int, int)> operation = Multiply;
280   EXPECT_EQ(operation(3, 3), 9);
281   operation = [](int a, int b) -> int { return a + b; };
282   EXPECT_EQ(operation(3, 3), 6);
283 }
284 
285 class MoveTracker {
286  public:
MoveTracker()287   MoveTracker() : move_count_(0) {}
288 
MoveTracker(MoveTracker && other)289   MoveTracker(MoveTracker&& other) : move_count_(other.move_count_ + 1) {}
290   MoveTracker& operator=(MoveTracker&& other) = default;
291 
operator ()() const292   int operator()() const { return move_count_; }
293 
294  private:
295   int move_count_;
296 };
297 
TEST(Function,Move_CustomObject)298 TEST(Function, Move_CustomObject) {
299   Function<int()> moved((MoveTracker()));
300   EXPECT_EQ(moved(), 1);
301   Function<int()> tracker(std::move(moved));
302   EXPECT_EQ(tracker(), 2);
303 
304 // Ignore use-after-move.
305 #ifndef __clang_analyzer__
306   EXPECT_EQ(moved, nullptr);
307 #endif  // __clang_analyzer__
308 }
309 
TEST(Function,MoveAssign_CustomObject)310 TEST(Function, MoveAssign_CustomObject) {
311   Function<int()> moved((MoveTracker()));
312   EXPECT_EQ(moved(), 1);
313   Function<int()> tracker = std::move(moved);
314   EXPECT_EQ(tracker(), 2);
315 
316 // Ignore use-after-move.
317 #ifndef __clang_analyzer__
318   EXPECT_EQ(moved, nullptr);
319 #endif  // __clang_analyzer__
320 }
321 
TEST(Function,MoveOnlyType)322 TEST(Function, MoveOnlyType) {
323   class MoveOnlyType {
324    public:
325     MoveOnlyType() = default;
326 
327     MoveOnlyType(const MoveOnlyType& other) = delete;
328     MoveOnlyType& operator=(const MoveOnlyType& other) = delete;
329 
330     MoveOnlyType(MoveOnlyType&&) = default;
331     MoveOnlyType& operator=(MoveOnlyType&&) = default;
332 
333     bool ItsWorking() const { return true; }
334   };
335 
336   pw::Function<bool(MoveOnlyType)> function = [](MoveOnlyType value) {
337     return value.ItsWorking();
338   };
339 
340   MoveOnlyType move_only;
341   EXPECT_TRUE(function(std::move(move_only)));
342 }
343 
TEST(Function,CallbackCanOnlyBeCalledOnce)344 TEST(Function, CallbackCanOnlyBeCalledOnce) {
345   Callback<void()> cb([]() {});
346   cb();
347   EXPECT_FALSE(cb);
348   EXPECT_EQ(cb, nullptr);
349 }
350 
TEST(Function,CallbackDestroysTargetAfterBeingCalled)351 TEST(Function, CallbackDestroysTargetAfterBeingCalled) {
352   class MoveOnlyDestructionCounter {
353    public:
354     MoveOnlyDestructionCounter(int* destroyed_count)
355         : destroyed_(destroyed_count) {}
356 
357     MoveOnlyDestructionCounter(const MoveOnlyDestructionCounter& other) =
358         delete;
359     MoveOnlyDestructionCounter& operator=(
360         const MoveOnlyDestructionCounter& other) = delete;
361 
362     MoveOnlyDestructionCounter(MoveOnlyDestructionCounter&& t) {
363       *this = std::move(t);
364     }
365     MoveOnlyDestructionCounter& operator=(MoveOnlyDestructionCounter&& t) {
366       destroyed_ = t.destroyed_;
367       t.destroyed_ = nullptr;
368       return *this;
369     }
370 
371     ~MoveOnlyDestructionCounter() {
372       if (destroyed_) {
373         (*destroyed_)++;
374       }
375     }
376 
377    private:
378     int* destroyed_;
379   };
380 
381   int destroyed_count = 0;
382   MoveOnlyDestructionCounter destruction_counter(&destroyed_count);
383   Callback<void()> cb = [destruction_counter =
384                              std::move(destruction_counter)]() {};
385   EXPECT_EQ(destroyed_count, 0);
386   cb();
387   EXPECT_EQ(destroyed_count, 1);
388 }
389 
390 }  // namespace
391 }  // namespace pw
392 
393 namespace obscure_different_namespace_which_should_never_collide {
394 namespace {
395 
TEST(Function,Null_OperatorEquals_DifferentNamespace)396 TEST(Function, Null_OperatorEquals_DifferentNamespace) {
397   pw::Closure implicit_null;
398   pw::Closure explicit_null(nullptr);
399   pw::Closure assigned_null = nullptr;
400   pw::Closure not_null([]() {});
401 
402   EXPECT_TRUE(implicit_null == nullptr);
403   EXPECT_TRUE(explicit_null == nullptr);
404   EXPECT_TRUE(assigned_null == nullptr);
405   EXPECT_TRUE(not_null != nullptr);
406 
407   EXPECT_FALSE(implicit_null != nullptr);
408   EXPECT_FALSE(explicit_null != nullptr);
409   EXPECT_FALSE(assigned_null != nullptr);
410   EXPECT_FALSE(not_null == nullptr);
411 }
412 
413 }  // namespace
414 }  // namespace obscure_different_namespace_which_should_never_collide
415