1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "gtest/gtest.h"
6
7 #include "CopyOnWrite.h"
8
9 using namespace mozilla;
10 using namespace mozilla::image;
11
12 struct ValueStats {
13 int32_t mCopies = 0;
14 int32_t mFrees = 0;
15 int32_t mCalls = 0;
16 int32_t mConstCalls = 0;
17 int32_t mSerial = 0;
18 };
19
20 struct Value {
21 NS_INLINE_DECL_REFCOUNTING(Value)
22
ValueValue23 explicit Value(ValueStats& aStats)
24 : mStats(aStats), mSerial(mStats.mSerial++) {}
25
ValueValue26 Value(const Value& aOther)
27 : mStats(aOther.mStats), mSerial(mStats.mSerial++) {
28 mStats.mCopies++;
29 }
30
GoValue31 void Go() { mStats.mCalls++; }
GoValue32 void Go() const { mStats.mConstCalls++; }
33
SerialValue34 int32_t Serial() const { return mSerial; }
35
36 protected:
~ValueValue37 ~Value() { mStats.mFrees++; }
38
39 private:
40 ValueStats& mStats;
41 int32_t mSerial;
42 };
43
TEST(ImageCopyOnWrite,Read)44 TEST(ImageCopyOnWrite, Read)
45 {
46 ValueStats stats;
47
48 {
49 CopyOnWrite<Value> cow(new Value(stats));
50
51 EXPECT_EQ(0, stats.mCopies);
52 EXPECT_EQ(0, stats.mFrees);
53 EXPECT_TRUE(cow.CanRead());
54
55 cow.Read([&](const Value* aValue) {
56 EXPECT_EQ(0, stats.mCopies);
57 EXPECT_EQ(0, stats.mFrees);
58 EXPECT_EQ(0, aValue->Serial());
59 EXPECT_TRUE(cow.CanRead());
60 EXPECT_TRUE(cow.CanWrite());
61
62 aValue->Go();
63
64 EXPECT_EQ(0, stats.mCalls);
65 EXPECT_EQ(1, stats.mConstCalls);
66 });
67
68 EXPECT_EQ(0, stats.mCopies);
69 EXPECT_EQ(0, stats.mFrees);
70 EXPECT_EQ(0, stats.mCalls);
71 EXPECT_EQ(1, stats.mConstCalls);
72 }
73
74 EXPECT_EQ(0, stats.mCopies);
75 EXPECT_EQ(1, stats.mFrees);
76 }
77
TEST(ImageCopyOnWrite,RecursiveRead)78 TEST(ImageCopyOnWrite, RecursiveRead)
79 {
80 ValueStats stats;
81
82 {
83 CopyOnWrite<Value> cow(new Value(stats));
84
85 EXPECT_EQ(0, stats.mCopies);
86 EXPECT_EQ(0, stats.mFrees);
87 EXPECT_TRUE(cow.CanRead());
88
89 cow.Read([&](const Value* aValue) {
90 EXPECT_EQ(0, stats.mCopies);
91 EXPECT_EQ(0, stats.mFrees);
92 EXPECT_EQ(0, aValue->Serial());
93 EXPECT_TRUE(cow.CanRead());
94 EXPECT_TRUE(cow.CanWrite());
95
96 // Make sure that Read() inside a Read() succeeds.
97 cow.Read(
98 [&](const Value* aValue) {
99 EXPECT_EQ(0, stats.mCopies);
100 EXPECT_EQ(0, stats.mFrees);
101 EXPECT_EQ(0, aValue->Serial());
102 EXPECT_TRUE(cow.CanRead());
103 EXPECT_TRUE(cow.CanWrite());
104
105 aValue->Go();
106
107 EXPECT_EQ(0, stats.mCalls);
108 EXPECT_EQ(1, stats.mConstCalls);
109 },
110 []() {
111 // This gets called if we can't read. We shouldn't get here.
112 EXPECT_TRUE(false);
113 });
114 });
115
116 EXPECT_EQ(0, stats.mCopies);
117 EXPECT_EQ(0, stats.mFrees);
118 EXPECT_EQ(0, stats.mCalls);
119 EXPECT_EQ(1, stats.mConstCalls);
120 }
121
122 EXPECT_EQ(0, stats.mCopies);
123 EXPECT_EQ(1, stats.mFrees);
124 }
125
TEST(ImageCopyOnWrite,Write)126 TEST(ImageCopyOnWrite, Write)
127 {
128 ValueStats stats;
129
130 {
131 CopyOnWrite<Value> cow(new Value(stats));
132
133 EXPECT_EQ(0, stats.mCopies);
134 EXPECT_EQ(0, stats.mFrees);
135 EXPECT_TRUE(cow.CanRead());
136 EXPECT_TRUE(cow.CanWrite());
137
138 cow.Write([&](Value* aValue) {
139 EXPECT_EQ(0, stats.mCopies);
140 EXPECT_EQ(0, stats.mFrees);
141 EXPECT_EQ(0, aValue->Serial());
142 EXPECT_TRUE(!cow.CanRead());
143 EXPECT_TRUE(!cow.CanWrite());
144
145 aValue->Go();
146
147 EXPECT_EQ(1, stats.mCalls);
148 EXPECT_EQ(0, stats.mConstCalls);
149 });
150
151 EXPECT_EQ(0, stats.mCopies);
152 EXPECT_EQ(0, stats.mFrees);
153 EXPECT_EQ(1, stats.mCalls);
154 EXPECT_EQ(0, stats.mConstCalls);
155 }
156
157 EXPECT_EQ(0, stats.mCopies);
158 EXPECT_EQ(1, stats.mFrees);
159 }
160
TEST(ImageCopyOnWrite,WriteRecursive)161 TEST(ImageCopyOnWrite, WriteRecursive)
162 {
163 ValueStats stats;
164
165 {
166 CopyOnWrite<Value> cow(new Value(stats));
167
168 EXPECT_EQ(0, stats.mCopies);
169 EXPECT_EQ(0, stats.mFrees);
170 EXPECT_TRUE(cow.CanRead());
171 EXPECT_TRUE(cow.CanWrite());
172
173 cow.Read([&](const Value* aValue) {
174 EXPECT_EQ(0, stats.mCopies);
175 EXPECT_EQ(0, stats.mFrees);
176 EXPECT_EQ(0, aValue->Serial());
177 EXPECT_TRUE(cow.CanRead());
178 EXPECT_TRUE(cow.CanWrite());
179
180 // Make sure Write() inside a Read() succeeds.
181 cow.Write(
182 [&](Value* aValue) {
183 EXPECT_EQ(1, stats.mCopies);
184 EXPECT_EQ(0, stats.mFrees);
185 EXPECT_EQ(1, aValue->Serial());
186 EXPECT_TRUE(!cow.CanRead());
187 EXPECT_TRUE(!cow.CanWrite());
188
189 aValue->Go();
190
191 EXPECT_EQ(1, stats.mCalls);
192 EXPECT_EQ(0, stats.mConstCalls);
193
194 // Make sure Read() inside a Write() fails.
195 cow.Read(
196 [](const Value* aValue) {
197 // This gets called if we can read. We shouldn't get here.
198 EXPECT_TRUE(false);
199 },
200 []() {
201 // This gets called if we can't read. We *should* get here.
202 EXPECT_TRUE(true);
203 });
204
205 // Make sure Write() inside a Write() fails.
206 cow.Write(
207 [](Value* aValue) {
208 // This gets called if we can write. We shouldn't get here.
209 EXPECT_TRUE(false);
210 },
211 []() {
212 // This gets called if we can't write. We *should* get here.
213 EXPECT_TRUE(true);
214 });
215 },
216 []() {
217 // This gets called if we can't write. We shouldn't get here.
218 EXPECT_TRUE(false);
219 });
220
221 aValue->Go();
222
223 EXPECT_EQ(1, stats.mCopies);
224 EXPECT_EQ(0, stats.mFrees);
225 EXPECT_EQ(1, stats.mCalls);
226 EXPECT_EQ(1, stats.mConstCalls);
227 });
228
229 EXPECT_EQ(1, stats.mCopies);
230 EXPECT_EQ(1, stats.mFrees);
231 EXPECT_EQ(1, stats.mCalls);
232 EXPECT_EQ(1, stats.mConstCalls);
233 }
234
235 EXPECT_EQ(1, stats.mCopies);
236 EXPECT_EQ(2, stats.mFrees);
237 }
238