1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android-base/file.h>
18
19 #include <gtest/gtest.h>
20
21 #include <MemoryBuffer.h>
22 #include <MemoryXz.h>
23
24 namespace unwindstack {
25
26 class MemoryXzTest : public ::testing::Test {
27 protected:
SetUp()28 void SetUp() override { expected_content_ = ReadFile("boot_arm.oat.gnu_debugdata"); }
29
ReadFile(const char * filename)30 static std::unique_ptr<MemoryBuffer> ReadFile(const char* filename) {
31 std::string dir = android::base::GetExecutableDirectory() + "/tests/files/";
32 std::string data; // NB: It is actually binary data.
33 EXPECT_TRUE(android::base::ReadFileToString(dir + filename, &data)) << filename;
34 EXPECT_GT(data.size(), 0u);
35 auto memory = std::make_unique<MemoryBuffer>(data.size());
36 EXPECT_EQ(data.size(), memory->Size());
37 memcpy(memory->GetPtr(0), data.data(), data.size());
38 return memory;
39 }
40
VerifyContent(MemoryXz & xz,uint64_t offset,uint64_t size)41 void VerifyContent(MemoryXz& xz, uint64_t offset, uint64_t size) {
42 EXPECT_EQ(xz.Size(), expected_content_->Size());
43 EXPECT_LE(offset + size, expected_content_->Size());
44 std::vector<uint8_t> seen_content(size);
45 xz.ReadFully(offset, seen_content.data(), size);
46 EXPECT_EQ(memcmp(seen_content.data(), expected_content_->GetPtr(offset), size), 0);
47 }
48
49 std::unique_ptr<MemoryBuffer> expected_content_;
50 };
51
52 // Test the expected random-accessible format.
TEST_F(MemoryXzTest,Decompress)53 TEST_F(MemoryXzTest, Decompress) {
54 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz");
55 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
56 EXPECT_TRUE(xz.Init());
57 EXPECT_GT(xz.BlockCount(), 1u);
58 EXPECT_EQ(xz.BlockSize(), 16 * 1024u);
59 EXPECT_EQ(xz.MemoryUsage(), 0u);
60 VerifyContent(xz, 0, expected_content_->Size());
61 EXPECT_EQ(xz.MemoryUsage(), xz.Size());
62 }
63
64 // Test one big monolithic compressed block.
TEST_F(MemoryXzTest,DecompressOneBlock)65 TEST_F(MemoryXzTest, DecompressOneBlock) {
66 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz.one-block");
67 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
68 EXPECT_TRUE(xz.Init());
69 EXPECT_EQ(xz.BlockCount(), 1u);
70 EXPECT_GT(xz.BlockSize(), xz.Size());
71 EXPECT_EQ(xz.MemoryUsage(), 0u);
72 VerifyContent(xz, 0, expected_content_->Size());
73 EXPECT_EQ(xz.MemoryUsage(), xz.Size());
74 }
75
76 // Test fallback (non-consistent block sizes).
TEST_F(MemoryXzTest,DecompressOddSizes)77 TEST_F(MemoryXzTest, DecompressOddSizes) {
78 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz.odd-sizes");
79 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
80 EXPECT_TRUE(xz.Init());
81 EXPECT_EQ(xz.BlockCount(), 1u);
82 EXPECT_GT(xz.BlockSize(), xz.Size());
83 EXPECT_EQ(xz.MemoryUsage(), xz.Size());
84 VerifyContent(xz, 0, expected_content_->Size());
85 }
86
87 // Test fallback (non-power-of-2 block size).
TEST_F(MemoryXzTest,DecompressNonPower)88 TEST_F(MemoryXzTest, DecompressNonPower) {
89 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz.non-power");
90 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
91 EXPECT_TRUE(xz.Init());
92 EXPECT_EQ(xz.BlockCount(), 1u);
93 EXPECT_GT(xz.BlockSize(), xz.Size());
94 EXPECT_EQ(xz.MemoryUsage(), xz.Size());
95 VerifyContent(xz, 0, expected_content_->Size());
96 }
97
98 // Read first byte of some blocks.
TEST_F(MemoryXzTest,ReadFirstByte)99 TEST_F(MemoryXzTest, ReadFirstByte) {
100 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz");
101 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
102 EXPECT_TRUE(xz.Init());
103 EXPECT_GT(xz.BlockCount(), 1u);
104 EXPECT_EQ(xz.BlockSize(), 16 * 1024u);
105 for (size_t i = 0; i < xz.BlockCount(); i += 3) {
106 VerifyContent(xz, i * xz.BlockSize(), 1);
107 }
108 EXPECT_LT(xz.MemoryUsage(), xz.Size()); // We didn't decompress all blocks.
109 }
110
111 // Read last byte of some blocks.
TEST_F(MemoryXzTest,ReadLastByte)112 TEST_F(MemoryXzTest, ReadLastByte) {
113 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz");
114 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
115 EXPECT_TRUE(xz.Init());
116 EXPECT_GT(xz.BlockCount(), 1u);
117 EXPECT_EQ(xz.BlockSize(), 16 * 1024u);
118 for (size_t i = 1; i < xz.BlockCount(); i += 3) {
119 VerifyContent(xz, i * xz.BlockSize() - 1, 1);
120 }
121 EXPECT_LT(xz.MemoryUsage(), xz.Size()); // We didn't decompress all blocks.
122 }
123
124 // Read across boundary of blocks.
TEST_F(MemoryXzTest,ReadBoundary)125 TEST_F(MemoryXzTest, ReadBoundary) {
126 auto compressed = ReadFile("boot_arm.oat.gnu_debugdata.xz");
127 MemoryXz xz(compressed.get(), 0, compressed->Size(), "boot_arm.oat");
128 EXPECT_TRUE(xz.Init());
129 EXPECT_GT(xz.BlockCount(), 1u);
130 EXPECT_EQ(xz.BlockSize(), 16 * 1024u);
131 for (size_t i = 1; i < xz.BlockCount(); i += 3) {
132 VerifyContent(xz, i * xz.BlockSize() - 1, 2);
133 }
134 EXPECT_LT(xz.MemoryUsage(), xz.Size()); // We didn't decompress all blocks.
135 }
136
137 } // namespace unwindstack
138