blob: 9fc01d33570438db0e1f2da39416f4718625159d [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 Heplerf5cdd932021-06-14 13:53:23 -070023// Ensure that Function can be constant initialized.
24[[maybe_unused]] PW_CONSTINIT Function<void()> can_be_constant_initialized;
25
Alexei Frolov99de52d2021-05-11 19:58:01 -070026int Multiply(int a, int b) { return a * b; }
27
28TEST(Function, OperatorCall) {
29 Function<int(int, int)> multiply(Multiply);
30 EXPECT_EQ(multiply(3, 7), 21);
31}
32
33void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
34 callback(a + b);
35}
36
37int add_result = -1;
38
39void free_add_callback(int sum) { add_result = sum; }
40
41TEST(Function, ConstructInPlace_FreeFunction) {
42 add_result = -1;
43 CallbackAdd(25, 17, free_add_callback);
44 EXPECT_EQ(add_result, 42);
45}
46
47TEST(Function, ConstructInPlace_NonCapturingLambda) {
48 add_result = -1;
49 CallbackAdd(25, 18, [](int sum) { add_result = sum; });
50 EXPECT_EQ(add_result, 43);
51}
52
53TEST(Function, ConstructInPlace_CapturingLambda) {
54 int result = -1;
55 CallbackAdd(25, 19, [&](int sum) { result = sum; });
56 EXPECT_EQ(result, 44);
57}
58
59class CallableObject {
60 public:
61 CallableObject(int* result) : result_(result) {}
62
63 CallableObject(CallableObject&& other) = default;
64 CallableObject& operator=(CallableObject&& other) = default;
65
66 void operator()(int sum) { *result_ = sum; }
67
68 private:
69 int* result_;
70};
71
72TEST(Function, ConstructInPlace_CallableObject) {
73 int result = -1;
74 CallbackAdd(25, 20, CallableObject(&result));
75 EXPECT_EQ(result, 45);
76}
77
78class MemberFunctionTest : public ::testing::Test {
79 protected:
80 MemberFunctionTest() : result_(-1) {}
81
82 void set_result(int result) { result_ = result; }
83
84 int result_;
85};
86
87TEST_F(MemberFunctionTest, ConstructInPlace_Lambda) {
88 CallbackAdd(25, 21, [this](int sum) { set_result(sum); });
89 EXPECT_EQ(result_, 46);
90}
91
92TEST(Function, Null_OperatorBool) {
93 Closure implicit_null;
94 Closure explicit_null(nullptr);
95 Closure assigned_null = nullptr;
96 Closure not_null([]() {});
97
98 EXPECT_FALSE(bool(implicit_null));
99 EXPECT_FALSE(bool(explicit_null));
100 EXPECT_FALSE(bool(assigned_null));
101 EXPECT_TRUE(bool(not_null));
102
103 EXPECT_TRUE(!implicit_null);
104 EXPECT_TRUE(!explicit_null);
105 EXPECT_TRUE(!assigned_null);
106 EXPECT_FALSE(!not_null);
107}
108
109TEST(Function, Null_OperatorEquals) {
110 Closure implicit_null;
111 Closure explicit_null(nullptr);
112 Closure assigned_null = nullptr;
113 Closure not_null([]() {});
114
115 EXPECT_TRUE(implicit_null == nullptr);
116 EXPECT_TRUE(explicit_null == nullptr);
117 EXPECT_TRUE(assigned_null == nullptr);
118 EXPECT_TRUE(not_null != nullptr);
119
120 EXPECT_FALSE(implicit_null != nullptr);
121 EXPECT_FALSE(explicit_null != nullptr);
122 EXPECT_FALSE(assigned_null != nullptr);
123 EXPECT_FALSE(not_null == nullptr);
124}
125
126TEST(Function, Null_Set) {
127 Closure function = []() {};
128 EXPECT_NE(function, nullptr);
129 function = nullptr;
130 EXPECT_EQ(function, nullptr);
131}
132
133void DoNothing() {}
134
135TEST(Function, Null_FunctionPointer) {
136 void (*ptr)() = DoNothing;
137 Closure not_null(ptr);
138 EXPECT_NE(not_null, nullptr);
139 ptr = nullptr;
140 Closure is_null(ptr);
141 EXPECT_EQ(is_null, nullptr);
142}
143
144TEST(Function, Move_Null) {
145 Closure moved;
146 EXPECT_EQ(moved, nullptr);
147 Closure function(std::move(moved));
148 EXPECT_EQ(function, nullptr);
149
150// Ignore use-after-move.
151#ifndef __clang_analyzer__
152 EXPECT_EQ(moved, nullptr);
153#endif // __clang_analyzer__
154}
155
156TEST(Function, MoveAssign_Null) {
157 Closure moved;
158 EXPECT_EQ(moved, nullptr);
159 Closure function = std::move(moved);
160 EXPECT_EQ(function, nullptr);
161
162// Ignore use-after-move.
163#ifndef __clang_analyzer__
164 EXPECT_EQ(moved, nullptr);
165#endif // __clang_analyzer__
166}
167
168TEST(Function, Move_Inline) {
169 Function<int(int, int)> moved(Multiply);
170 EXPECT_NE(moved, nullptr);
171 Function<int(int, int)> multiply(std::move(moved));
172 EXPECT_EQ(multiply(3, 3), 9);
173
174// Ignore use-after-move.
175#ifndef __clang_analyzer__
176 EXPECT_EQ(moved, nullptr);
177#endif // __clang_analyzer__
178}
179
180TEST(Function, MoveAssign_Inline) {
181 Function<int(int, int)> moved(Multiply);
182 EXPECT_NE(moved, nullptr);
183 Function<int(int, int)> multiply = std::move(moved);
184 EXPECT_EQ(multiply(3, 3), 9);
185
186// Ignore use-after-move.
187#ifndef __clang_analyzer__
188 EXPECT_EQ(moved, nullptr);
189#endif // __clang_analyzer__
190}
191
192class MoveTracker {
193 public:
194 MoveTracker() : move_count_(0) {}
195
196 MoveTracker(MoveTracker&& other) : move_count_(other.move_count_ + 1) {}
197 MoveTracker& operator=(MoveTracker&& other) = default;
198
199 int operator()() const { return move_count_; }
200
201 private:
202 int move_count_;
203};
204
205TEST(Function, Move_CustomObject) {
206 Function<int()> moved((MoveTracker()));
207 EXPECT_EQ(moved(), 2); // internally moves twice on construction
208 Function<int()> tracker(std::move(moved));
209 EXPECT_EQ(tracker(), 3);
210
211// Ignore use-after-move.
212#ifndef __clang_analyzer__
213 EXPECT_EQ(moved, nullptr);
214#endif // __clang_analyzer__
215}
216
217TEST(Function, MoveAssign_CustomObject) {
218 Function<int()> moved((MoveTracker()));
219 EXPECT_EQ(moved(), 2); // internally moves twice on construction
220 Function<int()> tracker = std::move(moved);
221 EXPECT_EQ(tracker(), 3);
222
223// Ignore use-after-move.
224#ifndef __clang_analyzer__
225 EXPECT_EQ(moved, nullptr);
226#endif // __clang_analyzer__
227}
228
229} // namespace
230} // namespace pw
Ewout van Bekkumc4a786a2021-07-27 17:05:12 -0700231
232namespace obscure_different_namespace_which_should_never_collide {
233namespace {
234
235TEST(Function, Null_OperatorEquals_DifferentNamespace) {
236 pw::Closure implicit_null;
237 pw::Closure explicit_null(nullptr);
238 pw::Closure assigned_null = nullptr;
239 pw::Closure not_null([]() {});
240
241 EXPECT_TRUE(implicit_null == nullptr);
242 EXPECT_TRUE(explicit_null == nullptr);
243 EXPECT_TRUE(assigned_null == nullptr);
244 EXPECT_TRUE(not_null != nullptr);
245
246 EXPECT_FALSE(implicit_null != nullptr);
247 EXPECT_FALSE(explicit_null != nullptr);
248 EXPECT_FALSE(assigned_null != nullptr);
249 EXPECT_FALSE(not_null == nullptr);
250}
251
252} // namespace
253} // namespace obscure_different_namespace_which_should_never_collide