1 // Copyright 2018 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <gtest/gtest.h> 16 17 #include "common/RefCounted.h" 18 #include "common/Result.h" 19 20 namespace { 21 22 template <typename T, typename E> TestError(Result<T,E> * result,E expectedError)23 void TestError(Result<T, E>* result, E expectedError) { 24 EXPECT_TRUE(result->IsError()); 25 EXPECT_FALSE(result->IsSuccess()); 26 27 std::unique_ptr<E> storedError = result->AcquireError(); 28 EXPECT_EQ(*storedError, expectedError); 29 } 30 31 template <typename T, typename E> TestSuccess(Result<T,E> * result,T expectedSuccess)32 void TestSuccess(Result<T, E>* result, T expectedSuccess) { 33 EXPECT_FALSE(result->IsError()); 34 EXPECT_TRUE(result->IsSuccess()); 35 36 const T storedSuccess = result->AcquireSuccess(); 37 EXPECT_EQ(storedSuccess, expectedSuccess); 38 39 // Once the success is acquired, result has an empty 40 // payload and is neither in the success nor error state. 41 EXPECT_FALSE(result->IsError()); 42 EXPECT_FALSE(result->IsSuccess()); 43 } 44 45 static int dummyError = 0xbeef; 46 static float dummySuccess = 42.0f; 47 static const float dummyConstSuccess = 42.0f; 48 49 class AClass : public RefCounted { 50 public: 51 int a = 0; 52 }; 53 54 // Tests using the following overload of TestSuccess make 55 // local Ref instances to dummySuccessObj. Tests should 56 // ensure any local Ref objects made along the way continue 57 // to point to dummySuccessObj. 58 template <typename T, typename E> TestSuccess(Result<Ref<T>,E> * result,T * expectedSuccess)59 void TestSuccess(Result<Ref<T>, E>* result, T* expectedSuccess) { 60 EXPECT_FALSE(result->IsError()); 61 EXPECT_TRUE(result->IsSuccess()); 62 63 // AClass starts with a reference count of 1 and stored 64 // on the stack in the caller. The result parameter should 65 // hold the only other reference to the object. 66 EXPECT_EQ(expectedSuccess->GetRefCountForTesting(), 2u); 67 68 const Ref<T> storedSuccess = result->AcquireSuccess(); 69 EXPECT_EQ(storedSuccess.Get(), expectedSuccess); 70 71 // Once the success is acquired, result has an empty 72 // payload and is neither in the success nor error state. 73 EXPECT_FALSE(result->IsError()); 74 EXPECT_FALSE(result->IsSuccess()); 75 76 // Once we call AcquireSuccess, result no longer stores 77 // the object. storedSuccess should contain the only other 78 // reference to the object. 79 EXPECT_EQ(storedSuccess->GetRefCountForTesting(), 2u); 80 } 81 82 // Result<void, E*> 83 84 // Test constructing an error Result<void, E> TEST(ResultOnlyPointerError,ConstructingError)85 TEST(ResultOnlyPointerError, ConstructingError) { 86 Result<void, int> result(std::make_unique<int>(dummyError)); 87 TestError(&result, dummyError); 88 } 89 90 // Test moving an error Result<void, E> TEST(ResultOnlyPointerError,MovingError)91 TEST(ResultOnlyPointerError, MovingError) { 92 Result<void, int> result(std::make_unique<int>(dummyError)); 93 Result<void, int> movedResult(std::move(result)); 94 TestError(&movedResult, dummyError); 95 } 96 97 // Test returning an error Result<void, E> TEST(ResultOnlyPointerError,ReturningError)98 TEST(ResultOnlyPointerError, ReturningError) { 99 auto CreateError = []() -> Result<void, int> { 100 return {std::make_unique<int>(dummyError)}; 101 }; 102 103 Result<void, int> result = CreateError(); 104 TestError(&result, dummyError); 105 } 106 107 // Test constructing a success Result<void, E> TEST(ResultOnlyPointerError,ConstructingSuccess)108 TEST(ResultOnlyPointerError, ConstructingSuccess) { 109 Result<void, int> result; 110 EXPECT_TRUE(result.IsSuccess()); 111 EXPECT_FALSE(result.IsError()); 112 } 113 114 // Test moving a success Result<void, E> TEST(ResultOnlyPointerError,MovingSuccess)115 TEST(ResultOnlyPointerError, MovingSuccess) { 116 Result<void, int> result; 117 Result<void, int> movedResult(std::move(result)); 118 EXPECT_TRUE(movedResult.IsSuccess()); 119 EXPECT_FALSE(movedResult.IsError()); 120 } 121 122 // Test returning a success Result<void, E> TEST(ResultOnlyPointerError,ReturningSuccess)123 TEST(ResultOnlyPointerError, ReturningSuccess) { 124 auto CreateError = []() -> Result<void, int> { return {}; }; 125 126 Result<void, int> result = CreateError(); 127 EXPECT_TRUE(result.IsSuccess()); 128 EXPECT_FALSE(result.IsError()); 129 } 130 131 // Result<T*, E*> 132 133 // Test constructing an error Result<T*, E> TEST(ResultBothPointer,ConstructingError)134 TEST(ResultBothPointer, ConstructingError) { 135 Result<float*, int> result(std::make_unique<int>(dummyError)); 136 TestError(&result, dummyError); 137 } 138 139 // Test moving an error Result<T*, E> TEST(ResultBothPointer,MovingError)140 TEST(ResultBothPointer, MovingError) { 141 Result<float*, int> result(std::make_unique<int>(dummyError)); 142 Result<float*, int> movedResult(std::move(result)); 143 TestError(&movedResult, dummyError); 144 } 145 146 // Test returning an error Result<T*, E> TEST(ResultBothPointer,ReturningError)147 TEST(ResultBothPointer, ReturningError) { 148 auto CreateError = []() -> Result<float*, int> { 149 return {std::make_unique<int>(dummyError)}; 150 }; 151 152 Result<float*, int> result = CreateError(); 153 TestError(&result, dummyError); 154 } 155 156 // Test constructing a success Result<T*, E> TEST(ResultBothPointer,ConstructingSuccess)157 TEST(ResultBothPointer, ConstructingSuccess) { 158 Result<float*, int> result(&dummySuccess); 159 TestSuccess(&result, &dummySuccess); 160 } 161 162 // Test moving a success Result<T*, E> TEST(ResultBothPointer,MovingSuccess)163 TEST(ResultBothPointer, MovingSuccess) { 164 Result<float*, int> result(&dummySuccess); 165 Result<float*, int> movedResult(std::move(result)); 166 TestSuccess(&movedResult, &dummySuccess); 167 } 168 169 // Test returning a success Result<T*, E> TEST(ResultBothPointer,ReturningSuccess)170 TEST(ResultBothPointer, ReturningSuccess) { 171 auto CreateSuccess = []() -> Result<float*, int*> { return {&dummySuccess}; }; 172 173 Result<float*, int*> result = CreateSuccess(); 174 TestSuccess(&result, &dummySuccess); 175 } 176 177 // Tests converting from a Result<TChild*, E> TEST(ResultBothPointer,ConversionFromChildClass)178 TEST(ResultBothPointer, ConversionFromChildClass) { 179 struct T { 180 int a; 181 }; 182 struct TChild : T {}; 183 184 TChild child; 185 T* childAsT = &child; 186 { 187 Result<T*, int> result(&child); 188 TestSuccess(&result, childAsT); 189 } 190 { 191 Result<TChild*, int> resultChild(&child); 192 Result<T*, int> result(std::move(resultChild)); 193 TestSuccess(&result, childAsT); 194 } 195 { 196 Result<TChild*, int> resultChild(&child); 197 Result<T*, int> result = std::move(resultChild); 198 TestSuccess(&result, childAsT); 199 } 200 } 201 202 // Result<const T*, E> 203 204 // Test constructing an error Result<const T*, E> TEST(ResultBothPointerWithConstResult,ConstructingError)205 TEST(ResultBothPointerWithConstResult, ConstructingError) { 206 Result<const float*, int> result(std::make_unique<int>(dummyError)); 207 TestError(&result, dummyError); 208 } 209 210 // Test moving an error Result<const T*, E> TEST(ResultBothPointerWithConstResult,MovingError)211 TEST(ResultBothPointerWithConstResult, MovingError) { 212 Result<const float*, int> result(std::make_unique<int>(dummyError)); 213 Result<const float*, int> movedResult(std::move(result)); 214 TestError(&movedResult, dummyError); 215 } 216 217 // Test returning an error Result<const T*, E*> TEST(ResultBothPointerWithConstResult,ReturningError)218 TEST(ResultBothPointerWithConstResult, ReturningError) { 219 auto CreateError = []() -> Result<const float*, int> { 220 return {std::make_unique<int>(dummyError)}; 221 }; 222 223 Result<const float*, int> result = CreateError(); 224 TestError(&result, dummyError); 225 } 226 227 // Test constructing a success Result<const T*, E*> TEST(ResultBothPointerWithConstResult,ConstructingSuccess)228 TEST(ResultBothPointerWithConstResult, ConstructingSuccess) { 229 Result<const float*, int> result(&dummyConstSuccess); 230 TestSuccess(&result, &dummyConstSuccess); 231 } 232 233 // Test moving a success Result<const T*, E*> TEST(ResultBothPointerWithConstResult,MovingSuccess)234 TEST(ResultBothPointerWithConstResult, MovingSuccess) { 235 Result<const float*, int> result(&dummyConstSuccess); 236 Result<const float*, int> movedResult(std::move(result)); 237 TestSuccess(&movedResult, &dummyConstSuccess); 238 } 239 240 // Test returning a success Result<const T*, E*> TEST(ResultBothPointerWithConstResult,ReturningSuccess)241 TEST(ResultBothPointerWithConstResult, ReturningSuccess) { 242 auto CreateSuccess = []() -> Result<const float*, int> { return {&dummyConstSuccess}; }; 243 244 Result<const float*, int> result = CreateSuccess(); 245 TestSuccess(&result, &dummyConstSuccess); 246 } 247 248 // Result<Ref<T>, E> 249 250 // Test constructing an error Result<Ref<T>, E> TEST(ResultRefT,ConstructingError)251 TEST(ResultRefT, ConstructingError) { 252 Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError)); 253 TestError(&result, dummyError); 254 } 255 256 // Test moving an error Result<Ref<T>, E> TEST(ResultRefT,MovingError)257 TEST(ResultRefT, MovingError) { 258 Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError)); 259 Result<Ref<AClass>, int> movedResult(std::move(result)); 260 TestError(&movedResult, dummyError); 261 } 262 263 // Test returning an error Result<Ref<T>, E> TEST(ResultRefT,ReturningError)264 TEST(ResultRefT, ReturningError) { 265 auto CreateError = []() -> Result<Ref<AClass>, int> { 266 return {std::make_unique<int>(dummyError)}; 267 }; 268 269 Result<Ref<AClass>, int> result = CreateError(); 270 TestError(&result, dummyError); 271 } 272 273 // Test constructing a success Result<Ref<T>, E> TEST(ResultRefT,ConstructingSuccess)274 TEST(ResultRefT, ConstructingSuccess) { 275 AClass success; 276 277 Ref<AClass> refObj(&success); 278 Result<Ref<AClass>, int> result(std::move(refObj)); 279 TestSuccess(&result, &success); 280 } 281 282 // Test moving a success Result<Ref<T>, E> TEST(ResultRefT,MovingSuccess)283 TEST(ResultRefT, MovingSuccess) { 284 AClass success; 285 286 Ref<AClass> refObj(&success); 287 Result<Ref<AClass>, int> result(std::move(refObj)); 288 Result<Ref<AClass>, int> movedResult(std::move(result)); 289 TestSuccess(&movedResult, &success); 290 } 291 292 // Test returning a success Result<Ref<T>, E> TEST(ResultRefT,ReturningSuccess)293 TEST(ResultRefT, ReturningSuccess) { 294 AClass success; 295 auto CreateSuccess = [&success]() -> Result<Ref<AClass>, int> { 296 return Ref<AClass>(&success); 297 }; 298 299 Result<Ref<AClass>, int> result = CreateSuccess(); 300 TestSuccess(&result, &success); 301 } 302 303 class OtherClass { 304 public: 305 int a = 0; 306 }; 307 class Base : public RefCounted {}; 308 class Child : public OtherClass, public Base {}; 309 310 // Test constructing a Result<Ref<TChild>, E> TEST(ResultRefT,ConversionFromChildConstructor)311 TEST(ResultRefT, ConversionFromChildConstructor) { 312 Child child; 313 Ref<Child> refChild(&child); 314 315 Result<Ref<Base>, int> result(std::move(refChild)); 316 TestSuccess<Base>(&result, &child); 317 } 318 319 // Test copy constructing Result<Ref<TChild>, E> TEST(ResultRefT,ConversionFromChildCopyConstructor)320 TEST(ResultRefT, ConversionFromChildCopyConstructor) { 321 Child child; 322 Ref<Child> refChild(&child); 323 324 Result<Ref<Child>, int> resultChild(std::move(refChild)); 325 Result<Ref<Base>, int> result(std::move(resultChild)); 326 TestSuccess<Base>(&result, &child); 327 } 328 329 // Test assignment operator for Result<Ref<TChild>, E> TEST(ResultRefT,ConversionFromChildAssignmentOperator)330 TEST(ResultRefT, ConversionFromChildAssignmentOperator) { 331 Child child; 332 Ref<Child> refChild(&child); 333 334 Result<Ref<Child>, int> resultChild(std::move(refChild)); 335 Result<Ref<Base>, int> result = std::move(resultChild); 336 TestSuccess<Base>(&result, &child); 337 } 338 339 // Result<T, E> 340 341 // Test constructing an error Result<T, E> TEST(ResultGeneric,ConstructingError)342 TEST(ResultGeneric, ConstructingError) { 343 Result<std::vector<float>, int> result(std::make_unique<int>(dummyError)); 344 TestError(&result, dummyError); 345 } 346 347 // Test moving an error Result<T, E> TEST(ResultGeneric,MovingError)348 TEST(ResultGeneric, MovingError) { 349 Result<std::vector<float>, int> result(std::make_unique<int>(dummyError)); 350 Result<std::vector<float>, int> movedResult(std::move(result)); 351 TestError(&movedResult, dummyError); 352 } 353 354 // Test returning an error Result<T, E> TEST(ResultGeneric,ReturningError)355 TEST(ResultGeneric, ReturningError) { 356 auto CreateError = []() -> Result<std::vector<float>, int> { 357 return {std::make_unique<int>(dummyError)}; 358 }; 359 360 Result<std::vector<float>, int> result = CreateError(); 361 TestError(&result, dummyError); 362 } 363 364 // Test constructing a success Result<T, E> TEST(ResultGeneric,ConstructingSuccess)365 TEST(ResultGeneric, ConstructingSuccess) { 366 Result<std::vector<float>, int> result({1.0f}); 367 TestSuccess(&result, {1.0f}); 368 } 369 370 // Test moving a success Result<T, E> TEST(ResultGeneric,MovingSuccess)371 TEST(ResultGeneric, MovingSuccess) { 372 Result<std::vector<float>, int> result({1.0f}); 373 Result<std::vector<float>, int> movedResult(std::move(result)); 374 TestSuccess(&movedResult, {1.0f}); 375 } 376 377 // Test returning a success Result<T, E> TEST(ResultGeneric,ReturningSuccess)378 TEST(ResultGeneric, ReturningSuccess) { 379 auto CreateSuccess = []() -> Result<std::vector<float>, int> { return {{1.0f}}; }; 380 381 Result<std::vector<float>, int> result = CreateSuccess(); 382 TestSuccess(&result, {1.0f}); 383 } 384 385 } // anonymous namespace 386