/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2012-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <folly/Optional.h>
+#include <folly/Portability.h>
+#include <folly/portability/GMock.h>
+#include <folly/portability/GTest.h>
-#include <memory>
-#include <vector>
#include <algorithm>
#include <iomanip>
+#include <memory>
#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
-#include <glog/logging.h>
-#include <gtest/gtest.h>
#include <boost/optional.hpp>
using std::unique_ptr;
namespace folly {
-template<class V>
+template <class V>
std::ostream& operator<<(std::ostream& os, const Optional<V>& v) {
if (v) {
os << "Optional(" << v.value() << ')';
EXPECT_FALSE(x);
}
+TEST(Optional, Emplace) {
+ Optional<std::vector<int>> opt;
+ auto& values1 = opt.emplace(3, 4);
+ EXPECT_THAT(values1, testing::ElementsAre(4, 4, 4));
+ auto& values2 = opt.emplace(2, 5);
+ EXPECT_THAT(values2, testing::ElementsAre(5, 5));
+}
+
+TEST(Optional, EmplaceInitializerList) {
+ Optional<std::vector<int>> opt;
+ auto& values1 = opt.emplace({3, 4, 5});
+ EXPECT_THAT(values1, testing::ElementsAre(3, 4, 5));
+ auto& values2 = opt.emplace({4, 5, 6});
+ EXPECT_THAT(values2, testing::ElementsAre(4, 5, 6));
+}
+
+TEST(Optional, Reset) {
+ Optional<int> opt(3);
+ opt.reset();
+ EXPECT_FALSE(opt);
+}
+
TEST(Optional, String) {
Optional<std::string> maybeString;
EXPECT_FALSE(maybeString);
}
class MoveTester {
-public:
+ public:
/* implicit */ MoveTester(const char* s) : s_(s) {}
MoveTester(const MoveTester&) = default;
MoveTester(MoveTester&& other) noexcept {
other.s_ = "";
}
MoveTester& operator=(const MoveTester&) = default;
- MoveTester& operator=(MoveTester&&) = default;
-private:
+ MoveTester& operator=(MoveTester&& other) noexcept {
+ s_ = std::move(other.s_);
+ other.s_ = "";
+ return *this;
+ }
+
+ private:
friend bool operator==(const MoveTester& o1, const MoveTester& o2);
std::string s_;
};
EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
}
+struct ExpectingDeleter {
+ explicit ExpectingDeleter(int expected) : expected(expected) { }
+ int expected;
+ void operator()(const int* ptr) {
+ EXPECT_EQ(*ptr, expected);
+ delete ptr;
+ }
+};
+
+TEST(Optional, value_move) {
+ auto ptr = Optional<std::unique_ptr<int, ExpectingDeleter>>(
+ {new int(42), ExpectingDeleter{1337}}).value();
+ *ptr = 1337;
+}
+
+TEST(Optional, dereference_move) {
+ auto ptr = *Optional<std::unique_ptr<int, ExpectingDeleter>>(
+ {new int(42), ExpectingDeleter{1337}});
+ *ptr = 1337;
+}
+
TEST(Optional, EmptyConstruct) {
Optional<int> opt;
EXPECT_FALSE(bool(opt));
EXPECT_FALSE(bool(test2));
}
+TEST(Optional, InPlaceConstruct) {
+ using A = std::pair<int, double>;
+ Optional<A> opt(in_place, 5, 3.2);
+ EXPECT_TRUE(bool(opt));
+ EXPECT_EQ(5, opt->first);
+}
+
+TEST(Optional, InPlaceNestedConstruct) {
+ using A = std::pair<int, double>;
+ Optional<Optional<A>> opt(in_place, in_place, 5, 3.2);
+ EXPECT_TRUE(bool(opt));
+ EXPECT_TRUE(bool(*opt));
+ EXPECT_EQ(5, (*opt)->first);
+}
+
TEST(Optional, Unique) {
Optional<unique_ptr<int>> opt;
opt.clear();
// empty->moved
- opt = unique_ptr<int>(new int(6));
+ opt = std::make_unique<int>(6);
EXPECT_EQ(6, **opt);
// full->moved
- opt = unique_ptr<int>(new int(7));
+ opt = std::make_unique<int>(7);
EXPECT_EQ(7, **opt);
// move it out by move construct
EXPECT_EQ("bye", a.value());
swap(a, b);
+ EXPECT_TRUE(a.hasValue());
+ EXPECT_TRUE(b.hasValue());
+ EXPECT_EQ("hello", a.value());
+ EXPECT_EQ("bye", b.value());
}
TEST(Optional, Comparisons) {
EXPECT_FALSE(bob != false);
}
+TEST(Optional, HeterogeneousComparisons) {
+ using opt8 = Optional<uint8_t>;
+ using opt64 = Optional<uint64_t>;
+
+ EXPECT_TRUE(opt8(4) == uint64_t(4));
+ EXPECT_FALSE(opt8(8) == uint64_t(4));
+ EXPECT_FALSE(opt8() == uint64_t(4));
+
+ EXPECT_TRUE(uint64_t(4) == opt8(4));
+ EXPECT_FALSE(uint64_t(4) == opt8(8));
+ EXPECT_FALSE(uint64_t(4) == opt8());
+
+ EXPECT_FALSE(opt8(4) != uint64_t(4));
+ EXPECT_TRUE(opt8(8) != uint64_t(4));
+ EXPECT_TRUE(opt8() != uint64_t(4));
+
+ EXPECT_FALSE(uint64_t(4) != opt8(4));
+ EXPECT_TRUE(uint64_t(4) != opt8(8));
+ EXPECT_TRUE(uint64_t(4) != opt8());
+
+ EXPECT_TRUE(opt8() == opt64());
+ EXPECT_TRUE(opt8(4) == opt64(4));
+ EXPECT_FALSE(opt8(8) == opt64(4));
+ EXPECT_FALSE(opt8() == opt64(4));
+ EXPECT_FALSE(opt8(4) == opt64());
+
+ EXPECT_FALSE(opt8() != opt64());
+ EXPECT_FALSE(opt8(4) != opt64(4));
+ EXPECT_TRUE(opt8(8) != opt64(4));
+ EXPECT_TRUE(opt8() != opt64(4));
+ EXPECT_TRUE(opt8(4) != opt64());
+
+ EXPECT_TRUE(opt8() < opt64(4));
+ EXPECT_TRUE(opt8(4) < opt64(8));
+ EXPECT_FALSE(opt8() < opt64());
+ EXPECT_FALSE(opt8(4) < opt64(4));
+ EXPECT_FALSE(opt8(8) < opt64(4));
+ EXPECT_FALSE(opt8(4) < opt64());
+
+ EXPECT_FALSE(opt8() > opt64(4));
+ EXPECT_FALSE(opt8(4) > opt64(8));
+ EXPECT_FALSE(opt8() > opt64());
+ EXPECT_FALSE(opt8(4) > opt64(4));
+ EXPECT_TRUE(opt8(8) > opt64(4));
+ EXPECT_TRUE(opt8(4) > opt64());
+
+ EXPECT_TRUE(opt8() <= opt64(4));
+ EXPECT_TRUE(opt8(4) <= opt64(8));
+ EXPECT_TRUE(opt8() <= opt64());
+ EXPECT_TRUE(opt8(4) <= opt64(4));
+ EXPECT_FALSE(opt8(8) <= opt64(4));
+ EXPECT_FALSE(opt8(4) <= opt64());
+
+ EXPECT_FALSE(opt8() >= opt64(4));
+ EXPECT_FALSE(opt8(4) >= opt64(8));
+ EXPECT_TRUE(opt8() >= opt64());
+ EXPECT_TRUE(opt8(4) >= opt64(4));
+ EXPECT_TRUE(opt8(8) >= opt64(4));
+ EXPECT_TRUE(opt8(4) >= opt64());
+}
+
+TEST(Optional, NoneComparisons) {
+ using opt = Optional<int>;
+ EXPECT_TRUE(opt() == none);
+ EXPECT_TRUE(none == opt());
+ EXPECT_FALSE(opt(1) == none);
+ EXPECT_FALSE(none == opt(1));
+
+ EXPECT_FALSE(opt() != none);
+ EXPECT_FALSE(none != opt());
+ EXPECT_TRUE(opt(1) != none);
+ EXPECT_TRUE(none != opt(1));
+
+ EXPECT_FALSE(opt() < none);
+ EXPECT_FALSE(none < opt());
+ EXPECT_FALSE(opt(1) < none);
+ EXPECT_TRUE(none < opt(1));
+
+ EXPECT_FALSE(opt() > none);
+ EXPECT_FALSE(none > opt());
+ EXPECT_FALSE(none > opt(1));
+ EXPECT_TRUE(opt(1) > none);
+
+ EXPECT_TRUE(opt() <= none);
+ EXPECT_TRUE(none <= opt());
+ EXPECT_FALSE(opt(1) <= none);
+ EXPECT_TRUE(none <= opt(1));
+
+ EXPECT_TRUE(opt() >= none);
+ EXPECT_TRUE(none >= opt());
+ EXPECT_TRUE(opt(1) >= none);
+ EXPECT_FALSE(none >= opt(1));
+}
+
TEST(Optional, Conversions) {
Optional<bool> mbool;
Optional<short> mshort;
// intended explicit operator bool, for if (opt).
bool b(mbool);
+ EXPECT_FALSE(b);
// Truthy tests work and are not ambiguous
if (mbool && mshort && mstr && mint) { // only checks not-empty
EXPECT_EQ(**optIntPtr, 3);
}
+#if __CLANG_PREREQ(3, 6)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wself-move"
+#endif
+
TEST(Optional, SelfAssignment) {
Optional<int> a = 42;
a = a;
ASSERT_TRUE(b.hasValue() && b.value() == 23333333);
}
+#if __CLANG_PREREQ(3, 6)
+# pragma clang diagnostic pop
+#endif
+
class ContainsOptional {
public:
ContainsOptional() { }
}
}
+TEST(Optional, Exceptions) {
+ Optional<int> empty;
+ EXPECT_THROW(empty.value(), OptionalEmptyException);
+}
+
+TEST(Optional, NoThrowDefaultConstructible) {
+ EXPECT_TRUE(std::is_nothrow_default_constructible<Optional<bool>>::value);
+}
+
+struct NoDestructor {};
+
+struct WithDestructor {
+ ~WithDestructor();
+};
+
+TEST(Optional, TriviallyDestructible) {
+ // These could all be static_asserts but EXPECT_* give much nicer output on
+ // failure.
+ EXPECT_TRUE(std::is_trivially_destructible<Optional<NoDestructor>>::value);
+ EXPECT_TRUE(std::is_trivially_destructible<Optional<int>>::value);
+ EXPECT_FALSE(std::is_trivially_destructible<Optional<WithDestructor>>::value);
+}
+
+TEST(Optional, Hash) {
+ // Test it's usable in std::unordered map (compile time check)
+ std::unordered_map<Optional<int>, Optional<int>> obj;
+ // Also check the std::hash template can be instantiated by the compiler
+ std::hash<Optional<int>>()(none);
+ std::hash<Optional<int>>()(3);
}
+} // namespace folly