1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "MoveOnly.h"
29#include <wtf/Function.h>
30
31namespace TestWebKitAPI {
32
33static WTF::Function<int()> function_for_reentrancy_test;
34static unsigned testObjectDestructorCalls = 0;
35
36enum class AssignmentMode { Null, Lambda, None };
37
38class TestObject {
39public:
40 TestObject(AssignmentMode);
41 TestObject(TestObject&&);
42
43 ~TestObject();
44 int operator()();
45
46 TestObject(const TestObject&) = delete;
47 TestObject& operator=(const TestObject&) = delete;
48
49private:
50 AssignmentMode m_assignmentMode;
51};
52
53TestObject::TestObject(AssignmentMode assignmentMode)
54 : m_assignmentMode(assignmentMode)
55{
56}
57
58TestObject::TestObject(TestObject&& other)
59{
60 m_assignmentMode = std::exchange(other.m_assignmentMode, AssignmentMode::None);
61}
62
63TestObject::~TestObject()
64{
65 if (m_assignmentMode == AssignmentMode::None)
66 return;
67
68 ++testObjectDestructorCalls;
69 if (m_assignmentMode == AssignmentMode::Null)
70 function_for_reentrancy_test = nullptr;
71 else
72 function_for_reentrancy_test = [] { return -1; };
73}
74
75int TestObject::operator()()
76{
77 return 0;
78}
79
80TEST(WTF_Function, assignNullReEntersAssignNull)
81{
82 function_for_reentrancy_test = nullptr;
83 testObjectDestructorCalls = 0;
84
85 function_for_reentrancy_test = TestObject(AssignmentMode::Null);
86 EXPECT_EQ(0, function_for_reentrancy_test());
87 EXPECT_FALSE(!function_for_reentrancy_test);
88 EXPECT_EQ(0U, testObjectDestructorCalls);
89 function_for_reentrancy_test = nullptr;
90 EXPECT_EQ(1U, testObjectDestructorCalls);
91 EXPECT_TRUE(!function_for_reentrancy_test);
92}
93
94TEST(WTF_Function, assignLamdbaReEntersAssignNull)
95{
96 function_for_reentrancy_test = nullptr;
97 testObjectDestructorCalls = 0;
98
99 function_for_reentrancy_test = TestObject(AssignmentMode::Null);
100 EXPECT_EQ(0, function_for_reentrancy_test());
101 EXPECT_FALSE(!function_for_reentrancy_test);
102 EXPECT_EQ(0U, testObjectDestructorCalls);
103 function_for_reentrancy_test = [] { return 3; };
104 EXPECT_EQ(1U, testObjectDestructorCalls);
105 EXPECT_TRUE(!function_for_reentrancy_test);
106}
107
108TEST(WTF_Function, assignLamdbaReEntersAssignLamdba)
109{
110 function_for_reentrancy_test = nullptr;
111 testObjectDestructorCalls = 0;
112
113 function_for_reentrancy_test = TestObject(AssignmentMode::Lambda);
114 EXPECT_EQ(0, function_for_reentrancy_test());
115 EXPECT_FALSE(!function_for_reentrancy_test);
116 EXPECT_EQ(0, function_for_reentrancy_test());
117 EXPECT_EQ(0U, testObjectDestructorCalls);
118 function_for_reentrancy_test = [] { return 3; };
119 EXPECT_EQ(1U, testObjectDestructorCalls);
120 EXPECT_FALSE(!function_for_reentrancy_test);
121 EXPECT_EQ(-1, function_for_reentrancy_test());
122}
123
124TEST(WTF_Function, assignNullReEntersAssignLamda)
125{
126 function_for_reentrancy_test = nullptr;
127 testObjectDestructorCalls = 0;
128
129 function_for_reentrancy_test = TestObject(AssignmentMode::Lambda);
130 EXPECT_EQ(0, function_for_reentrancy_test());
131 EXPECT_FALSE(!function_for_reentrancy_test);
132 EXPECT_EQ(0, function_for_reentrancy_test());
133 EXPECT_EQ(0U, testObjectDestructorCalls);
134 function_for_reentrancy_test = nullptr;
135 EXPECT_EQ(1U, testObjectDestructorCalls);
136 EXPECT_FALSE(!function_for_reentrancy_test);
137 EXPECT_EQ(-1, function_for_reentrancy_test());
138}
139
140TEST(WTF_Function, Basics)
141{
142 Function<unsigned()> a;
143 EXPECT_FALSE(static_cast<bool>(a));
144
145 a = [] {
146 return 1U;
147 };
148 EXPECT_TRUE(static_cast<bool>(a));
149 EXPECT_EQ(1U, a());
150
151 a = nullptr;
152 EXPECT_FALSE(static_cast<bool>(a));
153
154 a = MoveOnly { 2 };
155 EXPECT_TRUE(static_cast<bool>(a));
156 EXPECT_EQ(2U, a());
157
158 Function<unsigned()> b = WTFMove(a);
159 EXPECT_TRUE(static_cast<bool>(b));
160 EXPECT_EQ(2U, b());
161 EXPECT_FALSE(static_cast<bool>(a));
162
163 a = MoveOnly { 3 };
164 Function<unsigned()> c = WTFMove(a);
165 EXPECT_TRUE(static_cast<bool>(c));
166 EXPECT_EQ(3U, c());
167 EXPECT_FALSE(static_cast<bool>(a));
168
169 b = WTFMove(c);
170 EXPECT_TRUE(static_cast<bool>(b));
171 EXPECT_EQ(3U, b());
172 EXPECT_FALSE(static_cast<bool>(c));
173}
174
175struct FunctionDestructionChecker {
176 FunctionDestructionChecker(Function<unsigned()>& function)
177 : function { function }
178 {
179 }
180
181 ~FunctionDestructionChecker()
182 {
183 functionAsBool = static_cast<bool>(function);
184 functionResult = function();
185 }
186
187 unsigned operator()() const
188 {
189 return 10;
190 }
191
192 Function<unsigned()>& function;
193 static Optional<bool> functionAsBool;
194 static Optional<unsigned> functionResult;
195};
196
197Optional<bool> FunctionDestructionChecker::functionAsBool;
198Optional<unsigned> FunctionDestructionChecker::functionResult;
199
200TEST(WTF_Function, AssignBeforeDestroy)
201{
202 Function<unsigned()> a;
203
204 a = FunctionDestructionChecker(a);
205 a = [] {
206 return 1U;
207 };
208 EXPECT_TRUE(static_cast<bool>(FunctionDestructionChecker::functionAsBool));
209 EXPECT_TRUE(static_cast<bool>(FunctionDestructionChecker::functionResult));
210 EXPECT_TRUE(FunctionDestructionChecker::functionAsBool.value());
211 EXPECT_EQ(1U, FunctionDestructionChecker::functionResult.value());
212 FunctionDestructionChecker::functionAsBool = WTF::nullopt;
213 FunctionDestructionChecker::functionResult = WTF::nullopt;
214
215 a = FunctionDestructionChecker(a);
216 a = MoveOnly { 2 };
217 EXPECT_TRUE(static_cast<bool>(FunctionDestructionChecker::functionAsBool));
218 EXPECT_TRUE(static_cast<bool>(FunctionDestructionChecker::functionResult));
219 EXPECT_TRUE(FunctionDestructionChecker::functionAsBool.value());
220 EXPECT_EQ(2U, FunctionDestructionChecker::functionResult.value());
221 FunctionDestructionChecker::functionAsBool = WTF::nullopt;
222 FunctionDestructionChecker::functionResult = WTF::nullopt;
223}
224
225static int returnThree()
226{
227 return 3;
228}
229
230static int returnFour()
231{
232 return 4;
233}
234
235static int returnPassedValue(int value)
236{
237 return value;
238}
239
240TEST(WTF_Function, AssignFunctionPointer)
241{
242 Function<int()> f1 = returnThree;
243 EXPECT_TRUE(static_cast<bool>(f1));
244 EXPECT_EQ(3, f1());
245
246 f1 = returnFour;
247 EXPECT_TRUE(static_cast<bool>(f1));
248 EXPECT_EQ(4, f1());
249
250 f1 = nullptr;
251 EXPECT_FALSE(static_cast<bool>(f1));
252
253 Function<int(int)> f2 = returnPassedValue;
254 EXPECT_TRUE(static_cast<bool>(f2));
255 EXPECT_EQ(3, f2(3));
256 EXPECT_EQ(-3, f2(-3));
257
258 f2 = nullptr;
259 EXPECT_FALSE(static_cast<bool>(f2));
260}
261
262} // namespace TestWebKitAPI
263