#include #include #include #include #include #include #include namespace { using testing::Eq; using testing::Ge; using testing::Gt; using testing::Le; using testing::Lt; using testing::Ne; using testing::Not; template class OptionalTest : public ::testing::Test { public: using optional = std::optional; }; template T getSampleValue(); template <> bool getSampleValue() { return true; } template <> uint64_t getSampleValue() { return 42; } template <> c10::IntArrayRef getSampleValue() { return {}; } template <> std::string getSampleValue() { return "hello"; } using OptionalTypes = ::testing::Types< // 32-bit scalar optimization. bool, // Trivially destructible but not 32-bit scalar. uint64_t, // ArrayRef optimization. c10::IntArrayRef, // Non-trivial destructor. std::string>; TYPED_TEST_SUITE(OptionalTest, OptionalTypes); TYPED_TEST(OptionalTest, Empty) { typename TestFixture::optional empty; EXPECT_FALSE((bool)empty); EXPECT_FALSE(empty.has_value()); // NOLINTNEXTLINE(bugprone-unchecked-optional-access,hicpp-avoid-goto,cppcoreguidelines-avoid-goto) EXPECT_THROW(empty.value(), std::bad_optional_access); } TYPED_TEST(OptionalTest, Initialized) { using optional = typename TestFixture::optional; const auto val = getSampleValue(); optional opt((val)); auto copy(opt), moveFrom1(opt), moveFrom2(opt); optional move(std::move(moveFrom1)); optional copyAssign; copyAssign = opt; optional moveAssign; moveAssign = std::move(moveFrom2); std::array opts = { &opt, ©, ©Assign, &move, &moveAssign}; for (auto* popt : opts) { auto& opt = *popt; EXPECT_TRUE((bool)opt); EXPECT_TRUE(opt.has_value()); // NOLINTNEXTLINE(bugprone-unchecked-optional-access) EXPECT_EQ(opt.value(), val); // NOLINTNEXTLINE(bugprone-unchecked-optional-access) EXPECT_EQ(*opt, val); } } class SelfCompareTest : public testing::TestWithParam> {}; TEST_P(SelfCompareTest, SelfCompare) { std::optional x = GetParam(); EXPECT_THAT(x, Eq(x)); EXPECT_THAT(x, Le(x)); EXPECT_THAT(x, Ge(x)); EXPECT_THAT(x, Not(Ne(x))); EXPECT_THAT(x, Not(Lt(x))); EXPECT_THAT(x, Not(Gt(x))); } INSTANTIATE_TEST_SUITE_P( nullopt, SelfCompareTest, testing::Values(std::nullopt)); INSTANTIATE_TEST_SUITE_P( int, SelfCompareTest, testing::Values(std::make_optional(2))); TEST(OptionalTest, Nullopt) { std::optional x = 2; EXPECT_THAT(std::nullopt, Not(Eq(x))); EXPECT_THAT(x, Not(Eq(std::nullopt))); EXPECT_THAT(x, Ne(std::nullopt)); EXPECT_THAT(std::nullopt, Ne(x)); EXPECT_THAT(x, Not(Lt(std::nullopt))); EXPECT_THAT(std::nullopt, Lt(x)); EXPECT_THAT(x, Not(Le(std::nullopt))); EXPECT_THAT(std::nullopt, Le(x)); EXPECT_THAT(x, Gt(std::nullopt)); EXPECT_THAT(std::nullopt, Not(Gt(x))); EXPECT_THAT(x, Ge(std::nullopt)); EXPECT_THAT(std::nullopt, Not(Ge(x))); } // Ensure comparisons work... using CmpTestTypes = testing::Types< // between two optionals std::pair, std::optional>, // between an optional and a value std::pair, int>, // between a value and an optional std::pair>, // between an optional and a differently typed value std::pair, long>, // between a differently typed value and an optional std::pair>>; template class CmpTest : public testing::Test {}; TYPED_TEST_SUITE(CmpTest, CmpTestTypes); TYPED_TEST(CmpTest, Cmp) { TypeParam pair = {2, 3}; auto x = pair.first; auto y = pair.second; EXPECT_THAT(x, Not(Eq(y))); EXPECT_THAT(x, Ne(y)); EXPECT_THAT(x, Lt(y)); EXPECT_THAT(y, Not(Lt(x))); EXPECT_THAT(x, Le(y)); EXPECT_THAT(y, Not(Le(x))); EXPECT_THAT(x, Not(Gt(y))); EXPECT_THAT(y, Gt(x)); EXPECT_THAT(x, Not(Ge(y))); EXPECT_THAT(y, Ge(x)); } } // namespace