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