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