1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/zucchini/element_detection.h"
#include <map>
#include <vector>
#include "base/functional/bind.h"
#include "components/zucchini/buffer_view.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace zucchini {
namespace {
// This test uses a mock archive format where regions are determined by their
// consecutive byte values rather than parsing real executables.
//
// 0 - Padding or raw data (not mapped to an executable).
// 1 - A Win32x86 executable.
// 2 - A Win32x64 executable.
//
// So an example archive file of;
// 0 1 1 1 0 1 1 0 0 2 2 2 2
// contains (in order left to right):
// - One padding byte
// - Three byte Win32x86 executable
// - One padding byte
// - Two byte Win32x86 executable
// - Two padding bytes
// - Four byte Win32x64 executable
class ElementDetectionTest : public ::testing::Test {
protected:
using ElementVector = std::vector<Element>;
using ExeTypeMap = std::map<uint8_t, ExecutableType>;
ElementDetectionTest()
: exe_map_({{1, kExeTypeWin32X86}, {2, kExeTypeWin32X64}}) {}
ElementVector TestElementFinder(std::vector<uint8_t> buffer,
offset_t init_pos) {
ConstBufferView image(buffer.data(), buffer.size());
ElementFinder finder(
image,
base::BindRepeating(
[](ExeTypeMap exe_map, ConstBufferView image,
ConstBufferView region) -> std::optional<Element> {
EXPECT_GE(region.begin(), image.begin());
EXPECT_LE(region.end(), image.end());
EXPECT_GE(region.size(), 0U);
if (region[0] != 0) {
offset_t length = 1;
while (length < region.size() && region[length] == region[0])
++length;
return Element{{0, length}, exe_map[region[0]]};
}
return std::nullopt;
},
exe_map_, image),
init_pos);
std::vector<Element> elements;
for (auto element = finder.GetNext(); element; element = finder.GetNext()) {
elements.push_back(*element);
}
return elements;
}
ElementVector TestElementFinder(std::vector<uint8_t> buffer) {
return TestElementFinder(buffer, /* init_pos= */ 0U);
}
// Translation map from mock archive bytes to actual types used in Zucchini.
ExeTypeMap exe_map_;
};
TEST_F(ElementDetectionTest, ElementFinderEmpty) {
std::vector<uint8_t> buffer(10, 0);
ElementFinder finder(
ConstBufferView(buffer.data(), buffer.size()),
base::BindRepeating([](ConstBufferView image) -> std::optional<Element> {
return std::nullopt;
}),
/* init_pos= */ 0U);
EXPECT_EQ(std::nullopt, finder.GetNext());
}
TEST_F(ElementDetectionTest, ElementFinder) {
EXPECT_EQ(ElementVector(), TestElementFinder({}));
EXPECT_EQ(ElementVector(), TestElementFinder({0, 0}));
EXPECT_EQ(ElementVector({{{0, 2}, kExeTypeWin32X86}}),
TestElementFinder({1, 1}));
EXPECT_EQ(
ElementVector({{{0, 2}, kExeTypeWin32X86}, {{2, 2}, kExeTypeWin32X64}}),
TestElementFinder({1, 1, 2, 2}));
EXPECT_EQ(ElementVector({{{1, 2}, kExeTypeWin32X86}}),
TestElementFinder({0, 1, 1, 0}));
EXPECT_EQ(
ElementVector({{{1, 2}, kExeTypeWin32X86}, {{3, 3}, kExeTypeWin32X64}}),
TestElementFinder({0, 1, 1, 2, 2, 2}));
EXPECT_EQ(
ElementVector({{{1, 2}, kExeTypeWin32X86}, {{4, 3}, kExeTypeWin32X64}}),
TestElementFinder({0, 1, 1, 0, 2, 2, 2}));
EXPECT_EQ(ElementVector({{{4, 3}, kExeTypeWin32X64}}),
TestElementFinder({0, 1, 1, 0, 2, 2, 2}, /* init_pos= */ 3U));
}
} // namespace
} // namespace zucchini
|