Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021, Daniel Bertalan <dani@danielbertalan.dev>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <LibTest/TestCase.h>
9
10#include <AK/DeprecatedString.h>
11#include <AK/Optional.h>
12#include <AK/Vector.h>
13
14TEST_CASE(basic_optional)
15{
16 Optional<int> x;
17 EXPECT_EQ(x.has_value(), false);
18 x = 3;
19 EXPECT_EQ(x.has_value(), true);
20 EXPECT_EQ(x.value(), 3);
21}
22
23TEST_CASE(move_optional)
24{
25 Optional<int> x;
26 EXPECT_EQ(x.has_value(), false);
27 x = 3;
28 EXPECT_EQ(x.has_value(), true);
29 EXPECT_EQ(x.value(), 3);
30
31 Optional<int> y;
32 y = move(x);
33 EXPECT_EQ(y.has_value(), true);
34 EXPECT_EQ(y.value(), 3);
35 EXPECT_EQ(x.has_value(), false);
36}
37
38TEST_CASE(optional_rvalue_ref_qualified_getters)
39{
40 struct DontCopyMe {
41 DontCopyMe() { }
42 ~DontCopyMe() = default;
43 DontCopyMe(DontCopyMe&&) = default;
44 DontCopyMe& operator=(DontCopyMe&&) = default;
45 DontCopyMe(DontCopyMe const&) = delete;
46 DontCopyMe& operator=(DontCopyMe const&) = delete;
47
48 int x { 13 };
49 };
50
51 auto make_an_optional = []() -> Optional<DontCopyMe> {
52 return DontCopyMe {};
53 };
54
55 EXPECT_EQ(make_an_optional().value().x, 13);
56 EXPECT_EQ(make_an_optional().value_or(DontCopyMe {}).x, 13);
57}
58
59TEST_CASE(optional_leak_1)
60{
61 struct Structure {
62 Optional<DeprecatedString> str;
63 };
64
65 // This used to leak, it does not anymore.
66 Vector<Structure> vec;
67 vec.append({ "foo" });
68 EXPECT_EQ(vec[0].str.has_value(), true);
69 EXPECT_EQ(vec[0].str.value(), "foo");
70}
71
72TEST_CASE(short_notation)
73{
74 Optional<StringView> value = "foo"sv;
75
76 EXPECT_EQ(value->length(), 3u);
77 EXPECT_EQ(*value, "foo");
78}
79
80TEST_CASE(comparison_without_values)
81{
82 Optional<StringView> opt0;
83 Optional<StringView> opt1;
84 Optional<DeprecatedString> opt2;
85 EXPECT_EQ(opt0, opt1);
86 EXPECT_EQ(opt0, opt2);
87}
88
89TEST_CASE(comparison_with_values)
90{
91 Optional<StringView> opt0;
92 Optional<StringView> opt1 = "foo"sv;
93 Optional<DeprecatedString> opt2 = "foo"sv;
94 Optional<StringView> opt3 = "bar"sv;
95 EXPECT_NE(opt0, opt1);
96 EXPECT_EQ(opt1, opt2);
97 EXPECT_NE(opt1, opt3);
98}
99
100TEST_CASE(comparison_to_underlying_types)
101{
102 Optional<DeprecatedString> opt0;
103 EXPECT_NE(opt0, DeprecatedString());
104 EXPECT_NE(opt0, "foo");
105
106 Optional<StringView> opt1 = "foo"sv;
107 EXPECT_EQ(opt1, "foo");
108 EXPECT_NE(opt1, "bar");
109 EXPECT_EQ(opt1, DeprecatedString("foo"));
110}
111
112TEST_CASE(comparison_with_numeric_types)
113{
114 Optional<u8> opt0;
115 EXPECT_NE(opt0, 0);
116 Optional<u8> opt1 = 7;
117 EXPECT_EQ(opt1, 7);
118 EXPECT_EQ(opt1, 7.0);
119 EXPECT_EQ(opt1, 7u);
120 EXPECT_NE(opt1, -2);
121}
122
123TEST_CASE(test_copy_ctor_and_dtor_called)
124{
125#ifdef AK_HAVE_CONDITIONALLY_TRIVIAL
126 static_assert(IsTriviallyDestructible<Optional<u8>>);
127 static_assert(IsTriviallyCopyable<Optional<u8>>);
128 static_assert(IsTriviallyCopyConstructible<Optional<u8>>);
129 static_assert(IsTriviallyCopyAssignable<Optional<u8>>);
130 // These can't be trivial as we have to clear the original object.
131 static_assert(!IsTriviallyMoveConstructible<Optional<u8>>);
132 static_assert(!IsTriviallyMoveAssignable<Optional<u8>>);
133#endif
134
135 struct DestructionChecker {
136 explicit DestructionChecker(bool& was_destroyed)
137 : m_was_destroyed(was_destroyed)
138 {
139 }
140
141 ~DestructionChecker()
142 {
143 m_was_destroyed = true;
144 }
145 bool& m_was_destroyed;
146 };
147
148 static_assert(!IsTriviallyDestructible<Optional<DestructionChecker>>);
149
150 bool was_destroyed = false;
151 {
152 Optional<DestructionChecker> test_optional = DestructionChecker { was_destroyed };
153 }
154 EXPECT(was_destroyed);
155
156 struct CopyChecker {
157 explicit CopyChecker(bool& was_copy_constructed)
158 : m_was_copy_constructed(was_copy_constructed)
159 {
160 }
161
162 CopyChecker(CopyChecker const& other)
163 : m_was_copy_constructed(other.m_was_copy_constructed)
164 {
165 m_was_copy_constructed = true;
166 }
167
168 bool& m_was_copy_constructed;
169 };
170
171 static_assert(IsCopyConstructible<Optional<CopyChecker>>);
172 static_assert(!IsTriviallyCopyConstructible<Optional<CopyChecker>>);
173
174 bool was_copy_constructed = false;
175 Optional<CopyChecker> copy1 = CopyChecker { was_copy_constructed };
176 Optional<CopyChecker> copy2 = copy1;
177 EXPECT(was_copy_constructed);
178
179 struct MoveChecker {
180 explicit MoveChecker(bool& was_move_constructed)
181 : m_was_move_constructed(was_move_constructed)
182 {
183 }
184
185 MoveChecker(MoveChecker const& other)
186 : m_was_move_constructed(other.m_was_move_constructed)
187 {
188 EXPECT(false);
189 };
190
191 MoveChecker(MoveChecker&& other)
192 : m_was_move_constructed(other.m_was_move_constructed)
193 {
194 m_was_move_constructed = true;
195 };
196
197 bool& m_was_move_constructed;
198 };
199 static_assert(IsMoveConstructible<Optional<MoveChecker>>);
200 static_assert(!IsTriviallyMoveConstructible<Optional<MoveChecker>>);
201
202 bool was_moved = false;
203 Optional<MoveChecker> move1 = MoveChecker { was_moved };
204 Optional<MoveChecker> move2 = move(move1);
205 EXPECT(was_moved);
206
207#ifdef AK_HAVE_CONDITIONALLY_TRIVIAL
208 struct NonDestructible {
209 ~NonDestructible() = delete;
210 };
211 static_assert(!IsDestructible<Optional<NonDestructible>>);
212#endif
213}
214
215TEST_CASE(basic_optional_reference)
216{
217 Optional<int&> x;
218 EXPECT_EQ(x.has_value(), false);
219 int a = 3;
220 x = a;
221 EXPECT_EQ(x.has_value(), true);
222 EXPECT_EQ(x.value(), 3);
223 EXPECT_EQ(&x.value(), &a);
224
225 Optional<int const&> y;
226 EXPECT_EQ(y.has_value(), false);
227 int b = 3;
228 y = b;
229 EXPECT_EQ(y.has_value(), true);
230 EXPECT_EQ(y.value(), 3);
231 EXPECT_EQ(&y.value(), &b);
232 static_assert(IsConst<RemoveReference<decltype(y.value())>>);
233}
234
235TEST_CASE(move_optional_reference)
236{
237 Optional<int&> x;
238 EXPECT_EQ(x.has_value(), false);
239 int b = 3;
240 x = b;
241 EXPECT_EQ(x.has_value(), true);
242 EXPECT_EQ(x.value(), 3);
243
244 Optional<int&> y;
245 y = move(x);
246 EXPECT_EQ(y.has_value(), true);
247 EXPECT_EQ(y.value(), 3);
248 EXPECT_EQ(x.has_value(), false);
249}
250
251TEST_CASE(short_notation_reference)
252{
253 StringView test = "foo"sv;
254 Optional<StringView&> value = test;
255
256 EXPECT_EQ(value->length(), 3u);
257 EXPECT_EQ(*value, "foo");
258}
259
260TEST_CASE(comparison_reference)
261{
262 StringView test = "foo"sv;
263 Optional<StringView&> opt0;
264 Optional<StringView const&> opt1 = test;
265 Optional<DeprecatedString> opt2 = "foo"sv;
266 Optional<StringView> opt3 = "bar"sv;
267
268 EXPECT_NE(opt0, opt1);
269 EXPECT_EQ(opt1, opt2);
270 EXPECT_NE(opt1, opt3);
271}