/* * Copyright (C) 2016 The Android Open Source Project * * 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 "gtest/gtest.h" #include "chre/util/non_copyable.h" #include "chre/util/optional.h" using chre::Optional; class DestructorTestingObject { public: ~DestructorTestingObject() { if (valueToFlipWhenDestruct != nullptr) { *valueToFlipWhenDestruct = !*valueToFlipWhenDestruct; } } void setValueToFlipWhenDestruct(bool *value) { valueToFlipWhenDestruct = value; } private: bool *valueToFlipWhenDestruct = nullptr; }; TEST(Optional, ShouldDestructContainedObject) { bool destructed = false; { Optional<DestructorTestingObject> object(DestructorTestingObject{}); object.value().setValueToFlipWhenDestruct(&destructed); } EXPECT_TRUE(destructed); } TEST(Optional, NoValueByDefault) { Optional<int> myInt; EXPECT_FALSE(myInt.has_value()); } TEST(Optional, NonDefaultValueByDefault) { Optional<int> myInt(0x1337); EXPECT_TRUE(myInt.has_value()); EXPECT_EQ(*myInt, 0x1337); } TEST(Optional, NonDefaultMovedValueByDefault) { Optional<int> myInt(std::move(0x1337)); EXPECT_TRUE(myInt.has_value()); EXPECT_EQ(*myInt, 0x1337); } TEST(Optional, CopyConstruct) { Optional<int> myInt(0x1337); Optional<int> myNewInt(myInt); EXPECT_TRUE(myNewInt.has_value()); EXPECT_EQ(*myNewInt, 0x1337); } TEST(Optional, CopyConstructConst) { const Optional<int> myInt(0x1337); Optional<int> myNewInt(myInt); EXPECT_TRUE(myNewInt.has_value()); EXPECT_EQ(*myNewInt, 0x1337); } TEST(Optional, CopyAssignAndRead) { Optional<int> myInt; EXPECT_FALSE(myInt.has_value()); myInt = 0x1337; EXPECT_EQ(*myInt, 0x1337); EXPECT_TRUE(myInt.has_value()); myInt.reset(); EXPECT_FALSE(myInt.has_value()); } TEST(Optional, MoveAssignAndRead) { Optional<int> myInt; EXPECT_FALSE(myInt.has_value()); myInt = std::move(0xcafe); EXPECT_TRUE(myInt.has_value()); EXPECT_EQ(*myInt, 0xcafe); } TEST(Optional, OptionalMoveAssignAndRead) { Optional<int> myInt(0x1337); Optional<int> myMovedInt; EXPECT_FALSE(myMovedInt.has_value()); myMovedInt = std::move(myInt); EXPECT_TRUE(myInt.has_value()); EXPECT_TRUE(myMovedInt.has_value()); EXPECT_EQ(*myMovedInt, 0x1337); } TEST(Optional, OptionalCopyAssignAndRead) { Optional<int> myInt(0x1337); Optional<int> myCopiedInt; EXPECT_FALSE(myCopiedInt.has_value()); myCopiedInt = myInt; EXPECT_TRUE(myInt.has_value()); EXPECT_TRUE(myCopiedInt.has_value()); EXPECT_EQ(*myInt, 0x1337); EXPECT_EQ(*myCopiedInt, 0x1337); } static constexpr int kInvalidValue = -1; class MovableButNonCopyable : public chre::NonCopyable { public: MovableButNonCopyable() = default; MovableButNonCopyable(int value) : mValue(value) {} MovableButNonCopyable(MovableButNonCopyable&& other) { mValue = other.mValue; other.mValue = kInvalidValue; } MovableButNonCopyable& operator=(MovableButNonCopyable&& other) { assert(mMagic == kConstructedMagic); mValue = other.mValue; other.mValue = kInvalidValue; return *this; } ~MovableButNonCopyable() { mMagic = kUninitializedMagic; mValue = kUninitializedMagic; } int getValue() const { return mValue; } private: static constexpr int kConstructedMagic = 0xfeedc0fe; static constexpr int kUninitializedMagic = 0xdeadbeef; int mMagic = kConstructedMagic; int mValue = kInvalidValue; }; TEST(Optional, UninitializedAssignment) { constexpr int kValue1 = 0xd00d; constexpr int kValue2 = 0xcafe; MovableButNonCopyable transferee1(kValue1); MovableButNonCopyable transferee2(kValue2); Optional<MovableButNonCopyable> container; EXPECT_FALSE(container.has_value()); container = std::move(transferee1); EXPECT_TRUE(container.has_value()); EXPECT_EQ(container->getValue(), kValue1); EXPECT_EQ(transferee1.getValue(), kInvalidValue); container.reset(); EXPECT_FALSE(container.has_value()); container = std::move(transferee2); EXPECT_TRUE(container.has_value()); EXPECT_EQ(container->getValue(), kValue2); EXPECT_EQ(transferee2.getValue(), kInvalidValue); } // TODO: should add some tests to cover the possible assignment outcomes between // two Optional instances (e.g. assign one w/o value to one w/value, etc)