From 06f1ae9aaca969ee95ef840f22b6b461c304542d Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Tue, 13 Mar 2018 18:19:34 +0000 Subject: [Zucchini] Move Zucchini from /chrome/installer/ to /components/. (Use "git log --follow" to see older revisions of files). /components/ is the most logical place to put Zucchini, which only depends on /base and /testing/gtest. This move also enables Zucchini to be used by the Component Updater. Details: - Move all files; run the following to change deps and guards: sed 's/chrome\/installer/components/' *.cc *.h -i sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i - Sorting works out pretty well! - Change all 'chrome/installer/zucchini' to 'components/zucchini' throughout other parts of the repo; sort if necessary. - Fix 6 'git cl lint' errors. - Change 1 Bind() usage to BindRepeated(). - Update OWNER. Bug: 729154 Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7 Reviewed-on: https://chromium-review.googlesource.com/954923 Reviewed-by: Greg Thompson Reviewed-by: Jochen Eisinger Reviewed-by: Samuel Huang Commit-Queue: Samuel Huang Cr-Commit-Position: refs/heads/master@{#542857} NOKEYCHECK=True GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec --- buffer_source_unittest.cc | 347 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 buffer_source_unittest.cc (limited to 'buffer_source_unittest.cc') diff --git a/buffer_source_unittest.cc b/buffer_source_unittest.cc new file mode 100644 index 0000000..e8f00c5 --- /dev/null +++ b/buffer_source_unittest.cc @@ -0,0 +1,347 @@ +// 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_source.h" + +#include +#include + +#include +#include +#include +#include + +#include "components/zucchini/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace zucchini { + +using vec = std::vector; + +class BufferSourceTest : public testing::Test { + protected: + std::vector bytes_ = ParseHexString("10 32 54 76 98 BA DC FE 10 00"); + + BufferSource source_ = {bytes_.data(), bytes_.size()}; +}; + +TEST_F(BufferSourceTest, Skip) { + EXPECT_EQ(bytes_.size(), source_.Remaining()); + source_.Skip(2); + EXPECT_EQ(bytes_.size() - 2, source_.Remaining()); + source_.Skip(10); // Skipping past end just moves cursor to end. + EXPECT_EQ(size_t(0), source_.Remaining()); +} + +TEST_F(BufferSourceTest, CheckNextBytes) { + EXPECT_TRUE(source_.CheckNextBytes({0x10, 0x32, 0x54, 0x76})); + source_.Skip(4); + EXPECT_TRUE(source_.CheckNextBytes({0x98, 0xBA, 0xDC, 0xFE})); + + // Cursor has not advanced, so check fails. + EXPECT_FALSE(source_.CheckNextBytes({0x10, 0x00})); + + source_.Skip(4); + EXPECT_EQ(size_t(2), source_.Remaining()); + + // Goes beyond end by 2 bytes. + EXPECT_FALSE(source_.CheckNextBytes({0x10, 0x00, 0x00, 0x00})); + EXPECT_EQ(size_t(2), source_.Remaining()); +} + +TEST_F(BufferSourceTest, ConsumeBytes) { + EXPECT_FALSE(source_.ConsumeBytes({0x10, 0x00})); + EXPECT_EQ(bytes_.size(), source_.Remaining()); + EXPECT_TRUE(source_.ConsumeBytes({0x10, 0x32, 0x54, 0x76})); + EXPECT_EQ(size_t(6), source_.Remaining()); + EXPECT_TRUE(source_.ConsumeBytes({0x98, 0xBA, 0xDC, 0xFE})); + EXPECT_EQ(size_t(2), source_.Remaining()); + + // Goes beyond end by 2 bytes. + EXPECT_FALSE(source_.ConsumeBytes({0x10, 0x00, 0x00, 0x00})); + EXPECT_EQ(size_t(2), source_.Remaining()); +} + +TEST_F(BufferSourceTest, CheckNextValue) { + EXPECT_TRUE(source_.CheckNextValue(uint32_t(0x76543210))); + EXPECT_FALSE(source_.CheckNextValue(uint32_t(0x0))); + EXPECT_TRUE(source_.CheckNextValue(uint64_t(0xFEDCBA9876543210))); + EXPECT_FALSE(source_.CheckNextValue(uint64_t(0x0))); + + source_.Skip(8); + EXPECT_EQ(size_t(2), source_.Remaining()); + + // Goes beyond end by 2 bytes. + EXPECT_FALSE(source_.CheckNextValue(uint32_t(0x1000))); +} + +// Supported by MSVC, g++, and clang++. +// Ensures no gaps in packing. +#pragma pack(push, 1) +struct ValueType { + uint32_t a; + uint16_t b; +}; +#pragma pack(pop) + +TEST_F(BufferSourceTest, GetValueIntegral) { + uint32_t value = 0; + EXPECT_TRUE(source_.GetValue(&value)); + EXPECT_EQ(uint32_t(0x76543210), value); + EXPECT_EQ(size_t(6), source_.Remaining()); + + EXPECT_TRUE(source_.GetValue(&value)); + EXPECT_EQ(uint32_t(0xFEDCBA98), value); + EXPECT_EQ(size_t(2), source_.Remaining()); + + EXPECT_FALSE(source_.GetValue(&value)); + EXPECT_EQ(size_t(2), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetValueAggregate) { + ValueType value = {}; + EXPECT_TRUE(source_.GetValue(&value)); + EXPECT_EQ(uint32_t(0x76543210), value.a); + EXPECT_EQ(uint32_t(0xBA98), value.b); + EXPECT_EQ(size_t(4), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetRegion) { + ConstBufferView region; + EXPECT_TRUE(source_.GetRegion(0, ®ion)); + EXPECT_EQ(bytes_.size(), source_.Remaining()); + EXPECT_TRUE(region.empty()); + + EXPECT_TRUE(source_.GetRegion(2, ®ion)); + EXPECT_EQ(size_t(2), region.size()); + EXPECT_EQ(vec({0x10, 0x32}), vec(region.begin(), region.end())); + EXPECT_EQ(size_t(8), source_.Remaining()); + + EXPECT_FALSE(source_.GetRegion(bytes_.size(), ®ion)); + EXPECT_EQ(size_t(8), source_.Remaining()); + // |region| is left untouched. + EXPECT_EQ(vec({0x10, 0x32}), vec(region.begin(), region.end())); + EXPECT_EQ(size_t(2), region.size()); +} + +TEST_F(BufferSourceTest, GetPointerIntegral) { + const uint32_t* ptr = source_.GetPointer(); + EXPECT_NE(nullptr, ptr); + EXPECT_EQ(uint32_t(0x76543210), *ptr); + EXPECT_EQ(size_t(6), source_.Remaining()); + + ptr = source_.GetPointer(); + EXPECT_NE(nullptr, ptr); + EXPECT_EQ(uint32_t(0xFEDCBA98), *ptr); + EXPECT_EQ(size_t(2), source_.Remaining()); + + EXPECT_EQ(nullptr, source_.GetPointer()); + EXPECT_EQ(size_t(2), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetPointerAggregate) { + const ValueType* ptr = source_.GetPointer(); + EXPECT_NE(nullptr, ptr); + EXPECT_EQ(uint32_t(0x76543210), ptr->a); + EXPECT_EQ(uint32_t(0xBA98), ptr->b); + EXPECT_EQ(size_t(4), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetArrayIntegral) { + EXPECT_EQ(nullptr, source_.GetArray(3)); + + const uint32_t* ptr = source_.GetArray(2); + EXPECT_NE(nullptr, ptr); + EXPECT_EQ(uint32_t(0x76543210), ptr[0]); + EXPECT_EQ(uint32_t(0xFEDCBA98), ptr[1]); + EXPECT_EQ(size_t(2), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetArrayAggregate) { + const ValueType* ptr = source_.GetArray(2); + EXPECT_EQ(nullptr, ptr); + + ptr = source_.GetArray(1); + + EXPECT_NE(nullptr, ptr); + EXPECT_EQ(uint32_t(0x76543210), ptr[0].a); + EXPECT_EQ(uint32_t(0xBA98), ptr[0].b); + EXPECT_EQ(size_t(4), source_.Remaining()); +} + +TEST_F(BufferSourceTest, GetUleb128) { + using size_type = BufferSource::size_type; + // Result = {success, value, bytes_consumed}. + using Result = std::tuple; + + constexpr uint32_t kUnInit = 0xCCCCCCCC; // Arbitrary value. + constexpr Result kBad{false, kUnInit, 0U}; + + auto run = [kUnInit](const std::string hex_string) -> Result { + std::vector bytes = ParseHexString(hex_string); + BufferSource source(ConstBufferView{bytes.data(), bytes.size()}); + BufferSource::iterator base = source.begin(); + // Initialize |value| to |kUnInit| to ensure no write on failure. + uint32_t value = kUnInit; + bool success = source.GetUleb128(&value); + return {success, value, source.begin() - base}; + }; + + auto good = [](uint32_t value, size_type bytes_consumed) -> Result { + return Result{true, value, bytes_consumed}; + }; + + EXPECT_EQ(good(0x0U, 1U), run("00")); + EXPECT_EQ(good(0x20U, 1U), run("20")); + EXPECT_EQ(good(0x42U, 1U), run("42")); + EXPECT_EQ(good(0x7FU, 1U), run("7F")); + EXPECT_EQ(kBad, run("80")); // Out of data. + EXPECT_EQ(good(0x0U, 2U), run("80 00")); // Redundant code. + EXPECT_EQ(good(0x80U, 2U), run("80 01")); + EXPECT_EQ(good(0x7FU, 2U), run("FF 00")); // Redundant (unsigned). + EXPECT_EQ(good(0x3FFFU, 2U), run("FF 7F")); + EXPECT_EQ(good(0x0U, 1U), run("00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80")); // Out of data. + EXPECT_EQ(kBad, run("F1 88")); // Out of data. + EXPECT_EQ(good(0x0U, 3U), run("80 80 00")); // Redundant code. + EXPECT_EQ(good(0x4000U, 3U), run("80 80 01")); + EXPECT_EQ(good(0x00100000U, 3U), run("80 80 40")); + EXPECT_EQ(good(0x001FFFFFU, 3U), run("FF FF 7F")); + EXPECT_EQ(good(0x0U, 1U), run("00 00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80 80")); // Out of data. + EXPECT_EQ(kBad, run("AB CD EF")); // Out of data. + EXPECT_EQ(good(0x0U, 4U), run("80 80 80 00")); // Redundant code. + EXPECT_EQ(good(0x00100000U, 4U), run("80 80 C0 00")); + EXPECT_EQ(good(0x00200000U, 4U), run("80 80 80 01")); + EXPECT_EQ(good(0x08000000U, 4U), run("80 80 80 40")); + EXPECT_EQ(good(0x001FC07FU, 4U), run("FF 80 FF 00")); + EXPECT_EQ(good(0x0U, 5U), run("80 80 80 80 00")); // Redundant code. + EXPECT_EQ(good(0x10000000U, 5U), run("80 80 80 80 01")); + EXPECT_EQ(good(0x10204081U, 5U), run("81 81 81 81 01")); + EXPECT_EQ(good(0x7FFFFFFFU, 5U), run("FF FF FF FF 07")); + EXPECT_EQ(good(0x80000000U, 5U), run("80 80 80 80 08")); + EXPECT_EQ(good(0xFFFFFFFFU, 5U), run("FF FF FF FF 0F")); + EXPECT_EQ(kBad, run("FF FF FF FF 80")); // Too long / out of data. + EXPECT_EQ(good(0x0FFFFFFFU, 5U), run("FF FF FF FF 10")); // "1" discarded. + EXPECT_EQ(good(0x00000000U, 5U), run("80 80 80 80 20")); // "2" discarded. + EXPECT_EQ(good(0xA54A952AU, 5U), run("AA AA AA AA 7A")); // "7" discarded. + EXPECT_EQ(kBad, run("FF FF FF FF FF 00")); // Too long. +} + +TEST_F(BufferSourceTest, GetSleb128) { + using size_type = BufferSource::size_type; + // Result = {success, value, bytes_consumed}. + using Result = std::tuple; + + constexpr int32_t kUnInit = 0xCCCCCCCC; // Arbitrary value. + constexpr Result kBad{false, kUnInit, 0U}; + + auto run = [kUnInit](const std::string hex_string) -> Result { + std::vector bytes = ParseHexString(hex_string); + BufferSource source(ConstBufferView{bytes.data(), bytes.size()}); + BufferSource::iterator base = source.begin(); + // Initialize |value| to |kUnInit| to ensure no write on failure. + int32_t value = kUnInit; + bool success = source.GetSleb128(&value); + return {success, value, source.begin() - base}; + }; + + auto good = [](int32_t value, size_type bytes_consumed) -> Result { + return Result{true, value, bytes_consumed}; + }; + + EXPECT_EQ(good(0x0, 1U), run("00")); + EXPECT_EQ(good(0x20U, 1U), run("20")); + EXPECT_EQ(good(-0x3E, 1U), run("42")); + EXPECT_EQ(good(-0x1, 1U), run("7F")); + EXPECT_EQ(kBad, run("80")); // Out of data. + EXPECT_EQ(good(0x0, 2U), run("80 00")); // Redundant code. + EXPECT_EQ(good(0x80, 2U), run("80 01")); + EXPECT_EQ(good(0x7F, 2U), run("FF 00")); // Not redudnant. + EXPECT_EQ(good(-0x1, 2U), run("FF 7F")); // Redundant code. + EXPECT_EQ(good(0x0, 1U), run("00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80")); // Out of data. + EXPECT_EQ(kBad, run("F1 88")); // Out of data. + EXPECT_EQ(good(0x0, 3U), run("80 80 00")); // Redundant code. + EXPECT_EQ(good(0x4000, 3U), run("80 80 01")); + EXPECT_EQ(good(-0x100000, 3U), run("80 80 40")); + EXPECT_EQ(good(-0x1, 3U), run("FF FF 7F")); // Redundant code. + EXPECT_EQ(good(0x0, 1U), run("00 00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80 80")); // Out of data. + EXPECT_EQ(kBad, run("AB CD EF")); // Out of data. + EXPECT_EQ(good(0x0, 4U), run("80 80 80 00")); // Redundant code. + EXPECT_EQ(good(0x00100000, 4U), run("80 80 C0 00")); + EXPECT_EQ(good(0x00200000, 4U), run("80 80 80 01")); + EXPECT_EQ(good(-static_cast(0x08000000), 4U), run("80 80 80 40")); + EXPECT_EQ(good(0x001FC07F, 4U), run("FF 80 FF 00")); + EXPECT_EQ(good(0x0, 5U), run("80 80 80 80 00")); // Redundant code. + EXPECT_EQ(good(0x10000000, 5U), run("80 80 80 80 01")); + EXPECT_EQ(good(0x10204081, 5U), run("81 81 81 81 01")); + EXPECT_EQ(good(0x7FFFFFFF, 5U), run("FF FF FF FF 07")); + EXPECT_EQ(good(-static_cast(0x80000000), 5U), run("80 80 80 80 08")); + EXPECT_EQ(good(-0x1, 5U), run("FF FF FF FF 0F")); // Redundant code. + EXPECT_EQ(kBad, run("FF FF FF FF 80")); // Too long / out of data. + EXPECT_EQ(good(0x0FFFFFFF, 5U), run("FF FF FF FF 10")); // "1" discarded. + EXPECT_EQ(good(0x00000000, 5U), run("80 80 80 80 20")); // "2" discarded. + EXPECT_EQ(good(-0x5AB56AD6, 5U), run("AA AA AA AA 7A")); // "7" discarded. + EXPECT_EQ(kBad, run("FF FF FF FF FF 00")); // Too long. +} + +TEST_F(BufferSourceTest, SkipLeb128) { + using size_type = BufferSource::size_type; + // Result = {success, value, bytes_consumed}. + using Result = std::tuple; + + constexpr Result kBad{false, 0U}; + + auto run = [](const std::string hex_string) -> Result { + std::vector bytes = ParseHexString(hex_string); + BufferSource source(ConstBufferView{bytes.data(), bytes.size()}); + BufferSource::iterator base = source.begin(); + bool success = source.SkipLeb128(); + return {success, source.begin() - base}; + }; + + auto good = [](size_type bytes_consumed) -> Result { + return Result{true, bytes_consumed}; + }; + + EXPECT_EQ(good(1U), run("00")); + EXPECT_EQ(good(1U), run("20")); + EXPECT_EQ(good(1U), run("42")); + EXPECT_EQ(good(1U), run("7F")); + EXPECT_EQ(kBad, run("80")); // Out of data. + EXPECT_EQ(good(2U), run("80 00")); // Redundant code. + EXPECT_EQ(good(2U), run("80 01")); + EXPECT_EQ(good(2U), run("FF 00")); // Redundant (unsigned). + EXPECT_EQ(good(2U), run("FF 7F")); + EXPECT_EQ(good(1U), run("00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80")); // Out of data. + EXPECT_EQ(kBad, run("F1 88")); // Out of data. + EXPECT_EQ(good(3U), run("80 80 00")); // Redundant code. + EXPECT_EQ(good(3U), run("80 80 01")); + EXPECT_EQ(good(3U), run("80 80 40")); + EXPECT_EQ(good(3U), run("FF FF 7F")); + EXPECT_EQ(good(1U), run("00 00 80")); // Only reads byte 0. + EXPECT_EQ(kBad, run("80 80 80")); // Out of data. + EXPECT_EQ(kBad, run("AB CD EF")); // Out of data. + EXPECT_EQ(good(4U), run("80 80 80 00")); // Redundant code. + EXPECT_EQ(good(4U), run("80 80 C0 00")); + EXPECT_EQ(good(4U), run("80 80 80 01")); + EXPECT_EQ(good(4U), run("80 80 80 40")); + EXPECT_EQ(good(4U), run("FF 80 FF 00")); + EXPECT_EQ(good(5U), run("80 80 80 80 00")); // Redundant code. + EXPECT_EQ(good(5U), run("80 80 80 80 01")); + EXPECT_EQ(good(5U), run("81 81 81 81 01")); + EXPECT_EQ(good(5U), run("FF FF FF FF 07")); + EXPECT_EQ(good(5U), run("80 80 80 80 08")); + EXPECT_EQ(good(5U), run("FF FF FF FF 0F")); + EXPECT_EQ(kBad, run("FF FF FF FF 80")); // Too long / out of data. + EXPECT_EQ(good(5U), run("FF FF FF FF 10")); // "1" discarded. + EXPECT_EQ(good(5U), run("80 80 80 80 20")); // "2" discarded. + EXPECT_EQ(good(5U), run("AA AA AA AA 7A")); // "7" discarded. + EXPECT_EQ(kBad, run("FF FF FF FF FF 00")); // Too long. +} + +} // namespace zucchini -- cgit v1.2.3