/* Apache License, Version 2.0 */ #include "BLI_array.hh" #include "BLI_exception_safety_test_utils.hh" #include "BLI_strict_flags.h" #include "BLI_vector.hh" #include "testing/testing.h" namespace blender::tests { TEST(array, DefaultConstructor) { Array array; EXPECT_EQ(array.size(), 0); EXPECT_TRUE(array.is_empty()); } TEST(array, SizeConstructor) { Array array(5); EXPECT_EQ(array.size(), 5); EXPECT_FALSE(array.is_empty()); } TEST(array, FillConstructor) { Array array(5, 8); EXPECT_EQ(array.size(), 5); EXPECT_EQ(array[0], 8); EXPECT_EQ(array[1], 8); EXPECT_EQ(array[2], 8); EXPECT_EQ(array[3], 8); EXPECT_EQ(array[4], 8); } TEST(array, InitializerListConstructor) { Array array = {4, 5, 6, 7}; EXPECT_EQ(array.size(), 4); EXPECT_EQ(array[0], 4); EXPECT_EQ(array[1], 5); EXPECT_EQ(array[2], 6); EXPECT_EQ(array[3], 7); } TEST(array, SpanConstructor) { int stackarray[4] = {6, 7, 8, 9}; Span span(stackarray, ARRAY_SIZE(stackarray)); Array array(span); EXPECT_EQ(array.size(), 4); EXPECT_EQ(array[0], 6); EXPECT_EQ(array[1], 7); EXPECT_EQ(array[2], 8); EXPECT_EQ(array[3], 9); } TEST(array, CopyConstructor) { Array array = {5, 6, 7, 8}; Array new_array(array); EXPECT_EQ(array.size(), 4); EXPECT_EQ(new_array.size(), 4); EXPECT_NE(array.data(), new_array.data()); EXPECT_EQ(new_array[0], 5); EXPECT_EQ(new_array[1], 6); EXPECT_EQ(new_array[2], 7); EXPECT_EQ(new_array[3], 8); } TEST(array, MoveConstructor) { Array array = {5, 6, 7, 8}; Array new_array(std::move(array)); EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */ EXPECT_EQ(new_array.size(), 4); EXPECT_EQ(new_array[0], 5); EXPECT_EQ(new_array[1], 6); EXPECT_EQ(new_array[2], 7); EXPECT_EQ(new_array[3], 8); } TEST(array, CopyAssignment) { Array array = {1, 2, 3}; Array new_array = {4}; EXPECT_EQ(new_array.size(), 1); new_array = array; EXPECT_EQ(new_array.size(), 3); EXPECT_EQ(array.size(), 3); EXPECT_NE(array.data(), new_array.data()); EXPECT_EQ(new_array[0], 1); EXPECT_EQ(new_array[1], 2); EXPECT_EQ(new_array[2], 3); } TEST(array, MoveAssignment) { Array array = {1, 2, 3}; Array new_array = {4}; EXPECT_EQ(new_array.size(), 1); new_array = std::move(array); EXPECT_EQ(new_array.size(), 3); EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */ EXPECT_EQ(new_array[0], 1); EXPECT_EQ(new_array[1], 2); EXPECT_EQ(new_array[2], 3); } /** * Tests that the trivially constructible types are not zero-initialized. We do not want that for * performance reasons. */ TEST(array, TrivialTypeSizeConstructor) { Array *array = new Array(1); char *ptr = &(*array)[0]; array->~Array(); const char magic = 42; *ptr = magic; EXPECT_EQ(*ptr, magic); new (array) Array(1); EXPECT_EQ((*array)[0], magic); EXPECT_EQ(*ptr, magic); delete array; } struct ConstructibleType { char value; ConstructibleType() { value = 42; } }; TEST(array, NoInitializationSizeConstructor) { using MyArray = Array; TypedBuffer buffer; memset((void *)&buffer, 100, sizeof(MyArray)); /* Doing this to avoid some compiler optimization. */ for (int64_t i : IndexRange(sizeof(MyArray))) { EXPECT_EQ(((char *)buffer.ptr())[i], 100); } { MyArray &array = *new (buffer) MyArray(1, NoInitialization()); EXPECT_EQ(array[0].value, 100); array.clear_without_destruct(); array.~Array(); } { MyArray &array = *new (buffer) MyArray(1); EXPECT_EQ(array[0].value, 42); array.~Array(); } } TEST(array, Fill) { Array array(5); array.fill(3); EXPECT_EQ(array.size(), 5u); EXPECT_EQ(array[0], 3); EXPECT_EQ(array[1], 3); EXPECT_EQ(array[2], 3); EXPECT_EQ(array[3], 3); EXPECT_EQ(array[4], 3); } TEST(array, ReverseIterator) { Array array = {3, 4, 5, 6}; Vector reversed_vec; for (auto it = array.rbegin(); it != array.rend(); ++it) { reversed_vec.append(*it); *it += 10; } EXPECT_EQ_ARRAY(reversed_vec.data(), Span({6, 5, 4, 3}).data(), 4); EXPECT_EQ_ARRAY(array.data(), Span({13, 14, 15, 16}).data(), 4); } TEST(array, SpanConstructorExceptions) { std::array values; values[2].throw_during_copy = true; Span span{values}; EXPECT_ANY_THROW({ Array array(span); }); } TEST(array, SizeValueConstructorExceptions) { ExceptionThrower value; value.throw_during_copy = true; EXPECT_ANY_THROW({ Array array(5, value); }); } TEST(array, MoveConstructorExceptions) { Array array(3); array[1].throw_during_move = true; EXPECT_ANY_THROW({ Array array_copy(std::move(array)); }); } TEST(array, CopyAssignmentExceptions) { Array array(5); array[3].throw_during_copy = true; Array array_copy(10); EXPECT_ANY_THROW({ array_copy = array; }); } TEST(array, MoveAssignmentExceptions) { Array array(4); array[2].throw_during_move = true; Array array_moved(10); EXPECT_ANY_THROW({ array_moved = std::move(array); }); } TEST(array, Last) { Array array = {5, 7, 8, 9}; EXPECT_EQ(array.last(), 9); array.last() = 1; EXPECT_EQ(array[3], 1); EXPECT_EQ(const_cast &>(array).last(), 1); } TEST(array, Reinitialize) { Array array = {"hello", "world"}; EXPECT_EQ(array.size(), 2); EXPECT_EQ(array[1], "world"); array.reinitialize(3); EXPECT_EQ(array.size(), 3); EXPECT_EQ(array[0], ""); EXPECT_EQ(array[1], ""); EXPECT_EQ(array[2], ""); array.reinitialize(0); EXPECT_EQ(array.size(), 0); } } // namespace blender::tests