[libcxx][test][NFC] Various tests for std::vector
Add missing tests for std::vector funcionality to improve code coverage:
- Rewrote access tests to check modification of the container using
the reference returned by the non-const overload
- Added tests for reverse iterators: rbegin, rend, etc.
- Added exception test for vector::reserve
- Extended test cases for vector copy assignment
- Fixed insert_iter_value.pass.cpp to use insert overload with const
value_type& (not with value_type&& which is tested in
iter_rvalue.pass.cpp test)
Reviewed By: Quuxplusone, rarutyun, #libc
Differential Revision: https://reviews.llvm.org/D112438
GitOrigin-RevId: 8c6b24899e51648286bb812d92a23a28798c53eb
diff --git a/test/std/containers/sequences/vector/access.pass.cpp b/test/std/containers/sequences/vector/access.pass.cpp
index 4ac19ff..35d93db 100644
--- a/test/std/containers/sequences/vector/access.pass.cpp
+++ b/test/std/containers/sequences/vector/access.pass.cpp
@@ -29,7 +29,7 @@
template <class C>
C
-make(int size, int start = 0)
+make(int size, int start)
{
C c;
for (int i = 0; i < size; ++i)
@@ -37,84 +37,85 @@
return c;
}
+template <class Vector>
+void test_get_basic(Vector& c, int start_value) {
+ const int n = c.size();
+ for (int i = 0; i < n; ++i)
+ assert(c[i] == start_value + i);
+ for (int i = 0; i < n; ++i)
+ assert(c.at(i) == start_value + i);
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ try {
+ c.at(n);
+ assert(false);
+ } catch (const std::out_of_range&) {}
+#endif
+
+ assert(c.front() == start_value);
+ assert(c.back() == start_value + n - 1);
+}
+
+template <class Vector>
+void test_get() {
+ int start_value = 35;
+ Vector c = make<Vector>(10, start_value);
+ const Vector& cc = c;
+ test_get_basic(c, start_value);
+ test_get_basic(cc, start_value);
+}
+
+template <class Vector>
+void test_set() {
+ int start_value = 35;
+ const int n = 10;
+ Vector c = make<Vector>(n, start_value);
+
+ for (int i = 0; i < n; ++i) {
+ assert(c[i] == start_value + i);
+ c[i] = start_value + i + 1;
+ assert(c[i] == start_value + i + 1);
+ }
+ for (int i = 0; i < n; ++i) {
+ assert(c.at(i) == start_value + i + 1);
+ c.at(i) = start_value + i + 2;
+ assert(c.at(i) == start_value + i + 2);
+ }
+
+ assert(c.front() == start_value + 2);
+ c.front() = start_value + 3;
+ assert(c.front() == start_value + 3);
+
+ assert(c.back() == start_value + n + 1);
+ c.back() = start_value + n + 2;
+ assert(c.back() == start_value + n + 2);
+}
+
+template <class Vector>
+void test() {
+ test_get<Vector>();
+ test_set<Vector>();
+
+ Vector c;
+ const Vector& cc = c;
+ ASSERT_SAME_TYPE(typename Vector::reference, decltype(c[0]));
+ ASSERT_SAME_TYPE(typename Vector::const_reference, decltype(cc[0]));
+
+ ASSERT_SAME_TYPE(typename Vector::reference, decltype(c.at(0)));
+ ASSERT_SAME_TYPE(typename Vector::const_reference, decltype(cc.at(0)));
+
+ ASSERT_SAME_TYPE(typename Vector::reference, decltype(c.front()));
+ ASSERT_SAME_TYPE(typename Vector::const_reference, decltype(cc.front()));
+
+ ASSERT_SAME_TYPE(typename Vector::reference, decltype(c.back()));
+ ASSERT_SAME_TYPE(typename Vector::const_reference, decltype(cc.back()));
+}
+
int main(int, char**)
{
- {
- typedef std::vector<int> C;
- C c = make<C>(10);
- LIBCPP_ASSERT_NOEXCEPT(c[0]);
- LIBCPP_ASSERT_NOEXCEPT(c.front());
- LIBCPP_ASSERT_NOEXCEPT(c.back());
- // at() is NOT noexcept
- ASSERT_SAME_TYPE(C::reference, decltype(c[0]));
- ASSERT_SAME_TYPE(C::reference, decltype(c.at(0)));
- ASSERT_SAME_TYPE(C::reference, decltype(c.front()));
- ASSERT_SAME_TYPE(C::reference, decltype(c.back()));
- for (int i = 0; i < 10; ++i)
- assert(c[i] == i);
- for (int i = 0; i < 10; ++i)
- assert(c.at(i) == i);
- assert(c.front() == 0);
- assert(c.back() == 9);
- }
- {
- typedef std::vector<int> C;
- const int N = 5;
- const C c = make<C>(10, N);
- LIBCPP_ASSERT_NOEXCEPT(c[0]);
- LIBCPP_ASSERT_NOEXCEPT(c.front());
- LIBCPP_ASSERT_NOEXCEPT(c.back());
- // at() is NOT noexcept
- ASSERT_SAME_TYPE(C::const_reference, decltype(c[0]));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.at(0)));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.front()));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.back()));
- for (int i = 0; i < 10; ++i)
- assert(c[i] == N + i);
- for (int i = 0; i < 10; ++i)
- assert(c.at(i) == N + i);
- assert(c.front() == N);
- assert(c.back() == N + 9);
- }
+ test<std::vector<int> >();
#if TEST_STD_VER >= 11
- {
- typedef std::vector<int, min_allocator<int>> C;
- const int N = 34;
- C c = make<C>(10, N);
- LIBCPP_ASSERT_NOEXCEPT(c[0]);
- LIBCPP_ASSERT_NOEXCEPT(c.front());
- LIBCPP_ASSERT_NOEXCEPT(c.back());
- // at() is NOT noexcept
- ASSERT_SAME_TYPE(C::reference, decltype(c[0]));
- ASSERT_SAME_TYPE(C::reference, decltype(c.at(0)));
- ASSERT_SAME_TYPE(C::reference, decltype(c.front()));
- ASSERT_SAME_TYPE(C::reference, decltype(c.back()));
- for (int i = 0; i < 10; ++i)
- assert(c[i] == N + i);
- for (int i = 0; i < 10; ++i)
- assert(c.at(i) == N + i);
- assert(c.front() == N);
- assert(c.back() == N + 9);
- }
- {
- typedef std::vector<int, min_allocator<int>> C;
- const int N = 23;
- const C c = make<C>(10, N);
- LIBCPP_ASSERT_NOEXCEPT(c[0]);
- LIBCPP_ASSERT_NOEXCEPT(c.front());
- LIBCPP_ASSERT_NOEXCEPT(c.back());
- // at() is NOT noexcept
- ASSERT_SAME_TYPE(C::const_reference, decltype(c[0]));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.at(0)));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.front()));
- ASSERT_SAME_TYPE(C::const_reference, decltype(c.back()));
- for (int i = 0; i < 10; ++i)
- assert(c[i] == N + i);
- for (int i = 0; i < 10; ++i)
- assert(c.at(i) == N + i);
- assert(c.front() == N);
- assert(c.back() == N + 9);
- }
+ test<std::vector<int, min_allocator<int> > >();
#endif
return 0;
diff --git a/test/std/containers/sequences/vector/reverse_iterators.pass.cpp b/test/std/containers/sequences/vector/reverse_iterators.pass.cpp
new file mode 100644
index 0000000..c2b5d4d
--- /dev/null
+++ b/test/std/containers/sequences/vector/reverse_iterators.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// reverse_iterator rbegin();
+// reverse_iterator rend();
+// const_reverse_iterator rbegin() const;
+// const_reverse_iterator rend() const;
+// const_reverse_iterator crbegin() const;
+// const_reverse_iterator crend() const;
+
+#include <vector>
+#include <cassert>
+#include <iterator>
+
+#include "min_allocator.h"
+
+template <class Vector>
+void check_vector_reverse_iterators() {
+ {
+ Vector vec;
+ assert(vec.rbegin() == vec.rend());
+ assert(vec.crbegin() == vec.crend());
+ }
+ {
+ const int n = 10;
+ Vector vec;
+ const Vector& cvec = vec;
+ vec.reserve(n);
+ for (int i = 0; i < n; ++i)
+ vec.push_back(i);
+ {
+ int iterations = 0;
+
+ for (typename Vector::const_reverse_iterator it = vec.crbegin(); it != vec.crend(); ++it) {
+ assert(*it == (n - iterations - 1));
+ ++iterations;
+ }
+ assert(iterations == n);
+ }
+ {
+ assert(cvec.rbegin() == vec.crbegin());
+ assert(cvec.rend() == vec.crend());
+ }
+ {
+ int iterations = 0;
+
+ for (typename Vector::reverse_iterator it = vec.rbegin(); it != vec.rend(); ++it) {
+ assert(*it == (n - iterations - 1));
+ *it = 40;
+ assert(*it == 40);
+ ++iterations;
+ }
+ assert(iterations == n);
+ }
+
+ assert(std::distance(vec.rbegin(), vec.rend()) == n);
+ assert(std::distance(cvec.rbegin(), cvec.rend()) == n);
+ assert(std::distance(vec.crbegin(), vec.crend()) == n);
+ assert(std::distance(cvec.crbegin(), cvec.crend()) == n);
+ }
+}
+
+int main(int, char**) {
+ check_vector_reverse_iterators<std::vector<int> >();
+#if TEST_STD_VER >= 11
+ check_vector_reverse_iterators<std::vector<int, min_allocator<int> > >();
+#endif
+
+ return 0;
+}
diff --git a/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp b/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
index 378a67c..e525a75 100644
--- a/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
+++ b/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
@@ -48,6 +48,39 @@
assert(v.capacity() == 150);
assert(is_contiguous_container_asan_correct(v));
}
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ std::vector<int> v;
+ size_t sz = v.max_size() + 1;
+
+ try {
+ v.reserve(sz);
+ assert(false);
+ } catch (const std::length_error&) {
+ assert(v.size() == 0);
+ assert(v.capacity() == 0);
+ }
+ }
+ {
+ std::vector<int> v(10, 42);
+ int* previous_data = v.data();
+ size_t previous_capacity = v.capacity();
+ size_t sz = v.max_size() + 1;
+
+ try {
+ v.reserve(sz);
+ assert(false);
+ } catch (std::length_error&) {
+ assert(v.size() == 10);
+ assert(v.capacity() == previous_capacity);
+ assert(v.data() == previous_data);
+
+ for (int i = 0; i < 10; ++i) {
+ assert(v[i] == 42);
+ }
+ }
+ }
+#endif
#if TEST_STD_VER >= 11
{
std::vector<int, min_allocator<int>> v;
diff --git a/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp b/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp
index a318546..a14f90c 100644
--- a/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp
+++ b/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp
@@ -15,6 +15,7 @@
#include "test_macros.h"
#include "test_allocator.h"
#include "min_allocator.h"
+#include "allocators.h"
int main(int, char**)
{
@@ -34,6 +35,44 @@
}
#if TEST_STD_VER >= 11
{
+ // Test with Allocator::propagate_on_container_copy_assignment == false_type
+ using Alloc = NonPOCCAAllocator<int>;
+ bool copy_assigned_into = false;
+ std::vector<int, Alloc> l(3, 2, Alloc(5, nullptr));
+ std::vector<int, Alloc> l2(l, Alloc(3, ©_assigned_into));
+ assert(!copy_assigned_into);
+ l2 = l;
+ assert(!copy_assigned_into);
+ assert(l2 == l);
+ assert(l2.get_allocator() == Alloc(3, nullptr));
+ }
+ {
+ // Test with Allocator::propagate_on_container_copy_assignment == true_type
+ // and equal allocators
+ using Alloc = POCCAAllocator<int>;
+ bool copy_assigned_into = false;
+ std::vector<int, Alloc> l(3, 2, Alloc(5, nullptr));
+ std::vector<int, Alloc> l2(l, Alloc(5, ©_assigned_into));
+ assert(!copy_assigned_into);
+ l2 = l;
+ assert(copy_assigned_into);
+ assert(l2 == l);
+ assert(l2.get_allocator() == Alloc(5, nullptr));
+ }
+ {
+ // Test with Allocator::propagate_on_container_copy_assignment == true_type
+ // and unequal allocators
+ using Alloc = POCCAAllocator<int>;
+ bool copy_assigned_into = false;
+ std::vector<int, Alloc> l(3, 2, Alloc(5, nullptr));
+ std::vector<int, Alloc> l2(l, Alloc(3, ©_assigned_into));
+ assert(!copy_assigned_into);
+ l2 = l;
+ assert(copy_assigned_into);
+ assert(l2 == l);
+ assert(l2.get_allocator() == Alloc(5, nullptr));
+ }
+ {
std::vector<int, min_allocator<int> > l(3, 2, min_allocator<int>());
std::vector<int, min_allocator<int> > l2(l, min_allocator<int>());
l2 = l;
diff --git a/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp b/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
index 7a73580..5bc35be 100644
--- a/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
+++ b/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
@@ -57,6 +57,19 @@
assert(v[0] == 3);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int> v;
+ v.reserve(8);
+ size_t old_capacity = v.capacity();
+ assert(old_capacity >= 8);
+ v.resize(4); // keep the existing capacity
+ assert(v.capacity() == old_capacity);
+
+ v.emplace(v.cend(), 42);
+ assert(v.size() == 5);
+ assert(v.capacity() == old_capacity);
+ assert(v[4] == 42);
+ }
return 0;
}
diff --git a/test/std/containers/sequences/vector/vector.modifiers/insert_iter_value.pass.cpp b/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp
similarity index 80%
rename from test/std/containers/sequences/vector/vector.modifiers/insert_iter_value.pass.cpp
rename to test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp
index 2edadd0..63c1c64 100644
--- a/test/std/containers/sequences/vector/vector.modifiers/insert_iter_value.pass.cpp
+++ b/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp
@@ -23,7 +23,8 @@
{
{
std::vector<int> v(100);
- std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
+ const int lvalue = 1;
+ std::vector<int>::iterator i = v.insert(v.cbegin() + 10, lvalue);
assert(v.size() == 101);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
@@ -35,10 +36,28 @@
assert(v[j] == 0);
}
{
+ const size_t n = 100;
+ std::vector<int> v(n);
+ v.reserve(n + 1);
+ const int lvalue = 1;
+
+ // no reallocation expected
+ std::vector<int>::iterator it = v.insert(v.cbegin() + n, lvalue);
+
+ assert(v.size() == n + 1);
+ assert(is_contiguous_container_asan_correct(v));
+ assert(it == v.begin() + n);
+ for (size_t i = 0; i < n; ++i) {
+ assert(v[i] == 0);
+ }
+ assert(v[n] == lvalue);
+ }
+ {
std::vector<int> v(100);
while(v.size() < v.capacity()) v.push_back(0); // force reallocation
size_t sz = v.size();
- std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
+ const int lvalue = 1;
+ std::vector<int>::iterator i = v.insert(v.cbegin() + 10, lvalue);
assert(v.size() == sz + 1);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
@@ -54,7 +73,8 @@
while(v.size() < v.capacity()) v.push_back(0);
v.pop_back(); v.pop_back(); // force no reallocation
size_t sz = v.size();
- std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
+ const int lvalue = 1;
+ std::vector<int>::iterator i = v.insert(v.cbegin() + 10, lvalue);
assert(v.size() == sz + 1);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
@@ -67,7 +87,8 @@
}
{
std::vector<int, limited_allocator<int, 300> > v(100);
- std::vector<int, limited_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 1);
+ const int lvalue = 1;
+ std::vector<int, limited_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, lvalue);
assert(v.size() == 101);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
@@ -81,7 +102,8 @@
#if TEST_STD_VER >= 11
{
std::vector<int, min_allocator<int>> v(100);
- std::vector<int, min_allocator<int>>::iterator i = v.insert(v.cbegin() + 10, 1);
+ const int lvalue = 1;
+ std::vector<int, min_allocator<int>>::iterator i = v.insert(v.cbegin() + 10, lvalue);
assert(v.size() == 101);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
diff --git a/test/support/allocators.h b/test/support/allocators.h
index 759e9c3..f8e0c1b 100644
--- a/test/support/allocators.h
+++ b/test/support/allocators.h
@@ -185,6 +185,55 @@
return !(x == y);
}
+template <class T, bool POCCAValue>
+class MaybePOCCAAllocator {
+ int id_ = 0;
+ bool* copy_assigned_into_ = nullptr;
+public:
+ typedef std::integral_constant<bool, POCCAValue> propagate_on_container_copy_assignment;
+ typedef T value_type;
+
+ MaybePOCCAAllocator() = default;
+ MaybePOCCAAllocator(int id, bool* copy_assigned_into)
+ : id_(id), copy_assigned_into_(copy_assigned_into) {}
+
+ MaybePOCCAAllocator(const MaybePOCCAAllocator&) = default;
+ MaybePOCCAAllocator& operator=(const MaybePOCCAAllocator& a)
+ {
+ id_ = a.id();
+ if (copy_assigned_into_)
+ *copy_assigned_into_ = true;
+ return *this;
+ }
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(::operator new(n * sizeof(T)));
+ }
+
+ void deallocate(T* ptr, std::size_t)
+ {
+ ::operator delete(ptr);
+ }
+
+ int id() const { return id_; }
+
+ friend bool operator==(const MaybePOCCAAllocator& lhs, const MaybePOCCAAllocator& rhs)
+ {
+ return lhs.id() == rhs.id();
+ }
+
+ friend bool operator!=(const MaybePOCCAAllocator& lhs, const MaybePOCCAAllocator& rhs)
+ {
+ return !(lhs == rhs);
+ }
+};
+
+template <class T>
+using POCCAAllocator = MaybePOCCAAllocator<T, /*POCCAValue = */true>;
+template <class T>
+using NonPOCCAAllocator = MaybePOCCAAllocator<T, /*POCCAValue = */false>;
+
#endif // TEST_STD_VER >= 11
#endif // ALLOCATORS_H