TestCopyOnWrite.cpp (5867B)
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 23 explicit Value(ValueStats& aStats) 24 : mStats(aStats), mSerial(mStats.mSerial++) {} 25 26 Value(const Value& aOther) 27 : mStats(aOther.mStats), mSerial(mStats.mSerial++) { 28 mStats.mCopies++; 29 } 30 31 void Go() { mStats.mCalls++; } 32 void Go() const { mStats.mConstCalls++; } 33 34 int32_t Serial() const { return mSerial; } 35 36 protected: 37 ~Value() { mStats.mFrees++; } 38 39 private: 40 ValueStats& mStats; 41 int32_t mSerial; 42 }; 43 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 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 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 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 }