1#include <c10/util/Optional.h>
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5
6#include <array>
7#include <cstdint>
8#include <string>
9
10namespace {
11
12using testing::Eq;
13using testing::Ge;
14using testing::Gt;
15using testing::Le;
16using testing::Lt;
17using testing::Ne;
18using testing::Not;
19
20template <typename T>
21class OptionalTest : public ::testing::Test {
22 public:
23 using optional = c10::optional<T>;
24};
25
26template <typename T>
27T getSampleValue();
28
29template <>
30bool getSampleValue() {
31 return true;
32}
33
34template <>
35uint64_t getSampleValue() {
36 return 42;
37}
38
39template <>
40c10::IntArrayRef getSampleValue() {
41 return {};
42}
43
44template <>
45std::string getSampleValue() {
46 return "hello";
47}
48
49using OptionalTypes = ::testing::Types<
50 // 32-bit scalar optimization.
51 bool,
52 // Trivially destructible but not 32-bit scalar.
53 uint64_t,
54 // ArrayRef optimization.
55 c10::IntArrayRef,
56 // Non-trivial destructor.
57 std::string>;
58
59// This assert is also in Optional.cpp; including here too to make it
60// more likely that we'll remember to port this optimization over when
61// we move to std::optional.
62static_assert(
63 sizeof(c10::optional<c10::IntArrayRef>) == sizeof(c10::IntArrayRef),
64 "c10::optional<IntArrayRef> should be size-optimized");
65
66TYPED_TEST_CASE(OptionalTest, OptionalTypes);
67
68TYPED_TEST(OptionalTest, Empty) {
69 typename TestFixture::optional empty;
70
71 EXPECT_FALSE((bool)empty);
72 EXPECT_FALSE(empty.has_value());
73
74 // NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
75 EXPECT_THROW(empty.value(), c10::bad_optional_access);
76}
77
78TYPED_TEST(OptionalTest, Initialized) {
79 using optional = typename TestFixture::optional;
80
81 const auto val = getSampleValue<TypeParam>();
82 optional opt((val));
83 auto copy(opt), moveFrom1(opt), moveFrom2(opt);
84 optional move(std::move(moveFrom1));
85 optional copyAssign;
86 copyAssign = opt;
87 optional moveAssign;
88 moveAssign = std::move(moveFrom2);
89
90 std::array<typename TestFixture::optional*, 5> opts = {
91 &opt, &copy, &copyAssign, &move, &moveAssign};
92 for (auto* popt : opts) {
93 auto& opt = *popt;
94 EXPECT_TRUE((bool)opt);
95 EXPECT_TRUE(opt.has_value());
96
97 EXPECT_EQ(opt.value(), val);
98 EXPECT_EQ(*opt, val);
99 }
100}
101
102class SelfCompareTest : public testing::TestWithParam<c10::optional<int>> {};
103
104TEST_P(SelfCompareTest, SelfCompare) {
105 c10::optional<int> x = GetParam();
106 EXPECT_THAT(x, Eq(x));
107 EXPECT_THAT(x, Le(x));
108 EXPECT_THAT(x, Ge(x));
109 EXPECT_THAT(x, Not(Ne(x)));
110 EXPECT_THAT(x, Not(Lt(x)));
111 EXPECT_THAT(x, Not(Gt(x)));
112}
113
114INSTANTIATE_TEST_CASE_P(
115 nullopt,
116 SelfCompareTest,
117 testing::Values(c10::nullopt));
118INSTANTIATE_TEST_CASE_P(
119 int,
120 SelfCompareTest,
121 testing::Values(c10::make_optional(2)));
122
123TEST(OptionalTest, Nullopt) {
124 c10::optional<int> x = 2;
125
126 EXPECT_THAT(c10::nullopt, Not(Eq(x)));
127 EXPECT_THAT(x, Not(Eq(c10::nullopt)));
128
129 EXPECT_THAT(x, Ne(c10::nullopt));
130 EXPECT_THAT(c10::nullopt, Ne(x));
131
132 EXPECT_THAT(x, Not(Lt(c10::nullopt)));
133 EXPECT_THAT(c10::nullopt, Lt(x));
134
135 EXPECT_THAT(x, Not(Le(c10::nullopt)));
136 EXPECT_THAT(c10::nullopt, Le(x));
137
138 EXPECT_THAT(x, Gt(c10::nullopt));
139 EXPECT_THAT(c10::nullopt, Not(Gt(x)));
140
141 EXPECT_THAT(x, Ge(c10::nullopt));
142 EXPECT_THAT(c10::nullopt, Not(Ge(x)));
143}
144
145// Ensure comparisons work...
146using CmpTestTypes = testing::Types<
147 // between two optionals
148 std::pair<c10::optional<int>, c10::optional<int>>,
149
150 // between an optional and a value
151 std::pair<c10::optional<int>, int>,
152 // between a value and an optional
153 std::pair<int, c10::optional<int>>,
154
155 // between an optional and a differently typed value
156 std::pair<c10::optional<int>, long>,
157 // between a differently typed value and an optional
158 std::pair<long, c10::optional<int>>>;
159template <typename T>
160class CmpTest : public testing::Test {};
161TYPED_TEST_CASE(CmpTest, CmpTestTypes);
162
163TYPED_TEST(CmpTest, Cmp) {
164 TypeParam pair = {2, 3};
165 auto x = pair.first;
166 auto y = pair.second;
167
168 EXPECT_THAT(x, Not(Eq(y)));
169
170 EXPECT_THAT(x, Ne(y));
171
172 EXPECT_THAT(x, Lt(y));
173 EXPECT_THAT(y, Not(Lt(x)));
174
175 EXPECT_THAT(x, Le(y));
176 EXPECT_THAT(y, Not(Le(x)));
177
178 EXPECT_THAT(x, Not(Gt(y)));
179 EXPECT_THAT(y, Gt(x));
180
181 EXPECT_THAT(x, Not(Ge(y)));
182 EXPECT_THAT(y, Ge(x));
183}
184
185} // namespace
186