From cadc3f85a648b4b9f6efa47f564a8df0d5480c6c Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Wed, 6 Aug 2025 08:26:26 +0200 Subject: [PATCH] Tests: Run all Vector tests for FastLastAccess::Yes too --- Tests/AK/TestVector.cpp | 1260 ++++++++++++++++++++------------------- 1 file changed, 639 insertions(+), 621 deletions(-) diff --git a/Tests/AK/TestVector.cpp b/Tests/AK/TestVector.cpp index c31ae0385b7..bd5aba021d9 100644 --- a/Tests/AK/TestVector.cpp +++ b/Tests/AK/TestVector.cpp @@ -12,593 +12,6 @@ #include #include -TEST_CASE(construct) -{ - EXPECT(Vector().is_empty()); - EXPECT(Vector().size() == 0); -} - -TEST_CASE(ints) -{ - Vector ints; - ints.append(1); - ints.append(2); - ints.append(3); - EXPECT_EQ(ints.size(), 3u); - EXPECT_EQ(ints.take_last(), 3); - EXPECT_EQ(ints.size(), 2u); - EXPECT_EQ(ints.take_last(), 2); - EXPECT_EQ(ints.size(), 1u); - EXPECT_EQ(ints.take_last(), 1); - EXPECT_EQ(ints.size(), 0u); - - ints.clear(); - EXPECT_EQ(ints.size(), 0u); -} - -TEST_CASE(strings) -{ - Vector strings; - strings.append("ABC"); - strings.append("DEF"); - - int loop_counter = 0; - for (ByteString const& string : strings) { - EXPECT(!string.is_empty()); - ++loop_counter; - } - - loop_counter = 0; - for (auto& string : (const_cast const&>(strings))) { - EXPECT(!string.is_empty()); - ++loop_counter; - } - EXPECT_EQ(loop_counter, 2); -} - -TEST_CASE(conforms_to_iterator_protocol) -{ - static_assert(std::random_access_iterator::Iterator>); - static_assert(std::random_access_iterator::ConstIterator>); - static_assert(std::random_access_iterator::Iterator>); - static_assert(std::random_access_iterator::ConstIterator>); - - static_assert(std::random_access_iterator::Iterator>); - static_assert(std::random_access_iterator::ConstIterator>); - static_assert(std::random_access_iterator::Iterator>); - static_assert(std::random_access_iterator::ConstIterator>); -} - -TEST_CASE(strings_insert_ordered) -{ - Vector strings; - strings.append("abc"); - strings.append("def"); - strings.append("ghi"); - - strings.insert_before_matching("f-g"sv, [](auto& entry) { - return "f-g"sv < entry; - }); - - EXPECT_EQ(strings[0], "abc"); - EXPECT_EQ(strings[1], "def"); - EXPECT_EQ(strings[2], "f-g"); - EXPECT_EQ(strings[3], "ghi"); -} - -TEST_CASE(prepend_vector) -{ - Vector ints; - ints.append(1); - ints.append(2); - ints.append(3); - - Vector more_ints; - more_ints.append(4); - more_ints.append(5); - more_ints.append(6); - - ints.prepend(move(more_ints)); - - EXPECT_EQ(ints.size(), 6u); - EXPECT_EQ(more_ints.size(), 0u); - - EXPECT_EQ(ints[0], 4); - EXPECT_EQ(ints[1], 5); - EXPECT_EQ(ints[2], 6); - EXPECT_EQ(ints[3], 1); - EXPECT_EQ(ints[4], 2); - EXPECT_EQ(ints[5], 3); - - ints.prepend(move(more_ints)); - EXPECT_EQ(ints.size(), 6u); - EXPECT_EQ(more_ints.size(), 0u); - - more_ints.prepend(move(ints)); - EXPECT_EQ(more_ints.size(), 6u); - EXPECT_EQ(ints.size(), 0u); -} - -TEST_CASE(prepend_vector_object) -{ - struct SubObject { - SubObject(int v) - : value(v) - { - } - int value { 0 }; - }; - struct Object { - Object(NonnullOwnPtr&& a_subobject) - : subobject(move(a_subobject)) - { - } - OwnPtr subobject; - }; - - Vector objects; - objects.empend(make(1)); - objects.empend(make(2)); - objects.empend(make(3)); - - EXPECT_EQ(objects.size(), 3u); - - Vector more_objects; - more_objects.empend(make(4)); - more_objects.empend(make(5)); - more_objects.empend(make(6)); - EXPECT_EQ(more_objects.size(), 3u); - - objects.prepend(move(more_objects)); - EXPECT_EQ(more_objects.size(), 0u); - EXPECT_EQ(objects.size(), 6u); - - EXPECT_EQ(objects[0].subobject->value, 4); - EXPECT_EQ(objects[1].subobject->value, 5); - EXPECT_EQ(objects[2].subobject->value, 6); - EXPECT_EQ(objects[3].subobject->value, 1); - EXPECT_EQ(objects[4].subobject->value, 2); - EXPECT_EQ(objects[5].subobject->value, 3); -} - -TEST_CASE(vector_compare) -{ - Vector ints; - Vector same_ints; - - for (int i = 0; i < 1000; ++i) { - ints.append(i); - same_ints.append(i); - } - - EXPECT_EQ(ints.size(), 1000u); - EXPECT_EQ(ints, same_ints); - - Vector strings; - Vector same_strings; - - for (int i = 0; i < 1000; ++i) { - strings.append(ByteString::number(i)); - same_strings.append(ByteString::number(i)); - } - - EXPECT_EQ(strings.size(), 1000u); - EXPECT_EQ(strings, same_strings); -} - -TEST_CASE(grow_past_inline_capacity) -{ - auto make_vector = [] { - Vector strings; - for (int i = 0; i < 32; ++i) { - strings.append(ByteString::number(i)); - } - return strings; - }; - - auto strings = make_vector(); - - EXPECT_EQ(strings.size(), 32u); - EXPECT_EQ(strings[31], "31"); - - strings.clear(); - EXPECT_EQ(strings.size(), 0u); - EXPECT_EQ(strings.capacity(), 16u); - - strings = make_vector(); - - strings.clear_with_capacity(); - EXPECT_EQ(strings.size(), 0u); - EXPECT(strings.capacity() >= 32u); -} - -BENCHMARK_CASE(vector_append_trivial) -{ - // This should be super fast thanks to Vector using memmove. - Vector ints; - for (int i = 0; i < 1000000; ++i) { - ints.append(i); - } - for (int i = 0; i < 100; ++i) { - Vector tmp; - tmp.extend(ints); - EXPECT_EQ(tmp.size(), 1000000u); - } -} - -BENCHMARK_CASE(vector_remove_trivial) -{ - // This should be super fast thanks to Vector using memmove. - Vector ints; - for (int i = 0; i < 10000; ++i) { - ints.append(i); - } - while (!ints.is_empty()) { - ints.remove(0); - } - EXPECT_EQ(ints.size(), 0u); -} - -TEST_CASE(vector_remove) -{ - Vector ints; - ints.append(1); - ints.append(2); - ints.append(3); - ints.append(4); - ints.append(5); - - ints.remove(1); - EXPECT_EQ(ints.size(), 4u); - EXPECT_EQ(ints[0], 1); - EXPECT_EQ(ints[1], 3); - EXPECT_EQ(ints[2], 4); - EXPECT_EQ(ints[3], 5); - - ints.remove(0); - EXPECT_EQ(ints.size(), 3u); - EXPECT_EQ(ints[0], 3); - EXPECT_EQ(ints[1], 4); - EXPECT_EQ(ints[2], 5); - - ints.take_last(); - EXPECT_EQ(ints.size(), 2u); - EXPECT_EQ(ints[0], 3); - EXPECT_EQ(ints[1], 4); - - ints.take_first(); - EXPECT_EQ(ints.size(), 1u); - EXPECT_EQ(ints[0], 4); -} - -TEST_CASE(remove_all_matching) -{ - Vector ints; - - ints.append(1); - ints.append(2); - ints.append(3); - ints.append(4); - - EXPECT_EQ(ints.size(), 4u); - - EXPECT_EQ(ints.remove_all_matching([&](int value) { return value > 2; }), true); - EXPECT_EQ(ints.remove_all_matching([&](int) { return false; }), false); - - EXPECT_EQ(ints.size(), 2u); - - EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), true); - - EXPECT(ints.is_empty()); - - EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), false); -} - -TEST_CASE(nonnullownptrvector) -{ - struct Object { - ByteString string; - }; - Vector> objects; - - objects.append(make()); - EXPECT_EQ(objects.size(), 1u); - - OwnPtr o = make(); - objects.append(o.release_nonnull()); - EXPECT(o == nullptr); - EXPECT_EQ(objects.size(), 2u); -} - -TEST_CASE(insert_trivial) -{ - Vector ints; - ints.append(0); - ints.append(10); - ints.append(20); - ints.append(30); - ints.append(40); - ints.insert(2, 15); - EXPECT_EQ(ints.size(), 6u); - EXPECT_EQ(ints[0], 0); - EXPECT_EQ(ints[1], 10); - EXPECT_EQ(ints[2], 15); - EXPECT_EQ(ints[3], 20); - EXPECT_EQ(ints[4], 30); - EXPECT_EQ(ints[5], 40); -} - -TEST_CASE(resize_initializes) -{ - struct A { - A() { initialized = true; } - bool initialized { false }; - }; - - Vector ints; - ints.resize(32); - - for (size_t idx = 0; idx < 32; ++idx) - EXPECT(ints[idx].initialized); -} - -TEST_CASE(should_compare_vectors_of_same_type) -{ - Vector a {}; - Vector b {}; - - EXPECT(a == b); - EXPECT(!(a != b)); - - a.append(1); - EXPECT(!(a == b)); - EXPECT(a != b); - - b.append(1); - EXPECT(a == b); - EXPECT(!(a != b)); - - a.append(42); - b.append(17); - EXPECT(!(a == b)); - EXPECT(a != b); -} - -TEST_CASE(should_compare_vectors_of_different_inline_capacity) -{ - Vector a {}; - Vector b {}; - - EXPECT(a == b); - EXPECT(!(a != b)); - - a.append(1); - EXPECT(!(a == b)); - EXPECT(a != b); - - b.append(1); - EXPECT(a == b); - EXPECT(!(a != b)); - - a.append(42); - b.append(17); - EXPECT(!(a == b)); - EXPECT(a != b); -} - -TEST_CASE(should_compare_vectors_of_different_sizes) -{ - Vector a {}; - Vector b {}; - - EXPECT(a == b); - EXPECT(!(a != b)); - - // A is longer - a.append(1); - EXPECT(!(a == b)); - EXPECT(a != b); - - b.append(1); - EXPECT(a == b); - EXPECT(!(a != b)); - - // B is longer - b.append(42); - EXPECT(!(a == b)); - EXPECT(a != b); -} - -TEST_CASE(should_find_value) -{ - Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; - - auto const expected = v.begin() + 4; - - EXPECT_EQ(expected, v.find(0)); -} - -TEST_CASE(should_find_predicate) -{ - Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; - - auto const expected = v.begin() + 4; - - EXPECT_EQ(expected, v.find_if([](auto const v) { return v == 0; })); -} - -TEST_CASE(should_find_index) -{ - Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; - - EXPECT_EQ(4u, v.find_first_index(0).value()); - EXPECT(!v.find_first_index(42).has_value()); -} - -TEST_CASE(should_find_predicate_index) -{ - Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; - - EXPECT_EQ(4u, v.find_first_index_if([](auto const v) { return v == 0; }).value()); - EXPECT(!v.find_first_index_if([](auto const v) { return v == 123; }).has_value()); -} - -TEST_CASE(should_find_using_a_hashcompatible_value) -{ - // Tests whether a hash-compatible value can be used to compare (Strings cannot be impliticly constructed from a StringView.) - Vector v { "hello!"_string }; - EXPECT(v.contains_slow("hello!"sv)); -} - -TEST_CASE(should_contain_start) -{ - // Tests whether value is found if at the start of the range. - Vector v { 1, 2, 3, 4, 5 }; - - EXPECT(v.contains_in_range(1, 0, 4)); -} - -TEST_CASE(should_contain_end) -{ - // Tests whether value is found if at the end of the range. - Vector v { 1, 2, 3, 4, 5 }; - - EXPECT(v.contains_in_range(5, 0, 4)); -} - -TEST_CASE(should_contain_range) -{ - // Tests whether value is found within a range. - Vector v { 1, 2, 3, 4, 5 }; - - EXPECT(v.contains_in_range(3, 0, 4)); -} - -TEST_CASE(should_not_contain_not_present) -{ - // Tests whether a value that is not present is not found, as expected. - Vector v { 1, 2, 3, 4, 5 }; - - EXPECT(!v.contains_in_range(6, 0, 4)); -} - -TEST_CASE(should_not_contain_present_not_in_range) -{ - // Tests whether a value that is present, but not in range, is not found. - Vector v { 1, 2, 3, 4, 5 }; - - EXPECT(!v.contains_in_range(2, 2, 4)); -} - -TEST_CASE(can_store_references) -{ - int my_integer = 42; - Vector references; - references.append(my_integer); - references.prepend(my_integer); - EXPECT_EQ(&references.first(), &references.last()); - - { - Vector other_references; - other_references.extend(references); - EXPECT_EQ(&other_references.first(), &my_integer); - } - - { - Vector other_references; - other_references = references; - EXPECT_EQ(&other_references.first(), &my_integer); - } - - { - auto it = references.find(my_integer); - EXPECT(!it.is_end()); - EXPECT_EQ(*it, my_integer); - } - - { - int other_integer = 42; - auto index = references.find_first_index(other_integer); - EXPECT(index.has_value()); - EXPECT_EQ(index.value_or(99999u), 0u); - } - - { - auto integer = 42; - EXPECT(references.contains_slow(integer)); - } - - { - references.remove(0); - references.ensure_capacity(10); - EXPECT_EQ(&references.take_first(), &my_integer); - } -} - -TEST_CASE(reference_deletion_should_not_affect_object) -{ - size_t times_deleted = 0; - struct DeleteCounter { - explicit DeleteCounter(size_t& deleted) - : deleted(deleted) - { - } - - ~DeleteCounter() - { - ++deleted; - } - - size_t& deleted; - }; - - { - DeleteCounter counter { times_deleted }; - Vector references; - for (size_t i = 0; i < 16; ++i) - references.append(counter); - } - EXPECT_EQ(times_deleted, 1u); -} - -TEST_CASE(rbegin) -{ - Vector v { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; - - auto const expected = v.begin() + 4; - auto const expected_in_reverse = v.rbegin() + 4; - EXPECT_EQ(*expected, *expected_in_reverse); -} - -TEST_CASE(rend) -{ - Vector v { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; - - auto const expected = v.end() - 5; - auto const expected_in_reverse = v.rend() - 5; - EXPECT_EQ(*expected, *expected_in_reverse); -} - -TEST_CASE(reverse_iterator_for_loop) -{ - Vector v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - int index = 9; - for (auto rev = v.rbegin(); rev != v.rend(); ++rev) - EXPECT_EQ(*rev, index--); -} - -TEST_CASE(reverse_range_for_loop) -{ - Vector v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - int index = 9; - for (auto item : AK::ReverseWrapper::in_reverse(v)) - EXPECT_EQ(item, index--); - - index = 9; - for (auto item : v.in_reverse()) - EXPECT_EQ(item, index--); -} - static bool is_inline_element(auto& el, auto& vector) { uintptr_t vector_ptr = (uintptr_t)&vector; @@ -606,40 +19,645 @@ static bool is_inline_element(auto& el, auto& vector) return (element_ptr >= vector_ptr && element_ptr < (vector_ptr + sizeof(vector))); } -TEST_CASE(uses_inline_capacity_when_appended_to) +#define DECLARE_TESTS_FOR_VEC(Vector) \ + TEST_CASE(Vector##_construct) \ + { \ + EXPECT(Vector().is_empty()); \ + EXPECT(Vector().size() == 0); \ + } \ + \ + TEST_CASE(Vector##_ints) \ + { \ + Vector ints; \ + ints.append(1); \ + ints.append(2); \ + ints.append(3); \ + EXPECT_EQ(ints.size(), 3u); \ + EXPECT_EQ(ints.take_last(), 3); \ + EXPECT_EQ(ints.size(), 2u); \ + EXPECT_EQ(ints.take_last(), 2); \ + EXPECT_EQ(ints.size(), 1u); \ + EXPECT_EQ(ints.take_last(), 1); \ + EXPECT_EQ(ints.size(), 0u); \ + \ + ints.clear(); \ + EXPECT_EQ(ints.size(), 0u); \ + } \ + \ + TEST_CASE(Vector##_strings) \ + { \ + Vector strings; \ + strings.append("ABC"); \ + strings.append("DEF"); \ + \ + int loop_counter = 0; \ + for (ByteString const& string : strings) { \ + EXPECT(!string.is_empty()); \ + ++loop_counter; \ + } \ + \ + loop_counter = 0; \ + for (auto& string : (const_cast const&>(strings))) { \ + EXPECT(!string.is_empty()); \ + ++loop_counter; \ + } \ + EXPECT_EQ(loop_counter, 2); \ + } \ + \ + TEST_CASE(Vector##_conforms_to_iterator_protocol) \ + { \ + static_assert(std::random_access_iterator::Iterator>); \ + static_assert(std::random_access_iterator::ConstIterator>); \ + static_assert(std::random_access_iterator::Iterator>); \ + static_assert(std::random_access_iterator::ConstIterator>); \ + \ + static_assert(std::random_access_iterator::Iterator>); \ + static_assert(std::random_access_iterator::ConstIterator>); \ + static_assert(std::random_access_iterator::Iterator>); \ + static_assert(std::random_access_iterator::ConstIterator>); \ + } \ + \ + TEST_CASE(Vector##_strings_insert_ordered) \ + { \ + Vector strings; \ + strings.append("abc"); \ + strings.append("def"); \ + strings.append("ghi"); \ + \ + strings.insert_before_matching("f-g"sv, [](auto& entry) { \ + return "f-g"sv < entry; \ + }); \ + \ + EXPECT_EQ(strings[0], "abc"); \ + EXPECT_EQ(strings[1], "def"); \ + EXPECT_EQ(strings[2], "f-g"); \ + EXPECT_EQ(strings[3], "ghi"); \ + } \ + \ + TEST_CASE(Vector##_prepend_vector) \ + { \ + Vector ints; \ + ints.append(1); \ + ints.append(2); \ + ints.append(3); \ + \ + Vector more_ints; \ + more_ints.append(4); \ + more_ints.append(5); \ + more_ints.append(6); \ + \ + ints.prepend(move(more_ints)); \ + \ + EXPECT_EQ(ints.size(), 6u); \ + EXPECT_EQ(more_ints.size(), 0u); \ + \ + EXPECT_EQ(ints[0], 4); \ + EXPECT_EQ(ints[1], 5); \ + EXPECT_EQ(ints[2], 6); \ + EXPECT_EQ(ints[3], 1); \ + EXPECT_EQ(ints[4], 2); \ + EXPECT_EQ(ints[5], 3); \ + \ + ints.prepend(move(more_ints)); \ + EXPECT_EQ(ints.size(), 6u); \ + EXPECT_EQ(more_ints.size(), 0u); \ + \ + more_ints.prepend(move(ints)); \ + EXPECT_EQ(more_ints.size(), 6u); \ + EXPECT_EQ(ints.size(), 0u); \ + } \ + \ + TEST_CASE(Vector##_prepend_vector_object) \ + { \ + struct SubObject { \ + SubObject(int v) \ + : value(v) \ + { \ + } \ + int value { 0 }; \ + }; \ + struct Object { \ + Object(NonnullOwnPtr&& a_subobject) \ + : subobject(move(a_subobject)) \ + { \ + } \ + OwnPtr subobject; \ + }; \ + \ + Vector objects; \ + objects.empend(make(1)); \ + objects.empend(make(2)); \ + objects.empend(make(3)); \ + \ + EXPECT_EQ(objects.size(), 3u); \ + \ + Vector more_objects; \ + more_objects.empend(make(4)); \ + more_objects.empend(make(5)); \ + more_objects.empend(make(6)); \ + EXPECT_EQ(more_objects.size(), 3u); \ + \ + objects.prepend(move(more_objects)); \ + EXPECT_EQ(more_objects.size(), 0u); \ + EXPECT_EQ(objects.size(), 6u); \ + \ + EXPECT_EQ(objects[0].subobject->value, 4); \ + EXPECT_EQ(objects[1].subobject->value, 5); \ + EXPECT_EQ(objects[2].subobject->value, 6); \ + EXPECT_EQ(objects[3].subobject->value, 1); \ + EXPECT_EQ(objects[4].subobject->value, 2); \ + EXPECT_EQ(objects[5].subobject->value, 3); \ + } \ + \ + TEST_CASE(Vector##_vector_compare) \ + { \ + Vector ints; \ + Vector same_ints; \ + \ + for (int i = 0; i < 1000; ++i) { \ + ints.append(i); \ + same_ints.append(i); \ + } \ + \ + EXPECT_EQ(ints.size(), 1000u); \ + EXPECT_EQ(ints, same_ints); \ + \ + Vector strings; \ + Vector same_strings; \ + \ + for (int i = 0; i < 1000; ++i) { \ + strings.append(ByteString::number(i)); \ + same_strings.append(ByteString::number(i)); \ + } \ + \ + EXPECT_EQ(strings.size(), 1000u); \ + EXPECT_EQ(strings, same_strings); \ + } \ + \ + TEST_CASE(Vector##_grow_past_inline_capacity) \ + { \ + auto make_vector = [] { \ + Vector strings; \ + for (int i = 0; i < 32; ++i) { \ + strings.append(ByteString::number(i)); \ + } \ + return strings; \ + }; \ + \ + auto strings = make_vector(); \ + \ + EXPECT_EQ(strings.size(), 32u); \ + EXPECT_EQ(strings[31], "31"); \ + \ + strings.clear(); \ + EXPECT_EQ(strings.size(), 0u); \ + EXPECT_EQ(strings.capacity(), 16u); \ + \ + strings = make_vector(); \ + \ + strings.clear_with_capacity(); \ + EXPECT_EQ(strings.size(), 0u); \ + EXPECT(strings.capacity() >= 32u); \ + } \ + \ + BENCHMARK_CASE(Vector##_append_trivial) \ + { \ + /* This should be super fast thanks to Vector using memmove. */ \ + Vector ints; \ + for (int i = 0; i < 1000000; ++i) { \ + ints.append(i); \ + } \ + for (int i = 0; i < 100; ++i) { \ + Vector tmp; \ + tmp.extend(ints); \ + EXPECT_EQ(tmp.size(), 1000000u); \ + } \ + } \ + \ + BENCHMARK_CASE(Vector##_remove_trivial) \ + { \ + /* This should be super fast thanks to Vector using memmove. */ \ + Vector ints; \ + for (int i = 0; i < 10000; ++i) { \ + ints.append(i); \ + } \ + while (!ints.is_empty()) { \ + ints.remove(0); \ + } \ + EXPECT_EQ(ints.size(), 0u); \ + } \ + \ + TEST_CASE(Vector##_vector_remove) \ + { \ + Vector ints; \ + ints.append(1); \ + ints.append(2); \ + ints.append(3); \ + ints.append(4); \ + ints.append(5); \ + \ + ints.remove(1); \ + EXPECT_EQ(ints.size(), 4u); \ + EXPECT_EQ(ints[0], 1); \ + EXPECT_EQ(ints[1], 3); \ + EXPECT_EQ(ints[2], 4); \ + EXPECT_EQ(ints[3], 5); \ + \ + ints.remove(0); \ + EXPECT_EQ(ints.size(), 3u); \ + EXPECT_EQ(ints[0], 3); \ + EXPECT_EQ(ints[1], 4); \ + EXPECT_EQ(ints[2], 5); \ + \ + ints.take_last(); \ + EXPECT_EQ(ints.size(), 2u); \ + EXPECT_EQ(ints[0], 3); \ + EXPECT_EQ(ints[1], 4); \ + \ + ints.take_first(); \ + EXPECT_EQ(ints.size(), 1u); \ + EXPECT_EQ(ints[0], 4); \ + } \ + \ + TEST_CASE(Vector##_remove_all_matching) \ + { \ + Vector ints; \ + \ + ints.append(1); \ + ints.append(2); \ + ints.append(3); \ + ints.append(4); \ + \ + EXPECT_EQ(ints.size(), 4u); \ + \ + EXPECT_EQ(ints.remove_all_matching([&](int value) { return value > 2; }), true); \ + EXPECT_EQ(ints.remove_all_matching([&](int) { return false; }), false); \ + \ + EXPECT_EQ(ints.size(), 2u); \ + \ + EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), true); \ + \ + EXPECT(ints.is_empty()); \ + \ + EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), false); \ + } \ + \ + TEST_CASE(Vector##_nonnullownptrvector) \ + { \ + struct Object { \ + ByteString string; \ + }; \ + Vector> objects; \ + \ + objects.append(make()); \ + EXPECT_EQ(objects.size(), 1u); \ + \ + OwnPtr o = make(); \ + objects.append(o.release_nonnull()); \ + EXPECT(o == nullptr); \ + EXPECT_EQ(objects.size(), 2u); \ + } \ + \ + TEST_CASE(Vector##_insert_trivial) \ + { \ + Vector ints; \ + ints.append(0); \ + ints.append(10); \ + ints.append(20); \ + ints.append(30); \ + ints.append(40); \ + ints.insert(2, 15); \ + EXPECT_EQ(ints.size(), 6u); \ + EXPECT_EQ(ints[0], 0); \ + EXPECT_EQ(ints[1], 10); \ + EXPECT_EQ(ints[2], 15); \ + EXPECT_EQ(ints[3], 20); \ + EXPECT_EQ(ints[4], 30); \ + EXPECT_EQ(ints[5], 40); \ + } \ + \ + TEST_CASE(Vector##_resize_initializes) \ + { \ + struct A { \ + A() { initialized = true; } \ + bool initialized { false }; \ + }; \ + \ + Vector ints; \ + ints.resize(32); \ + \ + for (size_t idx = 0; idx < 32; ++idx) \ + EXPECT(ints[idx].initialized); \ + } \ + \ + TEST_CASE(Vector##_should_compare_vectors_of_same_type) \ + { \ + Vector a {}; \ + Vector b {}; \ + \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + a.append(1); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + \ + b.append(1); \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + a.append(42); \ + b.append(17); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + } \ + \ + TEST_CASE(Vector##_should_compare_vectors_of_different_inline_capacity) \ + { \ + Vector a {}; \ + Vector b {}; \ + \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + a.append(1); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + \ + b.append(1); \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + a.append(42); \ + b.append(17); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + } \ + \ + TEST_CASE(Vector##_should_compare_vectors_of_different_sizes) \ + { \ + Vector a {}; \ + Vector b {}; \ + \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + /* A is longer */ \ + a.append(1); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + \ + b.append(1); \ + EXPECT(a == b); \ + EXPECT(!(a != b)); \ + \ + /* B is longer */ \ + b.append(42); \ + EXPECT(!(a == b)); \ + EXPECT(a != b); \ + } \ + \ + TEST_CASE(Vector##_should_find_value) \ + { \ + Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; \ + \ + auto const expected = v.begin() + 4; \ + \ + EXPECT_EQ(expected, v.find(0)); \ + } \ + \ + TEST_CASE(Vector##_should_find_predicate) \ + { \ + Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; \ + \ + auto const expected = v.begin() + 4; \ + \ + EXPECT_EQ(expected, v.find_if([](auto const v) { return v == 0; })); \ + } \ + \ + TEST_CASE(Vector##_should_find_index) \ + { \ + Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; \ + \ + EXPECT_EQ(4u, v.find_first_index(0).value()); \ + EXPECT(!v.find_first_index(42).has_value()); \ + } \ + \ + TEST_CASE(Vector##_should_find_predicate_index) \ + { \ + Vector v { 1, 2, 3, 4, 0, 6, 7, 8, 0, 0 }; \ + \ + EXPECT_EQ(4u, v.find_first_index_if([](auto const v) { return v == 0; }).value()); \ + EXPECT(!v.find_first_index_if([](auto const v) { return v == 123; }).has_value()); \ + } \ + \ + TEST_CASE(Vector##_should_find_using_a_hashcompatible_value) \ + { \ + /* Tests whether a hash-compatible value can be used to compare (Strings cannot be implicitly constructed from a StringView.) */ \ + Vector v { "hello!"_string }; \ + EXPECT(v.contains_slow("hello!"sv)); \ + } \ + \ + TEST_CASE(Vector##_should_contain_start) \ + { \ + /* Tests whether value is found if at the start of the range. */ \ + Vector v { 1, 2, 3, 4, 5 }; \ + \ + EXPECT(v.contains_in_range(1, 0, 4)); \ + } \ + \ + TEST_CASE(Vector##_should_contain_end) \ + { \ + /* Tests whether value is found if at the end of the range. */ \ + Vector v { 1, 2, 3, 4, 5 }; \ + \ + EXPECT(v.contains_in_range(5, 0, 4)); \ + } \ + \ + TEST_CASE(Vector##_should_contain_range) \ + { \ + /* Tests whether value is found within a range. */ \ + Vector v { 1, 2, 3, 4, 5 }; \ + \ + EXPECT(v.contains_in_range(3, 0, 4)); \ + } \ + \ + TEST_CASE(Vector##_should_not_contain_not_present) \ + { \ + /* Tests whether a value that is not present is not found, as expected.*/ \ + Vector v { 1, 2, 3, 4, 5 }; \ + \ + EXPECT(!v.contains_in_range(6, 0, 4)); \ + } \ + \ + TEST_CASE(Vector##_should_not_contain_present_not_in_range) \ + { \ + /* Tests whether a value that is present, but not in range, is not found.*/ \ + Vector v { 1, 2, 3, 4, 5 }; \ + \ + EXPECT(!v.contains_in_range(2, 2, 4)); \ + } \ + \ + TEST_CASE(Vector##_can_store_references) \ + { \ + int my_integer = 42; \ + Vector references; \ + references.append(my_integer); \ + references.prepend(my_integer); \ + EXPECT_EQ(&references.first(), &references.last()); \ + \ + { \ + Vector other_references; \ + other_references.extend(references); \ + EXPECT_EQ(&other_references.first(), &my_integer); \ + } \ + \ + { \ + Vector other_references; \ + other_references = references; \ + EXPECT_EQ(&other_references.first(), &my_integer); \ + } \ + \ + { \ + auto it = references.find(my_integer); \ + EXPECT(!it.is_end()); \ + EXPECT_EQ(*it, my_integer); \ + } \ + \ + { \ + int other_integer = 42; \ + auto index = references.find_first_index(other_integer); \ + EXPECT(index.has_value()); \ + EXPECT_EQ(index.value_or(99999u), 0u); \ + } \ + \ + { \ + auto integer = 42; \ + EXPECT(references.contains_slow(integer)); \ + } \ + \ + { \ + references.remove(0); \ + references.ensure_capacity(10); \ + EXPECT_EQ(&references.take_first(), &my_integer); \ + } \ + } \ + \ + TEST_CASE(Vector##_reference_deletion_should_not_affect_object) \ + { \ + size_t times_deleted = 0; \ + struct DeleteCounter { \ + explicit DeleteCounter(size_t& deleted) \ + : deleted(deleted) \ + { \ + } \ + \ + ~DeleteCounter() \ + { \ + ++deleted; \ + } \ + \ + size_t& deleted; \ + }; \ + \ + { \ + DeleteCounter counter { times_deleted }; \ + Vector references; \ + for (size_t i = 0; i < 16; ++i) \ + references.append(counter); \ + } \ + EXPECT_EQ(times_deleted, 1u); \ + } \ + \ + TEST_CASE(Vector##_rbegin) \ + { \ + Vector v { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; \ + \ + auto const expected = v.begin() + 4; \ + auto const expected_in_reverse = v.rbegin() + 4; \ + EXPECT_EQ(*expected, *expected_in_reverse); \ + } \ + \ + TEST_CASE(Vector##_rend) \ + { \ + Vector v { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; \ + \ + auto const expected = v.end() - 5; \ + auto const expected_in_reverse = v.rend() - 5; \ + EXPECT_EQ(*expected, *expected_in_reverse); \ + } \ + \ + TEST_CASE(Vector##_reverse_iterator_for_loop) \ + { \ + Vector v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; \ + int index = 9; \ + for (auto rev = v.rbegin(); rev != v.rend(); ++rev) \ + EXPECT_EQ(*rev, index--); \ + } \ + \ + TEST_CASE(Vector##_reverse_range_for_loop) \ + { \ + Vector v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; \ + int index = 9; \ + for (auto item : AK::ReverseWrapper::in_reverse(v)) \ + EXPECT_EQ(item, index--); \ + \ + index = 9; \ + for (auto item : v.in_reverse()) \ + EXPECT_EQ(item, index--); \ + } \ + \ + TEST_CASE(Vector##_uses_inline_capacity_when_appended_to) \ + { \ + Vector v; \ + v.unchecked_append(1); \ + v.unchecked_append(123); \ + v.unchecked_append(50); \ + v.unchecked_append(43); \ + \ + for (auto& el : v) \ + EXPECT(is_inline_element(el, v)); \ + } \ + \ + TEST_CASE(Vector##_uses_inline_capacity_when_constructed_from_initializer_list) \ + { \ + Vector v { 10, 9, 3, 1, 3 }; \ + \ + for (auto& el : v) \ + EXPECT(is_inline_element(el, v)); \ + } \ + \ + TEST_CASE(Vector##_uses_inline_capacity_when_constructed_from_other_vector) \ + { \ + Vector other { 4, 3, 2, 1 }; \ + Vector v(other); \ + \ + for (auto& el : v) \ + EXPECT(is_inline_element(el, v)); \ + } \ + \ + TEST_CASE(Vector##_uses_inline_capacity_when_constructed_from_span) \ + { \ + Array array { "f00", "bar", "baz" }; \ + Vector v(array.span()); \ + \ + for (auto& el : v) \ + EXPECT(is_inline_element(el, v)); \ + } + +DECLARE_TESTS_FOR_VEC(Vector) + +template +using VectorWithFastLastAccess = Vector; +DECLARE_TESTS_FOR_VEC(VectorWithFastLastAccess) + +TEST_CASE(VectorWithFastLastAccess_unsafe) { - Vector v; - v.unchecked_append(1); - v.unchecked_append(123); - v.unchecked_append(50); - v.unchecked_append(43); + VectorWithFastLastAccess v; + v.append(1); + v.append(2); - for (auto& el : v) - EXPECT(is_inline_element(el, v)); -} - -TEST_CASE(uses_inline_capacity_when_constructed_from_initializer_list) -{ - Vector v { 10, 9, 3, 1, 3 }; - - for (auto& el : v) - EXPECT(is_inline_element(el, v)); -} - -TEST_CASE(uses_inline_capacity_when_constructed_from_other_vector) -{ - Vector other { 4, 3, 2, 1 }; - Vector v(other); - - for (auto& el : v) - EXPECT(is_inline_element(el, v)); -} - -TEST_CASE(uses_inline_capacity_when_constructed_from_span) -{ - Array array { "f00", "bar", "baz" }; - Vector v(array.span()); - - for (auto& el : v) - EXPECT(is_inline_element(el, v)); + EXPECT_EQ(v.unsafe_last(), 2); + EXPECT_EQ(v.unsafe_take_last(), 2); + EXPECT_EQ(v.unsafe_last(), 1); }