blob: 3fe99c83f3fb12b9fe4e0802d39cf131128ba010 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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 <set>
#include <string>
#include <vector>
#include "base/hash_tables.h"
#include "base/optional.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::InSequence;
typedef base::optional<int> OptionalInt;
TEST(OptionalTest, EnsureDefaultConstructorGivesDisengagedOptional) {
OptionalInt test;
EXPECT_TRUE(!test);
}
TEST(OptionalTest, EnsureNullOptConstructorGivesDisengagedOptional) {
OptionalInt test(base::nullopt);
EXPECT_TRUE(!test);
}
TEST(OptionalTest, InitializeConstructor) {
OptionalInt test(2);
EXPECT_FALSE(!test);
EXPECT_EQ(2, test.value());
}
TEST(OptionalTest, BoolCastOperator) {
OptionalInt test;
EXPECT_FALSE(static_cast<bool>(test));
test = 5;
EXPECT_TRUE(static_cast<bool>(test));
}
TEST(OptionalTest, InitializeAssign) {
OptionalInt test = 2;
EXPECT_FALSE(!test);
EXPECT_EQ(2, test.value());
}
TEST(OptionalTest, ReassignValue) {
OptionalInt test(2);
test = 5;
EXPECT_FALSE(!test);
EXPECT_EQ(5, test.value());
}
TEST(OptionalTest, CopyAssignment) {
OptionalInt a;
OptionalInt b = 2;
OptionalInt c = 3;
a = b;
EXPECT_FALSE(!a);
EXPECT_EQ(2, a.value());
a = c;
EXPECT_FALSE(!a);
EXPECT_EQ(3, a.value());
}
TEST(OptionalTest, ClearAssignment) {
OptionalInt test(2);
test = OptionalInt();
EXPECT_FALSE(test);
}
TEST(OptionalTest, EnsureAssignmentOfNullOptResultsInDisengagement) {
OptionalInt test(2);
test = base::nullopt;
EXPECT_FALSE(test);
}
TEST(OptionalTest, EnsureAssignmentOfDefaultOptionalResultsInDisengagement) {
OptionalInt test(2);
test = OptionalInt();
EXPECT_FALSE(test);
}
TEST(OptionalTest, CopyConstruction) {
OptionalInt test1(2);
OptionalInt test2(test1);
EXPECT_FALSE(!test2);
EXPECT_EQ(2, test2.value());
}
TEST(OptionalTest, Swap) {
OptionalInt test1(1);
OptionalInt test2(2);
// Swap two engaged optionals.
test1.swap(test2);
EXPECT_FALSE(!test1);
EXPECT_EQ(2, test1.value());
EXPECT_EQ(1, test2.value());
// Swap two optionals where only one is engaged.
test1 = base::nullopt;
test1.swap(test2);
EXPECT_FALSE(test2);
EXPECT_FALSE(!test1);
EXPECT_EQ(1, test1.value());
// Swap two optionals where only one is engaged, except the other way around.
test1.swap(test2);
EXPECT_FALSE(test1);
EXPECT_FALSE(!test2);
EXPECT_EQ(1, test2.value());
// Swap two disengaged optionals.
test2 = base::nullopt;
test1.swap(test2);
EXPECT_FALSE(test1);
EXPECT_FALSE(test2);
}
TEST(OptionalTest, StdSwap) {
OptionalInt test1(1);
OptionalInt test2(2);
// Swap two engaged optionals.
std::swap(test1, test2);
EXPECT_FALSE(!test1);
EXPECT_EQ(2, test1.value());
EXPECT_EQ(1, test2.value());
// Swap two optionals where only one is engaged.
test1 = base::nullopt;
std::swap(test1, test2);
EXPECT_FALSE(test2);
EXPECT_FALSE(!test1);
EXPECT_EQ(1, test1.value());
// Swap two optionals where only one is engaged, except the other way around.
std::swap(test1, test2);
EXPECT_FALSE(test1);
EXPECT_FALSE(!test2);
EXPECT_EQ(1, test2.value());
// Swap two disengaged optionals.
test2 = base::nullopt;
std::swap(test1, test2);
EXPECT_FALSE(test1);
EXPECT_FALSE(test2);
}
TEST(OptionalTest, SwapWithSelf) {
OptionalInt test(1);
test.swap(test);
EXPECT_EQ(1, test.value());
std::swap(test, test);
EXPECT_EQ(1, test.value());
}
TEST(OptionalTest, AsteriskDereference) {
OptionalInt test(2);
EXPECT_EQ(2, *test);
*test = 5;
EXPECT_EQ(5, test.value());
}
namespace {
struct TestStruct {
int foobar;
};
} // namespace
TEST(OptionalTest, ArrowDereference) {
TestStruct a;
a.foobar = 2;
base::optional<TestStruct> test(a);
EXPECT_EQ(2, test->foobar);
test->foobar = 5;
EXPECT_EQ(5, test.value().foobar);
// Test const arrow dereference.
const base::optional<TestStruct> test_const(a);
EXPECT_EQ(2, test_const->foobar);
}
namespace {
class NoDefaultTest {
public:
explicit NoDefaultTest(int i) { foobar_ = i; }
int foobar() const { return foobar_; }
private:
NoDefaultTest();
int foobar_;
};
} // namespace
TEST(OptionalTest, NoDefaultConstructorIsSupported) {
// First test with an object passed in upon construction
base::optional<NoDefaultTest> test1(NoDefaultTest(2));
EXPECT_EQ(2, test1.value().foobar());
// Now test with an object assignment after construction
base::optional<NoDefaultTest> test2;
test2 = NoDefaultTest(5);
EXPECT_EQ(5, test2.value().foobar());
}
TEST(OptionalTest, TestEquivalenceComparisons) {
OptionalInt test1 = 1;
OptionalInt test2 = 2;
OptionalInt test3;
OptionalInt test4 = 2;
EXPECT_FALSE(test1 == test2);
EXPECT_FALSE(test2 == test1);
EXPECT_FALSE(test1 == test3);
EXPECT_FALSE(test3 == test1);
EXPECT_FALSE(2 == test1);
EXPECT_FALSE(test1 == 2);
EXPECT_EQ(1, test1);
EXPECT_EQ(test1, 1);
EXPECT_EQ(test4, test2);
EXPECT_EQ(test2, test4);
// Test nullopt comparisons
EXPECT_TRUE(test3 == base::nullopt);
EXPECT_TRUE(base::nullopt == test3);
EXPECT_FALSE(test1 == base::nullopt);
EXPECT_FALSE(base::nullopt == test1);
}
TEST(OptionalTest, TestLessThanComparisons) {
OptionalInt test1 = 1;
OptionalInt test2 = 2;
OptionalInt test3;
OptionalInt test4 = 2;
EXPECT_TRUE(test1 < test2);
EXPECT_FALSE(test2 < test1);
EXPECT_FALSE(test1 < test1);
EXPECT_TRUE(test3 < test1);
EXPECT_FALSE(test1 < test3);
EXPECT_FALSE(test3 < test3);
EXPECT_TRUE(base::nullopt < test1);
EXPECT_FALSE(test1 < base::nullopt);
EXPECT_TRUE(test1 < 2);
EXPECT_FALSE(2 < test1);
}
TEST(OptionalTest, EnsureOptionalWorksWithFunnyAlignments) {
struct {
char c;
base::optional<uint64_t> number;
} foo;
EXPECT_FALSE(!!foo.number);
foo.number = 1;
EXPECT_TRUE(!!foo.number);
EXPECT_EQ(1, foo.number.value());
}
namespace {
class DestructorCallTester {
public:
DestructorCallTester() {};
DestructorCallTester(const DestructorCallTester&) {};
~DestructorCallTester() { Die(); }
MOCK_METHOD0(Die, void());
};
} // namespace
TEST(OptionalTest, EnsureDestructorIsCalled) {
{
// Ensure destructor is called upon optional destruction
base::optional<DestructorCallTester> test(base::in_place);
EXPECT_CALL(test.value(), Die());
}
{
// Ensure destructor is called upon assignment to null
base::optional<DestructorCallTester> test1(base::in_place);
base::optional<DestructorCallTester> test2(base::in_place);
{
InSequence s;
EXPECT_CALL(test1.value(), Die());
EXPECT_CALL(test2.value(), Die());
}
test1 = base::nullopt;
}
}
namespace {
// This class counts all calls to the set of methods declared in the class.
// It can be used to verify that certain methods are indeed called.
class MethodCallCounter {
public:
MethodCallCounter() {
ResetCounts();
++default_constructor_calls_;
}
MethodCallCounter(const MethodCallCounter& other) {
// A very non-standard copy constructor, since this is a test object
// intended to count method calls on this object and only this object.
ResetCounts();
++copy_constructor_calls_;
}
MethodCallCounter& operator=(const MethodCallCounter& other) {
++operator_equals_calls_;
return *this;
}
int default_constructor_calls() const { return default_constructor_calls_; }
int copy_constructor_calls() const { return copy_constructor_calls_; }
int operator_equals_calls() const { return operator_equals_calls_; }
private:
void ResetCounts() {
default_constructor_calls_ = 0;
copy_constructor_calls_ = 0;
operator_equals_calls_ = 0;
}
int default_constructor_calls_;
int copy_constructor_calls_;
int operator_equals_calls_;
};
} // namespace
TEST(OptionalTest, CopyConstructorIsCalledByValueCopyConstructor) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test(original_counter);
EXPECT_EQ(0, test->default_constructor_calls());
EXPECT_EQ(1, test->copy_constructor_calls());
EXPECT_EQ(0, test->operator_equals_calls());
}
TEST(OptionalTest, CopyConstructorIsCalledByOptionalCopyConstructor) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test1(original_counter);
base::optional<MethodCallCounter> test2(test1);
EXPECT_EQ(0, test2->default_constructor_calls());
EXPECT_EQ(1, test2->copy_constructor_calls());
EXPECT_EQ(0, test2->operator_equals_calls());
}
TEST(OptionalTest, CopyConstructorIsCalledByValueAssignment) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test;
test = original_counter;
EXPECT_EQ(0, test->default_constructor_calls());
EXPECT_EQ(1, test->copy_constructor_calls());
EXPECT_EQ(0, test->operator_equals_calls());
}
TEST(OptionalTest, CopyConstructorIsCalledByOptionalAssignment) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test1(original_counter);
base::optional<MethodCallCounter> test2;
test2 = test1;
EXPECT_EQ(0, test2->default_constructor_calls());
EXPECT_EQ(1, test2->copy_constructor_calls());
EXPECT_EQ(0, test2->operator_equals_calls());
}
TEST(OptionalTest, AssignmentIsCalledByValueAssignment) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test(original_counter);
test = original_counter;
EXPECT_EQ(0, test->default_constructor_calls());
EXPECT_EQ(1, test->copy_constructor_calls());
EXPECT_EQ(1, test->operator_equals_calls());
}
TEST(OptionalTest, AssignmentIsCalledByOptionalAssignment) {
MethodCallCounter original_counter;
base::optional<MethodCallCounter> test1(original_counter);
base::optional<MethodCallCounter> test2(original_counter);
test2 = test1;
EXPECT_EQ(0, test2->default_constructor_calls());
EXPECT_EQ(1, test2->copy_constructor_calls());
EXPECT_EQ(1, test2->operator_equals_calls());
}
TEST(OptionalTest, EnsureSelfAssignmentIsOkay) {
// Ensure that values are as we expect them to be.
OptionalInt test1(5);
test1 = test1;
EXPECT_FALSE(!test1);
EXPECT_EQ(5, test1.value());
// Ensure that the methods we expect to be called are actually called.
base::optional<MethodCallCounter> test2(base::in_place);
test2 = test2;
EXPECT_EQ(1, test2->default_constructor_calls());
EXPECT_EQ(0, test2->copy_constructor_calls());
EXPECT_EQ(1, test2->operator_equals_calls());
}
namespace {
// Helper classes to ensure that we can assign different values to optionals
// so long as the wrapped value can be assigned and constructed from the other.
struct XType {
XType(int number) { number_ = number; }
int number_;
};
struct YType {
explicit YType(int number) { number_ = number; }
explicit YType(const XType& x_type) { number_ = x_type.number_; }
YType& operator=(const XType& x_type) {
number_ = x_type.number_;
return *this;
}
int number_;
};
} // namespace
TEST(OptionalTest, CopyConstructorIsCalledByValueAssignmentFromOtherType) {
XType x_type(1);
base::optional<YType> test;
test = x_type;
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->number_);
}
TEST(OptionalTest, AssignmentIsCalledByValueAssignmentFromOtherType) {
XType x_type(1);
base::optional<YType> test(base::in_place, 2);
test = x_type;
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->number_);
}
TEST(OptionalTest, TestMakeOptional) {
OptionalInt test = base::make_optional(5);
EXPECT_FALSE(!test);
EXPECT_EQ(5, test.value());
}
TEST(OptionalTest, ValueOrTest) {
OptionalInt test;
EXPECT_EQ(4, test.value_or(4));
test = 2;
EXPECT_EQ(2, test.value_or(4));
}
TEST(OptionalTest, ConstOptionalsTest) {
const OptionalInt test1(5);
EXPECT_FALSE(!test1);
EXPECT_EQ(5, test1.value());
EXPECT_EQ(5, *test1);
const OptionalInt test2(test1);
EXPECT_FALSE(!test2);
EXPECT_EQ(5, test2.value());
EXPECT_EQ(5, *test2);
OptionalInt test3;
test3 = test2;
EXPECT_FALSE(!test3);
EXPECT_EQ(5, test3.value());
EXPECT_EQ(5, *test3);
}
TEST(OptionalTest, EmplaceInt) {
OptionalInt test;
test.emplace(5);
EXPECT_FALSE(!test);
EXPECT_EQ(5, test.value());
}
TEST(OptionalTest, EmplaceWithDefaultConstructor) {
base::optional<MethodCallCounter> test;
test.emplace();
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->default_constructor_calls());
EXPECT_EQ(0, test->copy_constructor_calls());
EXPECT_EQ(0, test->operator_equals_calls());
}
namespace {
class NoDefaultOrCopyConstructor {
public:
NoDefaultOrCopyConstructor(int x, int y) {
x_ = x;
y_ = y;
}
int x() const { return x_; }
int y() const { return y_; }
private:
NoDefaultOrCopyConstructor();
NoDefaultOrCopyConstructor(const NoDefaultOrCopyConstructor&);
int x_;
int y_;
};
} // namespace
TEST(OptionalTest, EmplaceObjectWithNoDefaultOrCopyConstructor) {
base::optional<NoDefaultOrCopyConstructor> test;
test.emplace(1, 2);
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->x());
EXPECT_EQ(2, test->y());
}
namespace {
class NonConstPointerInConstructor {
public:
explicit NonConstPointerInConstructor(int* param) { param_ = param; }
void SetParam(int value) { *param_ = value; }
private:
int* param_;
};
} // namespace
TEST(OptionalTest, EmplaceObjectWithNonConstPointer) {
int value = 0;
base::optional<NonConstPointerInConstructor> test;
test.emplace(&value);
test->SetParam(5);
EXPECT_EQ(5, value);
}
TEST(OptionalTest, ForwardingConstructorInt) {
OptionalInt test(base::in_place, 5);
EXPECT_FALSE(!test);
EXPECT_EQ(5, test.value());
}
TEST(OptionalTest, ForwardingConstructorWithDefaultConstructor) {
base::optional<MethodCallCounter> test(base::in_place);
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->default_constructor_calls());
EXPECT_EQ(0, test->copy_constructor_calls());
EXPECT_EQ(0, test->operator_equals_calls());
}
TEST(OptionalTest, ForwardingConstructorObjectWithNoDefaultOrCopyConstructor) {
base::optional<NoDefaultOrCopyConstructor> test(base::in_place, 1, 2);
EXPECT_FALSE(!test);
EXPECT_EQ(1, test->x());
EXPECT_EQ(2, test->y());
}
TEST(OptionalTest, ForwardingConstructorObjectWithNonConstPointer) {
int value = 0;
base::optional<NonConstPointerInConstructor> test(base::in_place, &value);
test->SetParam(5);
EXPECT_EQ(5, value);
}
namespace {
typedef base::optional<std::string> OptionalString;
} // namespace
TEST(OptionalTest, OptionalStringTest) {
{
OptionalString test;
EXPECT_TRUE(!test);
test = std::string("foo");
EXPECT_STREQ("foo", test->c_str());
}
{
OptionalString test(std::string("foo"));
EXPECT_FALSE(!test);
EXPECT_STREQ("foo", test->c_str());
OptionalString test2(test);
EXPECT_STREQ("foo", test2->c_str());
}
}
TEST(OptionalTest, OptionalStringInSetTest) {
// Optional strings in map test
std::set<OptionalString> optional_string_set;
optional_string_set.insert(std::string("foo"));
optional_string_set.insert(std::string("bar"));
EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
optional_string_set.end());
EXPECT_FALSE(optional_string_set.find(OptionalString()) !=
optional_string_set.end());
optional_string_set.insert(OptionalString());
EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(OptionalString()) !=
optional_string_set.end());
}
TEST(OptionalTest, StdVectorOfOptionalsWorksFine) {
std::vector<OptionalInt> test_vector;
test_vector.reserve(test_vector.capacity() + 1);
test_vector.resize(test_vector.capacity());
// Make sure all current optionals are disengaged.
for (std::vector<OptionalInt>::const_iterator iter = test_vector.begin();
iter != test_vector.end();
++iter) {
EXPECT_TRUE(!*iter);
}
EXPECT_TRUE(!test_vector[0]);
test_vector.clear();
test_vector.resize(test_vector.capacity() + 1, 5);
for (std::vector<OptionalInt>::const_iterator iter = test_vector.begin();
iter != test_vector.end();
++iter) {
ASSERT_FALSE(!*iter);
EXPECT_EQ(5, **iter);
}
ASSERT_FALSE(!test_vector[0]);
EXPECT_EQ(5, *test_vector[0]);
test_vector.push_back(8);
ASSERT_FALSE(!test_vector.back());
EXPECT_EQ(8, *test_vector.back());
}
TEST(OptionalTest, OptionalStringInHashSetTest) {
// Optional strings in map test
base::hash_set<OptionalString> optional_string_set;
optional_string_set.insert(std::string("foo"));
optional_string_set.insert(std::string("bar"));
EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
optional_string_set.end());
EXPECT_FALSE(optional_string_set.find(OptionalString()) !=
optional_string_set.end());
optional_string_set.insert(OptionalString());
EXPECT_TRUE(optional_string_set.find(std::string("foo")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(std::string("bar")) !=
optional_string_set.end());
EXPECT_TRUE(optional_string_set.find(OptionalString()) !=
optional_string_set.end());
}
namespace {
OptionalInt ConditionallyMakeOptional(bool should_make, int value) {
if (should_make) {
return OptionalInt(value);
} else {
return base::nullopt;
}
}
} // namespace
TEST(OptionalTest, OptionalCanBeReturnedFromFunction) {
OptionalInt test1 = ConditionallyMakeOptional(true, 5);
ASSERT_FALSE(!test1);
EXPECT_EQ(5, test1.value());
OptionalInt test2 = ConditionallyMakeOptional(false, 5);
EXPECT_TRUE(!test2);
}