Ryan Mitchell 81dfca0e05 Fix asset compression to check name ends with arg
There exists a discrepancy between how aapt1 and aapt2 prevent the
compression of assets using the -0 flag. aapt1 checked if the file name
ended with an argument, but aapt2 is checking if the file extension
exactly matches the argument. This change makes aapt2 behave the same as
aapt1 for asset compression using the -0 flag.

Bug: 132823799
Test: aapt2_tests
Change-Id: I641b3ebce29e4407b543faea373a5ce516b70cda
2019-06-10 08:59:52 -07:00

173 lines
6.1 KiB
C++

/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "test/Fixture.h"
#include <dirent.h>
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/utf8.h"
#include "androidfw/StringPiece.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "cmd/Compile.h"
#include "cmd/Link.h"
#include "io/FileStream.h"
#include "io/Util.h"
#include "util/Files.h"
using testing::Eq;
using testing::Ne;
namespace aapt {
const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
void ClearDirectory(const android::StringPiece& path) {
const std::string root_dir = path.to_string();
std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
if (!dir) {
StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
return;
}
while (struct dirent* entry = readdir(dir.get())) {
// Do not delete hidden files and do not recurse to the parent of this directory
if (util::StartsWith(entry->d_name, ".")) {
continue;
}
std::string full_path = file::BuildPath({root_dir, entry->d_name});
if (file::GetFileType(full_path) == file::FileType::kDirectory) {
ClearDirectory(full_path);
#ifdef _WIN32
_rmdir(full_path.c_str());
#else
rmdir(full_path.c_str());
#endif
} else {
android::base::utf8::unlink(full_path.c_str());
}
}
}
void TestDirectoryFixture::SetUp() {
temp_dir_ = file::BuildPath({android::base::GetExecutableDirectory(),
"_temp",
testing::UnitTest::GetInstance()->current_test_case()->name(),
testing::UnitTest::GetInstance()->current_test_info()->name()});
ASSERT_TRUE(file::mkdirs(temp_dir_));
ClearDirectory(temp_dir_);
}
void TestDirectoryFixture::TearDown() {
ClearDirectory(temp_dir_);
}
void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
CHECK(util::StartsWith(path, temp_dir_))
<< "Attempting to create a file outside of test temporary directory.";
// Create any intermediate directories specified in the path
auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep);
if (pos != path.rend()) {
std::string dirs = path.substr(0, (&*pos - path.data()));
file::mkdirs(dirs);
}
CHECK(android::base::WriteStringToFile(contents, path));
}
bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
const android::StringPiece& out_dir, IDiagnostics* diag) {
WriteFile(path, contents);
CHECK(file::mkdirs(out_dir.data()));
return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
}
bool CommandTestFixture::Link(const std::vector<std::string>& args, IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
}
// Link against the android SDK
std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
"integration-tests", "CommandTests",
"android-28.jar"});
link_args.insert(link_args.end(), {"-I", android_sdk});
return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
}
bool CommandTestFixture::Link(const std::vector<std::string>& args,
const android::StringPiece& flat_dir, IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
}
// Link against the android SDK
std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
"integration-tests", "CommandTests",
"android-28.jar"});
link_args.insert(link_args.end(), {"-I", android_sdk});
// Add the files from the compiled resources directory to the link file arguments
Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
if (compiled_files) {
for (std::string& compile_file : compiled_files.value()) {
compile_file = file::BuildPath({flat_dir, compile_file});
link_args.emplace_back(std::move(compile_file));
}
}
return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
}
std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
const std::string manifest_file = GetTestPath("AndroidManifest.xml");
WriteFile(manifest_file, android::base::StringPrintf(R"(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="%s">
</manifest>)", package_name));
return manifest_file;
}
std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
const android::StringPiece& path) {
return apk
->GetFileCollection()
->FindFile(path)
->OpenAsData();
}
void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data,
android::ResXMLTree *out_tree) {
ASSERT_THAT(apk, Ne(nullptr));
out_tree->setTo(data->data(), data->size());
ASSERT_THAT(out_tree->getError(), Eq(android::OK));
while (out_tree->next() != android::ResXMLTree::START_TAG) {
ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
}
}
} // namespace aapt