aboutsummaryrefslogtreecommitdiff
path: root/src/utils/vector_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/vector_test.cc')
-rw-r--r--src/utils/vector_test.cc234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/utils/vector_test.cc b/src/utils/vector_test.cc
new file mode 100644
index 0000000..5b0127c
--- /dev/null
+++ b/src/utils/vector_test.cc
@@ -0,0 +1,234 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/vector.h"
+
+#include <memory>
+#include <new>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/utils/compiler_attributes.h"
+
+#if LIBGAV1_MSAN
+#include <sanitizer/msan_interface.h>
+#endif
+
+namespace libgav1 {
+namespace {
+
+class Foo {
+ public:
+ Foo() = default;
+
+ int x() const { return x_; }
+
+ private:
+ int x_ = 38;
+};
+
+class Point {
+ public:
+ Point(int x, int y) : x_(x), y_(y) {}
+
+ int x() const { return x_; }
+ int y() const { return y_; }
+
+ private:
+ int x_;
+ int y_;
+};
+
+TEST(VectorTest, NoCtor) {
+ VectorNoCtor<int> v;
+ EXPECT_TRUE(v.resize(100));
+ Vector<int> w;
+ EXPECT_TRUE(w.resize(100));
+
+#if LIBGAV1_MSAN
+ // Use MemorySanitizer to check VectorNoCtor::resize() does not initialize
+ // the memory while Vector::resize() does.
+ //
+ // __msan_test_shadow(const void *x, uptr size) returns the offset of the
+ // first (at least partially) poisoned byte in the range, or -1 if the whole
+ // range is good.
+ for (size_t i = 0; i < 100; ++i) {
+ EXPECT_EQ(__msan_test_shadow(&v[i], sizeof(int)), 0);
+ EXPECT_EQ(__msan_test_shadow(&w[i], sizeof(int)), -1);
+ }
+#endif
+}
+
+TEST(VectorTest, Constructor) {
+ Vector<Foo> v;
+ EXPECT_TRUE(v.resize(100));
+ for (const Foo& foo : v) {
+ EXPECT_EQ(foo.x(), 38);
+ }
+}
+
+TEST(VectorTest, PushBack) {
+ // Create a vector containing integers
+ Vector<int> v;
+ EXPECT_TRUE(v.reserve(8));
+ EXPECT_EQ(v.size(), 0);
+
+ EXPECT_TRUE(v.push_back(25));
+ EXPECT_EQ(v.size(), 1);
+ EXPECT_EQ(v[0], 25);
+
+ EXPECT_TRUE(v.push_back(13));
+ EXPECT_EQ(v.size(), 2);
+ EXPECT_EQ(v[0], 25);
+ EXPECT_EQ(v[1], 13);
+}
+
+TEST(VectorTest, PushBackUnchecked) {
+ Vector<std::unique_ptr<Point>> v;
+ EXPECT_TRUE(v.reserve(2));
+ EXPECT_EQ(v.size(), 0);
+
+ std::unique_ptr<Point> point(new (std::nothrow) Point(1, 2));
+ EXPECT_NE(point, nullptr);
+ v.push_back_unchecked(std::move(point));
+ EXPECT_EQ(v.size(), 1);
+ EXPECT_EQ(v[0]->x(), 1);
+ EXPECT_EQ(v[0]->y(), 2);
+
+ point.reset(new (std::nothrow) Point(3, 4));
+ EXPECT_NE(point, nullptr);
+ v.push_back_unchecked(std::move(point));
+ EXPECT_EQ(v.size(), 2);
+ EXPECT_EQ(v[0]->x(), 1);
+ EXPECT_EQ(v[0]->y(), 2);
+ EXPECT_EQ(v[1]->x(), 3);
+ EXPECT_EQ(v[1]->y(), 4);
+}
+
+TEST(VectorTest, EmplaceBack) {
+ Vector<Point> v;
+ EXPECT_EQ(v.size(), 0);
+
+ EXPECT_TRUE(v.emplace_back(1, 2));
+ EXPECT_EQ(v.size(), 1);
+ EXPECT_EQ(v[0].x(), 1);
+ EXPECT_EQ(v[0].y(), 2);
+
+ EXPECT_TRUE(v.emplace_back(3, 4));
+ EXPECT_EQ(v.size(), 2);
+ EXPECT_EQ(v[0].x(), 1);
+ EXPECT_EQ(v[0].y(), 2);
+ EXPECT_EQ(v[1].x(), 3);
+ EXPECT_EQ(v[1].y(), 4);
+}
+
+// Copy constructor and assignment are deleted, but move constructor and
+// assignment are OK.
+TEST(VectorTest, Move) {
+ Vector<int> ints1;
+ EXPECT_TRUE(ints1.reserve(4));
+ EXPECT_TRUE(ints1.push_back(2));
+ EXPECT_TRUE(ints1.push_back(3));
+ EXPECT_TRUE(ints1.push_back(5));
+ EXPECT_TRUE(ints1.push_back(7));
+
+ // Move constructor.
+ Vector<int> ints2(std::move(ints1));
+ EXPECT_EQ(ints2.size(), 4);
+ EXPECT_EQ(ints2[0], 2);
+ EXPECT_EQ(ints2[1], 3);
+ EXPECT_EQ(ints2[2], 5);
+ EXPECT_EQ(ints2[3], 7);
+
+ // Move assignment.
+ Vector<int> ints3;
+ EXPECT_TRUE(ints3.reserve(1));
+ EXPECT_TRUE(ints3.push_back(11));
+ ints3 = std::move(ints2);
+ EXPECT_EQ(ints3.size(), 4);
+ EXPECT_EQ(ints3[0], 2);
+ EXPECT_EQ(ints3[1], 3);
+ EXPECT_EQ(ints3[2], 5);
+ EXPECT_EQ(ints3[3], 7);
+}
+
+TEST(VectorTest, Erase) {
+ Vector<int> ints;
+ EXPECT_TRUE(ints.reserve(4));
+ EXPECT_TRUE(ints.push_back(2));
+ EXPECT_TRUE(ints.push_back(3));
+ EXPECT_TRUE(ints.push_back(5));
+ EXPECT_TRUE(ints.push_back(7));
+
+ EXPECT_EQ(ints.size(), 4);
+ EXPECT_EQ(ints[0], 2);
+ EXPECT_EQ(ints[1], 3);
+ EXPECT_EQ(ints[2], 5);
+ EXPECT_EQ(ints[3], 7);
+
+ ints.erase(ints.begin());
+ EXPECT_EQ(ints.size(), 3);
+ EXPECT_EQ(ints[0], 3);
+ EXPECT_EQ(ints[1], 5);
+ EXPECT_EQ(ints[2], 7);
+}
+
+TEST(VectorTest, EraseNonTrivial) {
+ // A simple class that sets an int value to 0 in the destructor.
+ class Cleaner {
+ public:
+ explicit Cleaner(int* value) : value_(value) {}
+ ~Cleaner() { *value_ = 0; }
+
+ int value() const { return *value_; }
+
+ private:
+ int* value_;
+ };
+ int value1 = 100;
+ int value2 = 200;
+ Vector<std::unique_ptr<Cleaner>> v;
+ EXPECT_TRUE(v.reserve(2));
+ EXPECT_EQ(v.capacity(), 2);
+
+ std::unique_ptr<Cleaner> c(new (std::nothrow) Cleaner(&value1));
+ EXPECT_NE(c, nullptr);
+ EXPECT_TRUE(v.push_back(std::move(c)));
+ c.reset(new (std::nothrow) Cleaner(&value2));
+ EXPECT_NE(c, nullptr);
+ EXPECT_TRUE(v.push_back(std::move(c)));
+ EXPECT_EQ(v.size(), 2);
+ EXPECT_EQ(value1, 100);
+ EXPECT_EQ(value2, 200);
+
+ v.erase(v.begin());
+ EXPECT_EQ(v.size(), 1);
+ EXPECT_EQ(v.capacity(), 2);
+ EXPECT_EQ(value1, 0);
+ EXPECT_EQ(value2, 200);
+ EXPECT_EQ(v[0].get()->value(), value2);
+
+ EXPECT_TRUE(v.shrink_to_fit());
+ EXPECT_EQ(v.size(), 1);
+ EXPECT_EQ(v.capacity(), 1);
+ EXPECT_EQ(value2, 200);
+ EXPECT_EQ(v[0].get()->value(), value2);
+
+ v.clear();
+ EXPECT_TRUE(v.empty());
+ EXPECT_EQ(value2, 0);
+}
+
+} // namespace
+} // namespace libgav1