1/*
2 * Copyright (C) 2013-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 "RefLogger.h"
29#include <wtf/RefPtr.h>
30
31namespace TestWebKitAPI {
32
33TEST(WTF_Ref, Basic)
34{
35 DerivedRefLogger a("a");
36
37 {
38 Ref<RefLogger> ref(a);
39 EXPECT_EQ(&a, ref.ptr());
40 EXPECT_EQ(&a.name, &ref->name);
41 }
42 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
43
44 {
45 Ref<RefLogger> ref(adoptRef(a));
46 EXPECT_EQ(&a, ref.ptr());
47 EXPECT_EQ(&a.name, &ref->name);
48 }
49 EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
50}
51
52TEST(WTF_Ref, Assignment)
53{
54 DerivedRefLogger a("a");
55 RefLogger b("b");
56 DerivedRefLogger c("c");
57
58 {
59 Ref<RefLogger> ref(a);
60 EXPECT_EQ(&a, ref.ptr());
61 log() << "| ";
62 ref = b;
63 EXPECT_EQ(&b, ref.ptr());
64 log() << "| ";
65 }
66 EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
67
68 {
69 Ref<RefLogger> ref(a);
70 EXPECT_EQ(&a, ref.ptr());
71 log() << "| ";
72 ref = c;
73 EXPECT_EQ(&c, ref.ptr());
74 log() << "| ";
75 }
76 EXPECT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
77
78 {
79 Ref<RefLogger> ref(a);
80 EXPECT_EQ(&a, ref.ptr());
81 log() << "| ";
82 ref = adoptRef(b);
83 EXPECT_EQ(&b, ref.ptr());
84 log() << "| ";
85 }
86 EXPECT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
87
88 {
89 Ref<RefLogger> ref(a);
90 EXPECT_EQ(&a, ref.ptr());
91 log() << "| ";
92 ref = adoptRef(c);
93 EXPECT_EQ(&c, ref.ptr());
94 log() << "| ";
95 }
96 EXPECT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
97}
98
99static Ref<RefLogger> passWithRef(Ref<RefLogger>&& reference)
100{
101 return WTFMove(reference);
102}
103
104TEST(WTF_Ref, ReturnValue)
105{
106 DerivedRefLogger a("a");
107 RefLogger b("b");
108 DerivedRefLogger c("c");
109
110 {
111 Ref<RefLogger> ref(passWithRef(Ref<RefLogger>(a)));
112 EXPECT_EQ(&a, ref.ptr());
113 }
114 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
115
116 {
117 Ref<RefLogger> ref(a);
118 EXPECT_EQ(&a, ref.ptr());
119 log() << "| ";
120 ref = passWithRef(b);
121 EXPECT_EQ(&b, ref.ptr());
122 log() << "| ";
123 }
124 EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
125
126 {
127 RefPtr<RefLogger> ptr(passWithRef(a));
128 EXPECT_EQ(&a, ptr.get());
129 }
130 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
131
132 {
133 RefPtr<DerivedRefLogger> ptr(&a);
134 RefPtr<RefLogger> ptr2(WTFMove(ptr));
135 EXPECT_EQ(nullptr, ptr.get());
136 EXPECT_EQ(&a, ptr2.get());
137 }
138 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
139
140 {
141 Ref<DerivedRefLogger> derivedReference(a);
142 Ref<RefLogger> baseReference(passWithRef(derivedReference.copyRef()));
143 EXPECT_EQ(&a, derivedReference.ptr());
144 EXPECT_EQ(&a, baseReference.ptr());
145 }
146 EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
147}
148
149TEST(WTF_Ref, Swap)
150{
151 RefLogger a("a");
152 RefLogger b("b");
153
154 {
155 Ref<RefLogger> p1(a);
156 Ref<RefLogger> p2(b);
157 log() << "| ";
158 EXPECT_EQ(&a, p1.ptr());
159 EXPECT_EQ(&b, p2.ptr());
160 p1.swap(p2);
161 EXPECT_EQ(&b, p1.ptr());
162 EXPECT_EQ(&a, p2.ptr());
163 log() << "| ";
164 }
165 EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
166
167 {
168 Ref<RefLogger> p1(a);
169 Ref<RefLogger> p2(b);
170 log() << "| ";
171 EXPECT_EQ(&a, p1.ptr());
172 EXPECT_EQ(&b, p2.ptr());
173 std::swap(p1, p2);
174 EXPECT_EQ(&b, p1.ptr());
175 EXPECT_EQ(&a, p2.ptr());
176 log() << "| ";
177 }
178 EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
179}
180
181struct RefCheckingRefLogger : RefLogger {
182 RefCheckingRefLogger(const char* name);
183 void ref();
184 void deref();
185 const Ref<RefCheckingRefLogger>* slotToCheck { nullptr };
186};
187
188struct DerivedRefCheckingRefLogger : RefCheckingRefLogger {
189 DerivedRefCheckingRefLogger(const char* name);
190};
191
192RefCheckingRefLogger::RefCheckingRefLogger(const char* name)
193 : RefLogger { name }
194{
195}
196
197void RefCheckingRefLogger::ref()
198{
199 if (slotToCheck)
200 log() << "slot=" << slotToCheck->get().name << " ";
201 RefLogger::ref();
202}
203
204void RefCheckingRefLogger::deref()
205{
206 if (slotToCheck)
207 log() << "slot=" << slotToCheck->get().name << " ";
208 RefLogger::deref();
209}
210
211DerivedRefCheckingRefLogger::DerivedRefCheckingRefLogger(const char* name)
212 : RefCheckingRefLogger { name }
213{
214}
215
216TEST(WTF_Ref, AssignBeforeDeref)
217{
218 DerivedRefCheckingRefLogger a("a");
219 RefCheckingRefLogger b("b");
220 DerivedRefCheckingRefLogger c("c");
221
222 {
223 Ref<RefCheckingRefLogger> ref(a);
224 EXPECT_EQ(&a, ref.ptr());
225 log() << "| ";
226 a.slotToCheck = &ref;
227 b.slotToCheck = &ref;
228 ref = b;
229 a.slotToCheck = nullptr;
230 b.slotToCheck = nullptr;
231 EXPECT_EQ(&b, ref.ptr());
232 log() << "| ";
233 }
234 EXPECT_STREQ("ref(a) | slot=a ref(b) slot=b deref(a) | deref(b) ", takeLogStr().c_str());
235
236 {
237 Ref<RefCheckingRefLogger> ref(a);
238 EXPECT_EQ(&a, ref.ptr());
239 log() << "| ";
240 a.slotToCheck = &ref;
241 c.slotToCheck = &ref;
242 ref = c;
243 a.slotToCheck = nullptr;
244 c.slotToCheck = nullptr;
245 EXPECT_EQ(&c, ref.ptr());
246 log() << "| ";
247 }
248 EXPECT_STREQ("ref(a) | slot=a ref(c) slot=c deref(a) | deref(c) ", takeLogStr().c_str());
249
250 {
251 Ref<RefCheckingRefLogger> ref(a);
252 EXPECT_EQ(&a, ref.ptr());
253 log() << "| ";
254 a.slotToCheck = &ref;
255 ref = adoptRef(b);
256 a.slotToCheck = nullptr;
257 EXPECT_EQ(&b, ref.ptr());
258 log() << "| ";
259 }
260 EXPECT_STREQ("ref(a) | slot=b deref(a) | deref(b) ", takeLogStr().c_str());
261
262 {
263 Ref<RefCheckingRefLogger> ref(a);
264 EXPECT_EQ(&a, ref.ptr());
265 log() << "| ";
266 a.slotToCheck = &ref;
267 ref = adoptRef(c);
268 a.slotToCheck = nullptr;
269 EXPECT_EQ(&c, ref.ptr());
270 log() << "| ";
271 }
272 EXPECT_STREQ("ref(a) | slot=c deref(a) | deref(c) ", takeLogStr().c_str());
273}
274
275} // namespace TestWebKitAPI
276