170 lines
5.2 KiB
C++
170 lines
5.2 KiB
C++
// 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/patch_utils.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace zucchini {
|
|
|
|
template <class T>
|
|
void TestEncodeDecodeVarUInt(const std::vector<T>& data) {
|
|
std::vector<uint8_t> buffer;
|
|
|
|
std::vector<T> values;
|
|
for (T basis : data) {
|
|
// For variety, test the neighborhood values for each case in |data|. Some
|
|
// test cases may result in overflow when computing |value|, but we don't
|
|
// care about that.
|
|
for (int delta = -4; delta <= 4; ++delta) {
|
|
T value = delta + basis;
|
|
EncodeVarUInt<T>(value, std::back_inserter(buffer));
|
|
values.push_back(value);
|
|
|
|
value = delta - basis;
|
|
EncodeVarUInt<T>(value, std::back_inserter(buffer));
|
|
values.push_back(value);
|
|
}
|
|
}
|
|
|
|
auto it = buffer.begin();
|
|
for (T expected : values) {
|
|
T value = T(-1);
|
|
auto res = DecodeVarUInt(it, buffer.end(), &value);
|
|
EXPECT_NE(0, res);
|
|
EXPECT_EQ(expected, value);
|
|
it += res;
|
|
}
|
|
EXPECT_EQ(it, buffer.end());
|
|
|
|
T value = T(-1);
|
|
auto res = DecodeVarUInt(it, buffer.end(), &value);
|
|
EXPECT_EQ(0, res);
|
|
EXPECT_EQ(T(-1), value);
|
|
}
|
|
|
|
template <class T>
|
|
void TestEncodeDecodeVarInt(const std::vector<T>& data) {
|
|
std::vector<uint8_t> buffer;
|
|
|
|
std::vector<T> values;
|
|
for (T basis : data) {
|
|
// For variety, test the neighborhood values for each case in |data|. Some
|
|
// test cases may result in overflow when computing |value|, but we don't
|
|
// care about that.
|
|
for (int delta = -4; delta <= 4; ++delta) {
|
|
T value = delta + basis;
|
|
EncodeVarInt(value, std::back_inserter(buffer));
|
|
values.push_back(value);
|
|
|
|
value = delta - basis;
|
|
EncodeVarInt(value, std::back_inserter(buffer));
|
|
values.push_back(value);
|
|
}
|
|
}
|
|
|
|
auto it = buffer.begin();
|
|
for (T expected : values) {
|
|
T value = T(-1);
|
|
auto res = DecodeVarInt(it, buffer.end(), &value);
|
|
EXPECT_NE(0, res);
|
|
EXPECT_EQ(expected, value);
|
|
it += res;
|
|
}
|
|
EXPECT_EQ(it, buffer.end());
|
|
|
|
T value = T(-1);
|
|
auto res = DecodeVarInt(it, buffer.end(), &value);
|
|
EXPECT_EQ(0, res);
|
|
EXPECT_EQ(T(-1), value);
|
|
}
|
|
|
|
TEST(PatchUtilsTest, EncodeDecodeVarUInt32) {
|
|
TestEncodeDecodeVarUInt<uint32_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
|
|
1 << 22, 1 << 27, 1 << 28, 0x7FFFFFFFU,
|
|
UINT32_MAX});
|
|
}
|
|
|
|
TEST(PatchUtilsTest, EncodeDecodeVarInt32) {
|
|
TestEncodeDecodeVarInt<int32_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
|
|
1 << 22, 1 << 27, 1 << 28, -1, INT32_MIN,
|
|
INT32_MAX});
|
|
}
|
|
|
|
TEST(PatchUtilsTest, EncodeDecodeVarUInt64) {
|
|
TestEncodeDecodeVarUInt<uint64_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
|
|
1 << 22, 1ULL << 55, 1ULL << 56,
|
|
0x7FFFFFFFFFFFFFFFULL, UINT64_MAX});
|
|
}
|
|
|
|
TEST(PatchUtilsTest, EncodeDecodeVarInt64) {
|
|
TestEncodeDecodeVarInt<int64_t>({0, 64, 128, 8192, 16384, 1 << 20, 1 << 21,
|
|
1 << 22, 1LL << 55, 1LL << 56, -1, INT64_MIN,
|
|
INT64_MAX});
|
|
}
|
|
|
|
TEST(PatchUtilsTest, DecodeVarUInt32Malformed) {
|
|
constexpr uint32_t kUninit = static_cast<uint32_t>(-1LL);
|
|
|
|
// Output variable to ensure that on failure, the output variable is not
|
|
// written to.
|
|
uint32_t value = uint32_t(-1);
|
|
|
|
auto TestDecodeVarInt = [&value](const std::vector<uint8_t>& buffer) {
|
|
value = kUninit;
|
|
return DecodeVarUInt(buffer.begin(), buffer.end(), &value);
|
|
};
|
|
|
|
// Exhausted.
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>{}));
|
|
EXPECT_EQ(kUninit, value);
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>(4, 128)));
|
|
EXPECT_EQ(kUninit, value);
|
|
|
|
// Overflow.
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>(6, 128)));
|
|
EXPECT_EQ(kUninit, value);
|
|
EXPECT_EQ(0, TestDecodeVarInt({128, 128, 128, 128, 128, 42}));
|
|
EXPECT_EQ(kUninit, value);
|
|
|
|
// Following are pathological cases that are not handled for simplicity,
|
|
// hence decoding is expected to be successful.
|
|
EXPECT_NE(0, TestDecodeVarInt({128, 128, 128, 128, 16}));
|
|
EXPECT_EQ(uint32_t(0), value);
|
|
EXPECT_NE(0, TestDecodeVarInt({128, 128, 128, 128, 32}));
|
|
EXPECT_EQ(uint32_t(0), value);
|
|
EXPECT_NE(0, TestDecodeVarInt({128, 128, 128, 128, 64}));
|
|
EXPECT_EQ(uint32_t(0), value);
|
|
}
|
|
|
|
TEST(PatchUtilsTest, DecodeVarUInt64Malformed) {
|
|
constexpr uint64_t kUninit = static_cast<uint64_t>(-1);
|
|
|
|
uint64_t value = kUninit;
|
|
auto TestDecodeVarInt = [&value](const std::vector<uint8_t>& buffer) {
|
|
value = kUninit;
|
|
return DecodeVarUInt(buffer.begin(), buffer.end(), &value);
|
|
};
|
|
|
|
// Exhausted.
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>{}));
|
|
EXPECT_EQ(kUninit, value);
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>(9, 128)));
|
|
EXPECT_EQ(kUninit, value);
|
|
|
|
// Overflow.
|
|
EXPECT_EQ(0, TestDecodeVarInt(std::vector<uint8_t>(10, 128)));
|
|
EXPECT_EQ(kUninit, value);
|
|
EXPECT_EQ(0, TestDecodeVarInt(
|
|
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 42}));
|
|
EXPECT_EQ(kUninit, value);
|
|
}
|
|
|
|
} // namespace zucchini
|