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 | |
10 | namespace { |
11 | |
12 | using testing::Eq; |
13 | using testing::Ge; |
14 | using testing::Gt; |
15 | using testing::Le; |
16 | using testing::Lt; |
17 | using testing::Ne; |
18 | using testing::Not; |
19 | |
20 | template <typename T> |
21 | class OptionalTest : public ::testing::Test { |
22 | public: |
23 | using optional = c10::optional<T>; |
24 | }; |
25 | |
26 | template <typename T> |
27 | T getSampleValue(); |
28 | |
29 | template <> |
30 | bool getSampleValue() { |
31 | return true; |
32 | } |
33 | |
34 | template <> |
35 | uint64_t getSampleValue() { |
36 | return 42; |
37 | } |
38 | |
39 | template <> |
40 | c10::IntArrayRef getSampleValue() { |
41 | return {}; |
42 | } |
43 | |
44 | template <> |
45 | std::string getSampleValue() { |
46 | return "hello" ; |
47 | } |
48 | |
49 | using 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. |
62 | static_assert( |
63 | sizeof(c10::optional<c10::IntArrayRef>) == sizeof(c10::IntArrayRef), |
64 | "c10::optional<IntArrayRef> should be size-optimized" ); |
65 | |
66 | TYPED_TEST_CASE(OptionalTest, OptionalTypes); |
67 | |
68 | TYPED_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 | |
78 | TYPED_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, ©, ©Assign, &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 | |
102 | class SelfCompareTest : public testing::TestWithParam<c10::optional<int>> {}; |
103 | |
104 | TEST_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 | |
114 | INSTANTIATE_TEST_CASE_P( |
115 | nullopt, |
116 | SelfCompareTest, |
117 | testing::Values(c10::nullopt)); |
118 | INSTANTIATE_TEST_CASE_P( |
119 | int, |
120 | SelfCompareTest, |
121 | testing::Values(c10::make_optional(2))); |
122 | |
123 | TEST(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... |
146 | using 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>>>; |
159 | template <typename T> |
160 | class CmpTest : public testing::Test {}; |
161 | TYPED_TEST_CASE(CmpTest, CmpTestTypes); |
162 | |
163 | TYPED_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 | |