| |
| /* |
| * 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) |