// Copyright 2018 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "common/RefCounted.h" #include "common/Result.h" namespace { template void TestError(Result* result, E expectedError) { EXPECT_TRUE(result->IsError()); EXPECT_FALSE(result->IsSuccess()); std::unique_ptr storedError = result->AcquireError(); EXPECT_EQ(*storedError, expectedError); } template void TestSuccess(Result* result, T expectedSuccess) { EXPECT_FALSE(result->IsError()); EXPECT_TRUE(result->IsSuccess()); const T storedSuccess = result->AcquireSuccess(); EXPECT_EQ(storedSuccess, expectedSuccess); // Once the success is acquired, result has an empty // payload and is neither in the success nor error state. EXPECT_FALSE(result->IsError()); EXPECT_FALSE(result->IsSuccess()); } static int dummyError = 0xbeef; static float dummySuccess = 42.0f; static const float dummyConstSuccess = 42.0f; class AClass : public RefCounted { public: int a = 0; }; // Tests using the following overload of TestSuccess make // local Ref instances to dummySuccessObj. Tests should // ensure any local Ref objects made along the way continue // to point to dummySuccessObj. template void TestSuccess(Result, E>* result, T* expectedSuccess) { EXPECT_FALSE(result->IsError()); EXPECT_TRUE(result->IsSuccess()); // AClass starts with a reference count of 1 and stored // on the stack in the caller. The result parameter should // hold the only other reference to the object. EXPECT_EQ(expectedSuccess->GetRefCountForTesting(), 2u); const Ref storedSuccess = result->AcquireSuccess(); EXPECT_EQ(storedSuccess.Get(), expectedSuccess); // Once the success is acquired, result has an empty // payload and is neither in the success nor error state. EXPECT_FALSE(result->IsError()); EXPECT_FALSE(result->IsSuccess()); // Once we call AcquireSuccess, result no longer stores // the object. storedSuccess should contain the only other // reference to the object. EXPECT_EQ(storedSuccess->GetRefCountForTesting(), 2u); } // Result // Test constructing an error Result TEST(ResultOnlyPointerError, ConstructingError) { Result result(std::make_unique(dummyError)); TestError(&result, dummyError); } // Test moving an error Result TEST(ResultOnlyPointerError, MovingError) { Result result(std::make_unique(dummyError)); Result movedResult(std::move(result)); TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultOnlyPointerError, ReturningError) { auto CreateError = []() -> Result { return {std::make_unique(dummyError)}; }; Result result = CreateError(); TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultOnlyPointerError, ConstructingSuccess) { Result result; EXPECT_TRUE(result.IsSuccess()); EXPECT_FALSE(result.IsError()); } // Test moving a success Result TEST(ResultOnlyPointerError, MovingSuccess) { Result result; Result movedResult(std::move(result)); EXPECT_TRUE(movedResult.IsSuccess()); EXPECT_FALSE(movedResult.IsError()); } // Test returning a success Result TEST(ResultOnlyPointerError, ReturningSuccess) { auto CreateError = []() -> Result { return {}; }; Result result = CreateError(); EXPECT_TRUE(result.IsSuccess()); EXPECT_FALSE(result.IsError()); } // Result // Test constructing an error Result TEST(ResultBothPointer, ConstructingError) { Result result(std::make_unique(dummyError)); TestError(&result, dummyError); } // Test moving an error Result TEST(ResultBothPointer, MovingError) { Result result(std::make_unique(dummyError)); Result movedResult(std::move(result)); TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultBothPointer, ReturningError) { auto CreateError = []() -> Result { return {std::make_unique(dummyError)}; }; Result result = CreateError(); TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultBothPointer, ConstructingSuccess) { Result result(&dummySuccess); TestSuccess(&result, &dummySuccess); } // Test moving a success Result TEST(ResultBothPointer, MovingSuccess) { Result result(&dummySuccess); Result movedResult(std::move(result)); TestSuccess(&movedResult, &dummySuccess); } // Test returning a success Result TEST(ResultBothPointer, ReturningSuccess) { auto CreateSuccess = []() -> Result { return {&dummySuccess}; }; Result result = CreateSuccess(); TestSuccess(&result, &dummySuccess); } // Tests converting from a Result TEST(ResultBothPointer, ConversionFromChildClass) { struct T { int a; }; struct TChild : T {}; TChild child; T* childAsT = &child; { Result result(&child); TestSuccess(&result, childAsT); } { Result resultChild(&child); Result result(std::move(resultChild)); TestSuccess(&result, childAsT); } { Result resultChild(&child); Result result = std::move(resultChild); TestSuccess(&result, childAsT); } } // Result // Test constructing an error Result TEST(ResultBothPointerWithConstResult, ConstructingError) { Result result(std::make_unique(dummyError)); TestError(&result, dummyError); } // Test moving an error Result TEST(ResultBothPointerWithConstResult, MovingError) { Result result(std::make_unique(dummyError)); Result movedResult(std::move(result)); TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultBothPointerWithConstResult, ReturningError) { auto CreateError = []() -> Result { return {std::make_unique(dummyError)}; }; Result result = CreateError(); TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultBothPointerWithConstResult, ConstructingSuccess) { Result result(&dummyConstSuccess); TestSuccess(&result, &dummyConstSuccess); } // Test moving a success Result TEST(ResultBothPointerWithConstResult, MovingSuccess) { Result result(&dummyConstSuccess); Result movedResult(std::move(result)); TestSuccess(&movedResult, &dummyConstSuccess); } // Test returning a success Result TEST(ResultBothPointerWithConstResult, ReturningSuccess) { auto CreateSuccess = []() -> Result { return {&dummyConstSuccess}; }; Result result = CreateSuccess(); TestSuccess(&result, &dummyConstSuccess); } // Result, E> // Test constructing an error Result, E> TEST(ResultRefT, ConstructingError) { Result, int> result(std::make_unique(dummyError)); TestError(&result, dummyError); } // Test moving an error Result, E> TEST(ResultRefT, MovingError) { Result, int> result(std::make_unique(dummyError)); Result, int> movedResult(std::move(result)); TestError(&movedResult, dummyError); } // Test returning an error Result, E> TEST(ResultRefT, ReturningError) { auto CreateError = []() -> Result, int> { return {std::make_unique(dummyError)}; }; Result, int> result = CreateError(); TestError(&result, dummyError); } // Test constructing a success Result, E> TEST(ResultRefT, ConstructingSuccess) { AClass success; Ref refObj(&success); Result, int> result(std::move(refObj)); TestSuccess(&result, &success); } // Test moving a success Result, E> TEST(ResultRefT, MovingSuccess) { AClass success; Ref refObj(&success); Result, int> result(std::move(refObj)); Result, int> movedResult(std::move(result)); TestSuccess(&movedResult, &success); } // Test returning a success Result, E> TEST(ResultRefT, ReturningSuccess) { AClass success; auto CreateSuccess = [&success]() -> Result, int> { return Ref(&success); }; Result, int> result = CreateSuccess(); TestSuccess(&result, &success); } class OtherClass { public: int a = 0; }; class Base : public RefCounted {}; class Child : public OtherClass, public Base {}; // Test constructing a Result, E> TEST(ResultRefT, ConversionFromChildConstructor) { Child child; Ref refChild(&child); Result, int> result(std::move(refChild)); TestSuccess(&result, &child); } // Test copy constructing Result, E> TEST(ResultRefT, ConversionFromChildCopyConstructor) { Child child; Ref refChild(&child); Result, int> resultChild(std::move(refChild)); Result, int> result(std::move(resultChild)); TestSuccess(&result, &child); } // Test assignment operator for Result, E> TEST(ResultRefT, ConversionFromChildAssignmentOperator) { Child child; Ref refChild(&child); Result, int> resultChild(std::move(refChild)); Result, int> result = std::move(resultChild); TestSuccess(&result, &child); } // Result // Test constructing an error Result TEST(ResultGeneric, ConstructingError) { Result, int> result(std::make_unique(dummyError)); TestError(&result, dummyError); } // Test moving an error Result TEST(ResultGeneric, MovingError) { Result, int> result(std::make_unique(dummyError)); Result, int> movedResult(std::move(result)); TestError(&movedResult, dummyError); } // Test returning an error Result TEST(ResultGeneric, ReturningError) { auto CreateError = []() -> Result, int> { return {std::make_unique(dummyError)}; }; Result, int> result = CreateError(); TestError(&result, dummyError); } // Test constructing a success Result TEST(ResultGeneric, ConstructingSuccess) { Result, int> result({1.0f}); TestSuccess(&result, {1.0f}); } // Test moving a success Result TEST(ResultGeneric, MovingSuccess) { Result, int> result({1.0f}); Result, int> movedResult(std::move(result)); TestSuccess(&movedResult, {1.0f}); } // Test returning a success Result TEST(ResultGeneric, ReturningSuccess) { auto CreateSuccess = []() -> Result, int> { return {{1.0f}}; }; Result, int> result = CreateSuccess(); TestSuccess(&result, {1.0f}); } } // anonymous namespace