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 <sys/types.h>
18
19 #include <memory>
20 #include <string>
21 #include <string_view>
22
23 #include <android-base/file.h>
24 #include <dex/dex_file.h>
25 #include <gtest/gtest.h>
26
27 #include "art_api/dex_file_external.h"
28 #include "dex_file_test_data.h"
29
30 namespace art_api {
31 namespace dex {
32
33 class ADexFileTest : public ::testing::Test {
34 protected:
TearDown()35 void TearDown() override {
36 ADexFile_destroy(dex_);
37 }
38
39 ADexFile* dex_ = nullptr;
40 };
41
TEST_F(ADexFileTest,create)42 TEST_F(ADexFileTest, create) {
43 size_t size = sizeof(kDexData);
44 EXPECT_EQ(ADexFile_create(kDexData, size, &size, "", &dex_), ADEXFILE_ERROR_OK);
45 EXPECT_EQ(size, sizeof(kDexData));
46 EXPECT_NE(dex_, nullptr);
47 }
48
TEST_F(ADexFileTest,create_null_new_size)49 TEST_F(ADexFileTest, create_null_new_size) {
50 const size_t size = sizeof(kDexData);
51 EXPECT_EQ(ADexFile_create(kDexData, size, nullptr, "", &dex_), ADEXFILE_ERROR_OK);
52 EXPECT_NE(dex_, nullptr);
53 }
54
TEST_F(ADexFileTest,create_header_too_small)55 TEST_F(ADexFileTest, create_header_too_small) {
56 size_t size = sizeof(art::DexFile::Header) - 1;
57 EXPECT_EQ(ADexFile_create(kDexData, size, &size, "", &dex_), ADEXFILE_ERROR_NOT_ENOUGH_DATA);
58 EXPECT_EQ(size, sizeof(art::DexFile::Header));
59 EXPECT_EQ(dex_, nullptr);
60 }
61
TEST_F(ADexFileTest,create_file_too_small)62 TEST_F(ADexFileTest, create_file_too_small) {
63 size_t size = sizeof(art::DexFile::Header);
64 EXPECT_EQ(ADexFile_create(kDexData, size, &size, "", &dex_), ADEXFILE_ERROR_NOT_ENOUGH_DATA);
65 EXPECT_EQ(size, sizeof(kDexData));
66 EXPECT_EQ(dex_, nullptr);
67 }
68
GetTestDexData()69 static ADexFile* GetTestDexData() {
70 size_t size = sizeof(kDexData);
71 ADexFile* dex;
72 EXPECT_EQ(ADexFile_create(kDexData, size, &size, "", &dex), ADEXFILE_ERROR_OK);
73 EXPECT_EQ(size, sizeof(kDexData));
74 EXPECT_NE(dex, nullptr);
75 return dex;
76 }
77
TEST_F(ADexFileTest,findMethodAtOffset)78 TEST_F(ADexFileTest, findMethodAtOffset) {
79 dex_ = GetTestDexData();
80 ASSERT_NE(dex_, nullptr);
81
82 bool found_init = false;
83 auto check_init = [](void* ctx, const ADexFile_Method* method) {
84 size_t size;
85 size_t offset = ADexFile_Method_getCodeOffset(method, &size);
86 EXPECT_EQ(offset, 0x100u);
87 EXPECT_EQ(size, 8u);
88 EXPECT_STREQ(ADexFile_Method_getName(method, &size), "<init>");
89 EXPECT_STREQ(ADexFile_Method_getQualifiedName(method, false, &size), "Main.<init>");
90 EXPECT_STREQ(ADexFile_Method_getQualifiedName(method, true, &size), "void Main.<init>()");
91 EXPECT_STREQ(ADexFile_Method_getClassDescriptor(method, &size), "LMain;");
92 *reinterpret_cast<bool*>(ctx) = true;
93 };
94 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x102, check_init, &found_init), 1u);
95 EXPECT_TRUE(found_init);
96
97 bool found_main = false;
98 auto check_main = [](void* ctx, const ADexFile_Method* method) {
99 size_t size;
100 size_t offset = ADexFile_Method_getCodeOffset(method, &size);
101 EXPECT_EQ(offset, 0x118u);
102 EXPECT_EQ(size, 2u);
103 EXPECT_STREQ(ADexFile_Method_getName(method, &size), "main");
104 EXPECT_STREQ(ADexFile_Method_getQualifiedName(method, false, &size), "Main.main");
105 EXPECT_STREQ(ADexFile_Method_getQualifiedName(method, true, &size), "void Main.main(java.lang.String[])");
106 EXPECT_STREQ(ADexFile_Method_getClassDescriptor(method, &size), "LMain;");
107 *reinterpret_cast<bool*>(ctx) = true;
108 };
109 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x118, check_main, &found_main), 1u);
110 EXPECT_TRUE(found_main);
111 }
112
TEST_F(ADexFileTest,findMethodAtOffset_for_offset_boundaries)113 TEST_F(ADexFileTest, findMethodAtOffset_for_offset_boundaries) {
114 dex_ = GetTestDexData();
115 ASSERT_NE(dex_, nullptr);
116
117 auto no_cb = [](void*, const ADexFile_Method*) {};
118 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x99, no_cb, nullptr), 0);
119 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x100, no_cb, nullptr), 1);
120 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x107, no_cb, nullptr), 1);
121 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x108, no_cb, nullptr), 0);
122 EXPECT_EQ(ADexFile_findMethodAtOffset(dex_, 0x100000, no_cb, nullptr), 0);
123 }
124
TEST_F(ADexFileTest,forEachMethod)125 TEST_F(ADexFileTest, forEachMethod) {
126 dex_ = GetTestDexData();
127 ASSERT_NE(dex_, nullptr);
128
129 std::vector<std::string> names;
130 auto add = [](void* ctx, const ADexFile_Method* method) {
131 reinterpret_cast<decltype(names)*>(ctx)->
132 push_back(ADexFile_Method_getQualifiedName(method, false, nullptr));
133 };
134 EXPECT_EQ(ADexFile_forEachMethod(dex_, add, &names), 2u);
135 EXPECT_EQ(names, std::vector<std::string>({"Main.<init>", "Main.main"}));
136 }
137
TEST_F(ADexFileTest,Error_toString)138 TEST_F(ADexFileTest, Error_toString) {
139 constexpr size_t kNumErrors = 4;
140 for (size_t i = 0; i < kNumErrors; i++) {
141 const char* err = ADexFile_Error_toString(static_cast<ADexFile_Error>(i));
142 ASSERT_NE(err, nullptr);
143 ASSERT_FALSE(std::string_view(err).empty());
144 }
145 const char* err = ADexFile_Error_toString(static_cast<ADexFile_Error>(kNumErrors));
146 ASSERT_EQ(err, nullptr);
147 }
148
149 } // namespace dex
150 } // namespace art_api
151