1/*
2 * Copyright (C) 2011 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 <wtf/Ref.h>
29#include <wtf/RefCounter.h>
30#include <wtf/text/WTFString.h>
31
32namespace TestWebKitAPI {
33
34static const int IncrementExpected = 0xC0FFEE1;
35static const int DecrementExpected = 0xC0FFEE2;
36static const int CallbackNotExpected = 0xDECAF;
37
38enum TestCounterType { };
39typedef RefCounter<TestCounterType> TestCounter;
40typedef TestCounter::Token TokenType;
41
42TEST(WTF, RefCounter)
43{
44 // RefCounter API is pretty simple, containing the following 4 methods to test:
45 //
46 // 1) RefCounter(std::function<void()>);
47 // 2) ~RefCounter();
48 // 3) Ref<Count> token() const;
49 // 4) unsigned value() const;
50 //
51 // We'll test:
52 // 1) Construction:
53 // 1a) with a callback
54 // 1b) without a callback
55 // 2) Destruction where the RefCounter::Count has:
56 // 2a) a non-zero reference count (Count outlives RefCounter).
57 // 2b) a zero reference count (Count is deleted by RefCounter's destructor).
58 // 3) Call count to ref/deref the Count object, where:
59 // 3a) ref with callback from 0 -> 1.
60 // 3b) ref with callback from 1 -> >1.
61 // 3c) deref with callback from >1 -> 1.
62 // 3d) deref with callback from 1 -> 0.
63 // 3d) deref with callback from 1 -> 0.
64 // 3e) ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
65 // 3f) deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
66 // 3g) deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
67 // 3h) ref without callback
68 // 3i) deref without callback
69 // 3j) ref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
70 // 3k) deref using a Ref rather than a RefPtr (make sure there is no unnecessary reference count churn).
71 // 4) Test the value of the counter:
72 // 4a) at construction.
73 // 4b) as read within the callback.
74 // 4c) as read after the ref/deref.
75
76 // These values will outlive the following block.
77 int callbackValue = CallbackNotExpected;
78 TokenType incTo1Again;
79
80 {
81 // Testing (1a) - Construction with a callback.
82 TestCounter* counterPtr = nullptr;
83 TestCounter counter([&](RefCounterEvent event) {
84 // Check that the callback is called at the expected times, and the correct number of times.
85 if (RefCounterEvent::Increment == event)
86 EXPECT_EQ(callbackValue, IncrementExpected);
87 if (RefCounterEvent::Decrement == event)
88 EXPECT_EQ(callbackValue, DecrementExpected);
89 // return the value of the counter in the callback.
90 callbackValue = counterPtr->value();
91 });
92 counterPtr = &counter;
93 // Testing (4a) - after construction value() is 0.
94 EXPECT_EQ(0, static_cast<int>(counter.value()));
95
96 // Testing (3a) - ref with callback from 0 -> 1.
97 callbackValue = IncrementExpected;
98 TokenType incTo1(counter.count());
99 // Testing (4b) & (4c) - values within & after callback.
100 EXPECT_EQ(1, callbackValue);
101 EXPECT_EQ(1, static_cast<int>(counter.value()));
102
103 // Testing (3b) - ref with callback from 1 -> 2.
104 callbackValue = IncrementExpected;
105 TokenType incTo2(incTo1);
106 // Testing (4b) & (4c) - values within & after callback.
107 EXPECT_EQ(2, callbackValue);
108 EXPECT_EQ(2, static_cast<int>(counter.value()));
109
110 // Testing (3c) - deref with callback from >1 -> 1.
111 callbackValue = DecrementExpected;
112 incTo1 = nullptr;
113 // Testing (4b) & (4c) - values within & after callback.
114 EXPECT_EQ(1, callbackValue);
115 EXPECT_EQ(1, static_cast<int>(counter.value()));
116
117 {
118 // Testing (3j) - ref using a Ref rather than a RefPtr.
119 callbackValue = IncrementExpected;
120 TokenType incTo2Again(counter.count());
121 // Testing (4b) & (4c) - values within & after callback.
122 EXPECT_EQ(2, callbackValue);
123 EXPECT_EQ(2, static_cast<int>(counter.value()));
124 // Testing (3k) - deref using a Ref rather than a RefPtr.
125
126 callbackValue = DecrementExpected;
127 }
128 EXPECT_EQ(1, callbackValue);
129 EXPECT_EQ(1, static_cast<int>(counter.value()));
130 // Testing (4b) & (4c) - values within & after callback.
131
132 // Testing (3d) - deref with callback from 1 -> 0.
133 callbackValue = DecrementExpected;
134 incTo2 = nullptr;
135 // Testing (4b) & (4c) - values within & after callback.
136 EXPECT_EQ(0, callbackValue);
137 EXPECT_EQ(0, static_cast<int>(counter.value()));
138
139 // Testing (2a) - Destruction where the TestCounter::Count has a non-zero reference count.
140 callbackValue = IncrementExpected;
141 incTo1Again = counter.count();
142 EXPECT_EQ(1, callbackValue);
143 EXPECT_EQ(1, static_cast<int>(counter.value()));
144 callbackValue = CallbackNotExpected;
145 }
146
147 // Testing (3e) - ref with callback from 1 -> >1 AFTER RefCounter has been destroyed.
148 TokenType incTo2Again = incTo1Again;
149 // Testing (3f) - deref with callback from >1 -> 1 AFTER RefCounter has been destroyed.
150 incTo1Again = nullptr;
151 // Testing (3g) - deref with callback from 1 -> 0 AFTER RefCounter has been destroyed.
152 incTo2Again = nullptr;
153
154 // Testing (1b) - Construction without a callback.
155 TestCounter counter;
156 // Testing (4a) - after construction value() is 0.
157 EXPECT_EQ(0, static_cast<int>(counter.value()));
158 // Testing (3h) - ref without callback
159 TokenType incTo1(counter.count());
160 // Testing (4c) - value as read after the ref.
161 EXPECT_EQ(1, static_cast<int>(counter.value()));
162 // Testing (3i) - deref without callback
163 incTo1 = nullptr;
164 // Testing (4c) - value as read after the deref.
165 EXPECT_EQ(0, static_cast<int>(counter.value()));
166 // Testing (2b) - Destruction where the RefCounter::Count has a zero reference count.
167 // ... not a lot to test here! - we can at least ensure this code path is run & we don't crash!
168}
169
170TEST(WTF, RefCounterDeleteCounterWithOutstandingTokens)
171{
172 {
173 std::unique_ptr<TestCounter> counter = std::make_unique<TestCounter>([&](RefCounterEvent event) {
174 if (!counter->value())
175 counter = nullptr;
176 });
177
178 TokenType incTo1 = counter->count();
179 EXPECT_EQ(1UL, counter->value());
180 incTo1 = nullptr;
181 EXPECT_EQ(nullptr, counter.get());
182 }
183}
184
185} // namespace TestWebKitAPI
186