You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.7 KiB
180 lines
4.7 KiB
4 months ago
|
|
||
|
/*
|
||
|
* 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)
|