/* * Copyright 2017, 2018 Google * * 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. */ // Unit tests for StatusOr #include "Firestore/core/src/firebase/firestore/util/statusor.h" #include "gtest/gtest.h" namespace firebase { namespace firestore { namespace util { namespace { using std::string; class Base1 { public: virtual ~Base1() { } int pad_; }; class Base2 { public: virtual ~Base2() { } int yetotherpad_; }; class Derived : public Base1, public Base2 { public: ~Derived() override { } int evenmorepad_; }; class CopyNoAssign { public: explicit CopyNoAssign(int value) : foo_(value) { } CopyNoAssign(const CopyNoAssign& other) : foo_(other.foo_) { } int foo_; private: const CopyNoAssign& operator=(const CopyNoAssign&); }; class NoDefaultConstructor { public: explicit NoDefaultConstructor(int foo); }; static_assert(!std::is_default_constructible(), "Should not be default-constructible."); StatusOr> ReturnUniquePtr() { // Uses implicit constructor from T&& return std::unique_ptr(new int(0)); } TEST(StatusOr, ElementType) { static_assert(std::is_same::element_type, int>(), ""); static_assert(std::is_same::element_type, char>(), ""); } TEST(StatusOr, TestNoDefaultConstructorInitialization) { // Explicitly initialize it with an error code. StatusOr statusor( Status(FirestoreErrorCode::Cancelled, "")); EXPECT_FALSE(statusor.ok()); EXPECT_EQ(statusor.status().code(), FirestoreErrorCode::Cancelled); // Default construction of StatusOr initializes it with an UNKNOWN error code. StatusOr statusor2; EXPECT_FALSE(statusor2.ok()); EXPECT_EQ(statusor2.status().code(), FirestoreErrorCode::Unknown); } TEST(StatusOr, TestMoveOnlyInitialization) { StatusOr> thing(ReturnUniquePtr()); ASSERT_TRUE(thing.ok()); EXPECT_EQ(0, *thing.ValueOrDie()); int* previous = thing.ValueOrDie().get(); thing = ReturnUniquePtr(); EXPECT_TRUE(thing.ok()); EXPECT_EQ(0, *thing.ValueOrDie()); EXPECT_NE(previous, thing.ValueOrDie().get()); } TEST(StatusOr, TestMoveOnlyStatusCtr) { StatusOr> thing( Status(FirestoreErrorCode::Cancelled, "")); ASSERT_FALSE(thing.ok()); } TEST(StatusOr, TestMoveOnlyValueExtraction) { StatusOr> thing(ReturnUniquePtr()); ASSERT_TRUE(thing.ok()); std::unique_ptr ptr = thing.ConsumeValueOrDie(); EXPECT_EQ(0, *ptr); thing = std::move(ptr); ptr = std::move(thing.ValueOrDie()); EXPECT_EQ(0, *ptr); } TEST(StatusOr, TestMoveOnlyConversion) { StatusOr> const_thing(ReturnUniquePtr()); EXPECT_TRUE(const_thing.ok()); EXPECT_EQ(0, *const_thing.ValueOrDie()); // Test rvalue converting assignment const int* const_previous = const_thing.ValueOrDie().get(); const_thing = ReturnUniquePtr(); EXPECT_TRUE(const_thing.ok()); EXPECT_EQ(0, *const_thing.ValueOrDie()); EXPECT_NE(const_previous, const_thing.ValueOrDie().get()); } TEST(StatusOr, TestMoveOnlyVector) { // Sanity check that StatusOr works in vector. std::vector>> vec; vec.push_back(ReturnUniquePtr()); vec.resize(2); auto another_vec = std::move(vec); EXPECT_EQ(0, *another_vec[0].ValueOrDie()); EXPECT_EQ(FirestoreErrorCode::Unknown, another_vec[1].status().code()); } TEST(StatusOr, TestMoveWithValuesAndErrors) { StatusOr status_or(string(1000, '0')); StatusOr value1(string(1000, '1')); StatusOr value2(string(1000, '2')); StatusOr error1(Status(FirestoreErrorCode::Unknown, "error1")); StatusOr error2(Status(FirestoreErrorCode::Unknown, "error2")); ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '0'), status_or.ValueOrDie()); // Overwrite the value in status_or with another value. status_or = std::move(value1); ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '1'), status_or.ValueOrDie()); // Overwrite the value in status_or with an error. status_or = std::move(error1); ASSERT_FALSE(status_or.ok()); EXPECT_EQ("error1", status_or.status().error_message()); // Overwrite the error in status_or with another error. status_or = std::move(error2); ASSERT_FALSE(status_or.ok()); EXPECT_EQ("error2", status_or.status().error_message()); // Overwrite the error with a value. status_or = std::move(value2); ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '2'), status_or.ValueOrDie()); } TEST(StatusOr, TestCopyWithValuesAndErrors) { StatusOr status_or(string(1000, '0')); StatusOr value1(string(1000, '1')); StatusOr value2(string(1000, '2')); StatusOr error1(Status(FirestoreErrorCode::Unknown, "error1")); StatusOr error2(Status(FirestoreErrorCode::Unknown, "error2")); ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '0'), status_or.ValueOrDie()); // Overwrite the value in status_or with another value. status_or = value1; ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '1'), status_or.ValueOrDie()); // Overwrite the value in status_or with an error. status_or = error1; ASSERT_FALSE(status_or.ok()); EXPECT_EQ("error1", status_or.status().error_message()); // Overwrite the error in status_or with another error. status_or = error2; ASSERT_FALSE(status_or.ok()); EXPECT_EQ("error2", status_or.status().error_message()); // Overwrite the error with a value. status_or = value2; ASSERT_TRUE(status_or.ok()); EXPECT_EQ(string(1000, '2'), status_or.ValueOrDie()); // Verify original values unchanged. EXPECT_EQ(string(1000, '1'), value1.ValueOrDie()); EXPECT_EQ("error1", error1.status().error_message()); EXPECT_EQ("error2", error2.status().error_message()); EXPECT_EQ(string(1000, '2'), value2.ValueOrDie()); } TEST(StatusOr, TestDefaultCtor) { StatusOr thing; EXPECT_FALSE(thing.ok()); EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Unknown); } TEST(StatusOrDeathTest, TestDefaultCtorValue) { StatusOr thing; EXPECT_ANY_THROW(thing.ValueOrDie()); const StatusOr thing2; EXPECT_ANY_THROW(thing.ValueOrDie()); } TEST(StatusOr, TestStatusCtor) { StatusOr thing(Status(FirestoreErrorCode::Cancelled, "")); EXPECT_FALSE(thing.ok()); EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Cancelled); } TEST(StatusOr, TestValueCtor) { const int kI = 4; const StatusOr thing(kI); EXPECT_TRUE(thing.ok()); EXPECT_EQ(kI, thing.ValueOrDie()); } TEST(StatusOr, TestCopyCtorStatusOk) { const int kI = 4; const StatusOr original(kI); const StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie()); } TEST(StatusOr, TestCopyCtorStatusNotOk) { StatusOr original(Status(FirestoreErrorCode::Cancelled, "")); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); } TEST(StatusOr, TestCopyCtorNonAssignable) { const int kI = 4; CopyNoAssign value(kI); StatusOr original(value); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); EXPECT_EQ(original.ValueOrDie().foo_, copy.ValueOrDie().foo_); } TEST(StatusOr, TestCopyCtorStatusOKConverting) { const int kI = 4; StatusOr original(kI); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); EXPECT_DOUBLE_EQ(original.ValueOrDie(), copy.ValueOrDie()); } TEST(StatusOr, TestCopyCtorStatusNotOkConverting) { StatusOr original(Status(FirestoreErrorCode::Cancelled, "")); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); } TEST(StatusOr, TestAssignmentStatusOk) { const int kI = 4; StatusOr source(kI); StatusOr target; target = source; EXPECT_EQ(target.status(), source.status()); EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie()); } TEST(StatusOr, TestAssignmentStatusNotOk) { StatusOr source(Status(FirestoreErrorCode::Cancelled, "")); StatusOr target; target = source; EXPECT_EQ(target.status(), source.status()); } TEST(StatusOr, TestStatus) { StatusOr good(4); EXPECT_TRUE(good.ok()); StatusOr bad(Status(FirestoreErrorCode::Cancelled, "")); EXPECT_FALSE(bad.ok()); EXPECT_EQ(bad.status(), Status(FirestoreErrorCode::Cancelled, "")); } TEST(StatusOr, TestValue) { const int kI = 4; StatusOr thing(kI); EXPECT_EQ(kI, thing.ValueOrDie()); } TEST(StatusOr, TestValueConst) { const int kI = 4; const StatusOr thing(kI); EXPECT_EQ(kI, thing.ValueOrDie()); } TEST(StatusOrDeathTest, TestValueNotOk) { StatusOr thing(Status(FirestoreErrorCode::Cancelled, "cancelled")); EXPECT_ANY_THROW(thing.ValueOrDie()); } TEST(StatusOrDeathTest, TestValueNotOkConst) { const StatusOr thing(Status(FirestoreErrorCode::Unknown, "")); EXPECT_ANY_THROW(thing.ValueOrDie()); } TEST(StatusOr, TestPointerDefaultCtor) { StatusOr thing; EXPECT_FALSE(thing.ok()); EXPECT_EQ(thing.status().code(), FirestoreErrorCode::Unknown); } TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) { StatusOr thing; EXPECT_ANY_THROW(thing.ValueOrDie()); } TEST(StatusOr, TestPointerStatusCtor) { StatusOr thing(Status(FirestoreErrorCode::Cancelled, "")); EXPECT_FALSE(thing.ok()); EXPECT_EQ(thing.status(), Status(FirestoreErrorCode::Cancelled, "")); } TEST(StatusOr, TestPointerValueCtor) { const int kI = 4; StatusOr thing(&kI); EXPECT_TRUE(thing.ok()); EXPECT_EQ(&kI, thing.ValueOrDie()); } TEST(StatusOr, TestPointerCopyCtorStatusOk) { const int kI = 0; StatusOr original(&kI); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie()); } TEST(StatusOr, TestPointerCopyCtorStatusNotOk) { StatusOr original(Status(FirestoreErrorCode::Cancelled, "")); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); } TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) { Derived derived; StatusOr original(&derived); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); EXPECT_EQ(static_cast(original.ValueOrDie()), copy.ValueOrDie()); } TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) { StatusOr original(Status(FirestoreErrorCode::Cancelled, "")); StatusOr copy(original); EXPECT_EQ(copy.status(), original.status()); } TEST(StatusOr, TestPointerAssignmentStatusOk) { const int kI = 0; StatusOr source(&kI); StatusOr target; target = source; EXPECT_EQ(target.status(), source.status()); EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie()); } TEST(StatusOr, TestPointerAssignmentStatusNotOk) { StatusOr source(Status(FirestoreErrorCode::Cancelled, "")); StatusOr target; target = source; EXPECT_EQ(target.status(), source.status()); } TEST(StatusOr, TestPointerStatus) { const int kI = 0; StatusOr good(&kI); EXPECT_TRUE(good.ok()); StatusOr bad(Status(FirestoreErrorCode::Cancelled, "")); EXPECT_EQ(bad.status(), Status(FirestoreErrorCode::Cancelled, "")); } TEST(StatusOr, TestPointerValue) { const int kI = 0; StatusOr thing(&kI); EXPECT_EQ(&kI, thing.ValueOrDie()); } TEST(StatusOr, TestPointerValueConst) { const int kI = 0; const StatusOr thing(&kI); EXPECT_EQ(&kI, thing.ValueOrDie()); } // NOTE(tucker): tensorflow::StatusOr does not support this kind // of resize op. // NOTE(rsgowman): We stole StatusOr from tensorflow, so this applies here too. // TEST(StatusOr, StatusOrVectorOfUniquePointerCanResize) { // using EvilType = std::vector>; // static_assert(std::is_copy_constructible::value, ""); // std::vector> v(5); // v.reserve(v.capacity() + 10); // } TEST(StatusOrDeathTest, TestPointerValueNotOk) { StatusOr thing(Status(FirestoreErrorCode::Cancelled, "cancelled")); EXPECT_ANY_THROW(thing.ValueOrDie()); } TEST(StatusOrDeathTest, TestPointerValueNotOkConst) { const StatusOr thing( Status(FirestoreErrorCode::Cancelled, "cancelled")); EXPECT_ANY_THROW(thing.ValueOrDie()); } } // namespace } // namespace util } // namespace firestore } // namespace firebase