• 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_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