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