| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/zucchini/buffer_view.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <iterator> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "base/test/gtest_util.h" |
| #include "components/zucchini/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace zucchini { |
| |
| class BufferViewTest : public testing::Test { |
| protected: |
| // Some tests might modify this. |
| std::vector<uint8_t> bytes_ = ParseHexString("10 32 54 76 98 BA DC FE 10 00"); |
| }; |
| |
| TEST_F(BufferViewTest, Size) { |
| for (size_t len = 0; len <= bytes_.size(); ++len) { |
| EXPECT_EQ(len, ConstBufferView(bytes_.data(), len).size()); |
| EXPECT_EQ(len, MutableBufferView(bytes_.data(), len).size()); |
| } |
| } |
| |
| TEST_F(BufferViewTest, Empty) { |
| // Empty view. |
| EXPECT_TRUE(ConstBufferView(bytes_.data(), 0).empty()); |
| EXPECT_TRUE(MutableBufferView(bytes_.data(), 0).empty()); |
| |
| for (size_t len = 1; len <= bytes_.size(); ++len) { |
| EXPECT_FALSE(ConstBufferView(bytes_.data(), len).empty()); |
| EXPECT_FALSE(MutableBufferView(bytes_.data(), len).empty()); |
| } |
| } |
| |
| TEST_F(BufferViewTest, FromRange) { |
| constexpr size_t kSize = 10; |
| uint8_t raw_data[kSize] = {0x10, 0x32, 0x54, 0x76, 0x98, |
| 0xBA, 0xDC, 0xFE, 0x10, 0x00}; |
| ConstBufferView buffer = |
| ConstBufferView::FromRange(std::begin(raw_data), std::end(raw_data)); |
| EXPECT_EQ(bytes_.size(), buffer.size()); |
| EXPECT_EQ(std::begin(raw_data), buffer.begin()); |
| |
| MutableBufferView mutable_buffer = |
| MutableBufferView::FromRange(std::begin(raw_data), std::end(raw_data)); |
| EXPECT_EQ(bytes_.size(), mutable_buffer.size()); |
| EXPECT_EQ(std::begin(raw_data), mutable_buffer.begin()); |
| |
| EXPECT_DCHECK_DEATH( |
| ConstBufferView::FromRange(std::end(raw_data), std::begin(raw_data))); |
| |
| EXPECT_DCHECK_DEATH(MutableBufferView::FromRange(std::begin(raw_data) + 1, |
| std::begin(raw_data))); |
| } |
| |
| TEST_F(BufferViewTest, Subscript) { |
| ConstBufferView view(bytes_.data(), bytes_.size()); |
| |
| EXPECT_EQ(0x10, view[0]); |
| static_assert(!std::is_assignable<decltype(view[0]), uint8_t>::value, |
| "BufferView values should not be mutable."); |
| |
| MutableBufferView mutable_view(bytes_.data(), bytes_.size()); |
| |
| EXPECT_EQ(bytes_.data(), &mutable_view[0]); |
| mutable_view[0] = 42; |
| EXPECT_EQ(42, mutable_view[0]); |
| } |
| |
| TEST_F(BufferViewTest, SubRegion) { |
| ConstBufferView view(bytes_.data(), bytes_.size()); |
| |
| ConstBufferView sub_view = view[{2, 4}]; |
| EXPECT_EQ(view.begin() + 2, sub_view.begin()); |
| EXPECT_EQ(size_t(4), sub_view.size()); |
| } |
| |
| TEST_F(BufferViewTest, Shrink) { |
| ConstBufferView buffer(bytes_.data(), bytes_.size()); |
| |
| buffer.shrink(bytes_.size()); |
| EXPECT_EQ(bytes_.size(), buffer.size()); |
| buffer.shrink(2); |
| EXPECT_EQ(size_t(2), buffer.size()); |
| EXPECT_DCHECK_DEATH(buffer.shrink(bytes_.size())); |
| } |
| |
| TEST_F(BufferViewTest, Read) { |
| ConstBufferView buffer(bytes_.data(), bytes_.size()); |
| |
| EXPECT_EQ(0x10U, buffer.read<uint8_t>(0)); |
| EXPECT_EQ(0x54U, buffer.read<uint8_t>(2)); |
| |
| EXPECT_EQ(0x3210U, buffer.read<uint16_t>(0)); |
| EXPECT_EQ(0x7654U, buffer.read<uint16_t>(2)); |
| |
| EXPECT_EQ(0x76543210U, buffer.read<uint32_t>(0)); |
| EXPECT_EQ(0xBA987654U, buffer.read<uint32_t>(2)); |
| |
| EXPECT_EQ(0xFEDCBA9876543210ULL, buffer.read<uint64_t>(0)); |
| |
| EXPECT_EQ(0x00, buffer.read<uint8_t>(9)); |
| EXPECT_DEATH(buffer.read<uint8_t>(10), ""); |
| |
| EXPECT_EQ(0x0010FEDCU, buffer.read<uint32_t>(6)); |
| EXPECT_DEATH(buffer.read<uint32_t>(7), ""); |
| } |
| |
| TEST_F(BufferViewTest, Write) { |
| MutableBufferView buffer(bytes_.data(), bytes_.size()); |
| |
| buffer.write<uint32_t>(0, 0x01234567); |
| buffer.write<uint32_t>(4, 0x89ABCDEF); |
| EXPECT_EQ(ParseHexString("67 45 23 01 EF CD AB 89 10 00"), |
| std::vector<uint8_t>(buffer.begin(), buffer.end())); |
| |
| buffer.write<uint8_t>(9, 0xFF); |
| EXPECT_DEATH(buffer.write<uint8_t>(10, 0xFF), ""); |
| |
| buffer.write<uint32_t>(6, 0xFFFFFFFF); |
| EXPECT_DEATH(buffer.write<uint32_t>(7, 0xFFFFFFFF), ""); |
| } |
| |
| TEST_F(BufferViewTest, Modify) { |
| struct TestStruct { |
| uint32_t a; |
| uint32_t b; |
| }; |
| |
| MutableBufferView buffer(bytes_.data(), bytes_.size()); |
| |
| buffer.modify<TestStruct>(0).a = 0x01234567; |
| buffer.modify<TestStruct>(0).b = 0x89ABCDEF; |
| EXPECT_EQ(ParseHexString("67 45 23 01 EF CD AB 89 10 00"), |
| std::vector<uint8_t>(buffer.begin(), buffer.end())); |
| |
| buffer.modify<uint8_t>(9); |
| EXPECT_DEATH(buffer.modify<uint8_t>(10), ""); |
| |
| buffer.modify<uint32_t>(6); |
| EXPECT_DEATH(buffer.modify<uint32_t>(7), ""); |
| } |
| |
| TEST_F(BufferViewTest, CanAccess) { |
| MutableBufferView buffer(bytes_.data(), bytes_.size()); |
| EXPECT_TRUE(buffer.can_access<uint32_t>(0)); |
| EXPECT_TRUE(buffer.can_access<uint32_t>(6)); |
| EXPECT_FALSE(buffer.can_access<uint32_t>(7)); |
| EXPECT_FALSE(buffer.can_access<uint32_t>(10)); |
| EXPECT_FALSE(buffer.can_access<uint32_t>(0xFFFFFFFFU)); |
| |
| EXPECT_TRUE(buffer.can_access<uint8_t>(0)); |
| EXPECT_TRUE(buffer.can_access<uint8_t>(7)); |
| EXPECT_TRUE(buffer.can_access<uint8_t>(9)); |
| EXPECT_FALSE(buffer.can_access<uint8_t>(10)); |
| EXPECT_FALSE(buffer.can_access<uint8_t>(0xFFFFFFFF)); |
| } |
| |
| TEST_F(BufferViewTest, LocalRegion) { |
| ConstBufferView view(bytes_.data(), bytes_.size()); |
| |
| BufferRegion region = view.local_region(); |
| EXPECT_EQ(0U, region.offset); |
| EXPECT_EQ(bytes_.size(), region.size); |
| } |
| |
| TEST_F(BufferViewTest, Covers) { |
| EXPECT_TRUE(ConstBufferView().covers({0, 0})); |
| EXPECT_FALSE(ConstBufferView().covers({0, 1})); |
| |
| ConstBufferView view(bytes_.data(), bytes_.size()); |
| |
| EXPECT_TRUE(view.covers({0, 0})); |
| EXPECT_TRUE(view.covers({0, 1})); |
| EXPECT_TRUE(view.covers({0, bytes_.size()})); |
| EXPECT_FALSE(view.covers({0, bytes_.size() + 1})); |
| EXPECT_FALSE(view.covers({1, bytes_.size()})); |
| |
| EXPECT_TRUE(view.covers({bytes_.size() - 1, 0})); |
| EXPECT_TRUE(view.covers({bytes_.size() - 1, 1})); |
| EXPECT_FALSE(view.covers({bytes_.size() - 1, 2})); |
| EXPECT_TRUE(view.covers({bytes_.size(), 0})); |
| EXPECT_FALSE(view.covers({bytes_.size(), 1})); |
| EXPECT_FALSE(view.covers({bytes_.size() + 1, 0})); |
| EXPECT_FALSE(view.covers({bytes_.size() + 1, 1})); |
| |
| EXPECT_FALSE(view.covers({1, size_t(-1)})); |
| EXPECT_FALSE(view.covers({size_t(-1), 1})); |
| EXPECT_FALSE(view.covers({size_t(-1), size_t(-1)})); |
| } |
| |
| TEST_F(BufferViewTest, CoversArray) { |
| ConstBufferView view(bytes_.data(), bytes_.size()); |
| |
| for (uint32_t i = 1; i <= bytes_.size(); ++i) { |
| EXPECT_TRUE(view.covers_array(0, 1, i)); |
| EXPECT_TRUE(view.covers_array(0, i, 1)); |
| EXPECT_TRUE(view.covers_array(0, i, bytes_.size() / i)); |
| EXPECT_TRUE(view.covers_array(0, bytes_.size() / i, i)); |
| if (i < bytes_.size()) { |
| EXPECT_TRUE(view.covers_array(i, 1, bytes_.size() - i)); |
| EXPECT_TRUE(view.covers_array(i, bytes_.size() - i, 1)); |
| } |
| EXPECT_TRUE(view.covers_array(bytes_.size() - (bytes_.size() / i) * i, 1, |
| bytes_.size() / i)); |
| } |
| |
| EXPECT_TRUE(view.covers_array(0, 0, bytes_.size())); |
| EXPECT_TRUE(view.covers_array(bytes_.size() - 1, 0, bytes_.size())); |
| EXPECT_TRUE(view.covers_array(bytes_.size(), 0, bytes_.size())); |
| EXPECT_TRUE(view.covers_array(0, 0, 0x10000)); |
| EXPECT_TRUE(view.covers_array(bytes_.size() - 1, 0, 0x10000)); |
| EXPECT_TRUE(view.covers_array(bytes_.size(), 0, 0x10000)); |
| |
| EXPECT_FALSE(view.covers_array(0, 1, bytes_.size() + 1)); |
| EXPECT_FALSE(view.covers_array(0, 2, bytes_.size())); |
| EXPECT_FALSE(view.covers_array(0, bytes_.size() + 11, 1)); |
| EXPECT_FALSE(view.covers_array(0, bytes_.size(), 2)); |
| EXPECT_FALSE(view.covers_array(1, bytes_.size(), 1)); |
| |
| EXPECT_FALSE(view.covers_array(bytes_.size(), 1, 1)); |
| EXPECT_TRUE(view.covers_array(bytes_.size(), 0, 1)); |
| EXPECT_FALSE(view.covers_array(0, 0x10000, 0x10000)); |
| } |
| |
| TEST_F(BufferViewTest, Equals) { |
| // Almost identical to |bytes_|, except at 2 places: v v |
| std::vector<uint8_t> bytes2 = ParseHexString("10 32 54 76 98 AB CD FE 10 00"); |
| ConstBufferView view1(bytes_.data(), bytes_.size()); |
| ConstBufferView view2(&bytes2[0], bytes2.size()); |
| |
| EXPECT_TRUE(view1.equals(view1)); |
| EXPECT_TRUE(view2.equals(view2)); |
| EXPECT_FALSE(view1.equals(view2)); |
| EXPECT_FALSE(view2.equals(view1)); |
| |
| EXPECT_TRUE((view1[{0, 0}]).equals(view2[{0, 0}])); |
| EXPECT_TRUE((view1[{0, 0}]).equals(view2[{5, 0}])); |
| EXPECT_TRUE((view1[{0, 5}]).equals(view2[{0, 5}])); |
| EXPECT_FALSE((view1[{0, 6}]).equals(view2[{0, 6}])); |
| EXPECT_FALSE((view1[{0, 7}]).equals(view1[{0, 6}])); |
| EXPECT_TRUE((view1[{5, 3}]).equals(view1[{5, 3}])); |
| EXPECT_FALSE((view1[{5, 1}]).equals(view1[{5, 3}])); |
| EXPECT_TRUE((view2[{0, 1}]).equals(view2[{8, 1}])); |
| EXPECT_FALSE((view2[{1, 1}]).equals(view2[{8, 1}])); |
| } |
| |
| TEST_F(BufferViewTest, AlignOn) { |
| using size_type = ConstBufferView::size_type; |
| ConstBufferView image(bytes_.data(), bytes_.size()); |
| ConstBufferView view = image; |
| ASSERT_EQ(10U, view.size()); |
| |
| auto get_pos = [&image, &view]() -> size_type { |
| EXPECT_TRUE(view.begin() >= image.begin()); // Iterator compare. |
| return static_cast<size_type>(view.begin() - image.begin()); |
| }; |
| |
| EXPECT_EQ(0U, get_pos()); |
| view.remove_prefix(1U); |
| EXPECT_EQ(1U, get_pos()); |
| view.remove_prefix(4U); |
| EXPECT_EQ(5U, get_pos()); |
| |
| // Align. |
| EXPECT_TRUE(view.AlignOn(image, 1U)); // Trival case. |
| EXPECT_EQ(5U, get_pos()); |
| |
| EXPECT_TRUE(view.AlignOn(image, 2U)); |
| EXPECT_EQ(6U, get_pos()); |
| EXPECT_TRUE(view.AlignOn(image, 2U)); |
| EXPECT_EQ(6U, get_pos()); |
| |
| EXPECT_TRUE(view.AlignOn(image, 4U)); |
| EXPECT_EQ(8U, get_pos()); |
| EXPECT_TRUE(view.AlignOn(image, 2U)); |
| EXPECT_EQ(8U, get_pos()); |
| |
| view.remove_prefix(1U); |
| EXPECT_EQ(9U, get_pos()); |
| |
| // Pos is at 9, align to 4 would yield 12, but size is 10, so this fails. |
| EXPECT_FALSE(view.AlignOn(image, 4U)); |
| EXPECT_EQ(9U, get_pos()); |
| EXPECT_TRUE(view.AlignOn(image, 2U)); |
| EXPECT_EQ(10U, get_pos()); |
| } |
| |
| } // namespace zucchini |