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