Serenity Operating System
at master 271 lines 6.8 kB view raw
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}