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