blob: b10265678018e575d2de970552b17bc92b4d9f9a [file] [log] [blame]
/*
* Copyright 2014-present Facebook, Inc.
*
* 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.
*/
package com.facebook.buck.android;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.rules.Sha1HashCode;
import com.facebook.buck.testutil.integration.BuckBuildLog;
import com.facebook.buck.testutil.integration.DebuggableTemporaryFolder;
import com.facebook.buck.testutil.integration.ProjectWorkspace;
import com.facebook.buck.testutil.integration.TestDataHelper;
import com.facebook.buck.testutil.integration.ZipInspector;
import com.facebook.buck.util.DefaultPropertyFinder;
import com.facebook.buck.util.ProcessExecutor;
import com.facebook.buck.util.VersionStringComparator;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Pattern;
public class AndroidResourceFilterIntegrationTest {
private static boolean isBuildToolsNew;
private static Path pathToAapt;
private static final String APK_PATH_FORMAT = "buck-out/gen/apps/sample/%s.apk";
@Rule
public DebuggableTemporaryFolder tmpFolder = new DebuggableTemporaryFolder();
private ProjectWorkspace workspace;
@BeforeClass
public static void findBuildToolsVersion() {
AssumeAndroidPlatform.assumeSdkIsAvailable();
ProjectFilesystem filesystem = new ProjectFilesystem(Paths.get("."));
AndroidDirectoryResolver resolver = new DefaultAndroidDirectoryResolver(
filesystem,
Optional.<String>absent(),
new DefaultPropertyFinder(filesystem, ImmutableMap.copyOf(System.getenv())));
pathToAapt = AndroidPlatformTarget.getDefaultPlatformTarget(
resolver,
Optional.<Path>absent()).getAaptExecutable();
String buildToolsVersion = pathToAapt.getParent().getFileName().toString();
isBuildToolsNew = new VersionStringComparator().compare(buildToolsVersion, "21") >= 0;
}
@Before
public void setUp() throws IOException {
workspace = TestDataHelper.createProjectWorkspaceForScenario(
this, "android_project", tmpFolder);
workspace.setUp();
}
@Test
public void testApkWithoutResourceFilter() throws IOException {
ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", "//apps/sample:app");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app"));
ZipInspector zipInspector = new ZipInspector(apkFile);
if (isBuildToolsNew) {
zipInspector.assertFileExists("res/drawable-mdpi-v4/app_icon.png");
zipInspector.assertFileExists("res/drawable-hdpi-v4/app_icon.png");
zipInspector.assertFileExists("res/drawable-xhdpi-v4/app_icon.png");
} else {
zipInspector.assertFileExists("res/drawable-mdpi/app_icon.png");
zipInspector.assertFileExists("res/drawable-hdpi/app_icon.png");
zipInspector.assertFileExists("res/drawable-xhdpi/app_icon.png");
}
}
@Test
public void testApkWithMdpiFilter() throws IOException {
ProjectWorkspace.ProcessResult result =
workspace.runBuckCommand("build", "//apps/sample:app_mdpi");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_mdpi"));
ZipInspector zipInspector = new ZipInspector(apkFile);
if (isBuildToolsNew) {
zipInspector.assertFileExists("res/drawable-mdpi-v4/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-hdpi-v4/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-xhdpi-v4/app_icon.png");
} else {
zipInspector.assertFileExists("res/drawable-mdpi/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-hdpi/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-xhdpi/app_icon.png");
}
}
@Test
public void testModifyingImageRebuildsResourcesFilter() throws IOException {
ProjectWorkspace.ProcessResult result = workspace.runBuckBuild("//apps/sample:app_mdpi");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_mdpi"));
String iconPath = isBuildToolsNew
? "res/drawable-mdpi-v4/app_icon.png"
: "res/drawable-mdpi/app_icon.png";
long firstImageCrc = new ZipInspector(apkFile).getCrc(iconPath);
workspace.copyFile(
"res/com/sample/base/res/drawable-hdpi/app_icon.png",
"res/com/sample/base/res/drawable-mdpi/app_icon.png");
workspace.resetBuildLogFile();
result = workspace.runBuckBuild("//apps/sample:app_mdpi");
result.assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetBuiltLocally("//apps/sample:app_mdpi");
apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_mdpi"));
long secondImageCrc = new ZipInspector(apkFile).getCrc(iconPath);
assertNotEquals(firstImageCrc, secondImageCrc);
}
@Test
public void testApkWithXhdpiAndHdpiFilter() throws IOException {
ProjectWorkspace.ProcessResult result =
workspace.runBuckCommand("build", "//apps/sample:app_hdpi_xhdpi");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_hdpi_xhdpi"));
ZipInspector zipInspector = new ZipInspector(apkFile);
if (isBuildToolsNew) {
zipInspector.assertFileDoesNotExist("res/drawable-mdpi-v4/app_icon.png");
zipInspector.assertFileExists("res/drawable-hdpi-v4/app_icon.png");
zipInspector.assertFileExists("res/drawable-xhdpi-v4/app_icon.png");
} else {
zipInspector.assertFileDoesNotExist("res/drawable-mdpi/app_icon.png");
zipInspector.assertFileExists("res/drawable-hdpi/app_icon.png");
zipInspector.assertFileExists("res/drawable-xhdpi/app_icon.png");
}
}
@Test
public void testApkWithStringsAsAssets() throws IOException {
ProjectWorkspace.ProcessResult result =
workspace.runBuckCommand("build", "//apps/sample:app_comp_str");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_comp_str"));
ZipInspector zipInspector = new ZipInspector(apkFile);
zipInspector.assertFileExists("assets/strings/fr.fbstr");
}
@Test
public void testStringArtifactsAreCached() throws IOException {
workspace.enableDirCache();
workspace.runBuckBuild("//apps/sample:app_comp_str").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
Sha1HashCode androidBinaryRuleKey = buildLog.getRuleKey("//apps/sample:app_comp_str");
File cachedFile = workspace.getFile("buck-cache/" + androidBinaryRuleKey.getHash());
assertTrue(cachedFile.delete());
workspace.runBuckCommand("clean").assertSuccess();
workspace.runBuckBuild("//apps/sample:app_comp_str").assertSuccess();
}
@Test
public void testApkWithStringsAsAssetsAndResourceFilter() throws IOException {
ProjectWorkspace.ProcessResult result =
workspace.runBuckBuild("//apps/sample:app_comp_str_xhdpi");
result.assertSuccess();
File apkFile = workspace.getFile(String.format(APK_PATH_FORMAT, "app_comp_str_xhdpi"));
ZipInspector zipInspector = new ZipInspector(apkFile);
zipInspector.assertFileExists("assets/strings/fr.fbstr");
if (isBuildToolsNew) {
zipInspector.assertFileExists("res/drawable-xhdpi-v4/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-hdpi-v4/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-mdpi-v4/app_icon.png");
} else {
zipInspector.assertFileExists("res/drawable-xhdpi/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-hdpi/app_icon.png");
zipInspector.assertFileDoesNotExist("res/drawable-mdpi/app_icon.png");
}
}
@Test
public void testAsset() throws IOException {
workspace.enableDirCache();
workspace.runBuckBuild("//apps/sample:app").assertSuccess();
String apkFilePath = String.format(APK_PATH_FORMAT, "app");
File apkFile = workspace.getFile(apkFilePath);
ZipInspector zipInspector = new ZipInspector(apkFile);
long firstCrc = zipInspector.getCrc("assets/asset_file.txt");
workspace.replaceFileContents(
"res/com/sample/asset_only/assets/asset_file.txt",
"Hello",
"Bye");
workspace.runBuckBuild("//apps/sample:app").assertSuccess();
apkFile = workspace.getFile(apkFilePath);
zipInspector = new ZipInspector(apkFile);
long secondCrc = zipInspector.getCrc("assets/asset_file.txt");
assertNotEquals("Rebuilt APK file must include the new asset file.", firstCrc, secondCrc);
}
@Test
public void testEnglishBuildDoesntContainFrenchStrings()
throws IOException, InterruptedException {
workspace.runBuckBuild("//apps/sample:app").assertSuccess();
String apkFilePath = String.format(APK_PATH_FORMAT, "app");
File apkFile = workspace.getFile(apkFilePath);
int matchingLines = runAaptDumpResources(apkFile);
assertEquals(2, matchingLines);
workspace.runBuckBuild("//apps/sample:app_en").assertSuccess();
apkFilePath = String.format(APK_PATH_FORMAT, "app_en");
apkFile = workspace.getFile(apkFilePath);
matchingLines = runAaptDumpResources(apkFile);
assertEquals(1, matchingLines);
}
private int runAaptDumpResources(File apkFile) throws IOException, InterruptedException {
final Pattern pattern = Pattern.compile(".*com.example:string/base_button: t=.*");
ProcessExecutor.Result result = workspace.runCommand(
pathToAapt.toAbsolutePath().toString(),
"dump",
"resources",
apkFile.getAbsolutePath());
assertEquals(0, result.getExitCode());
return FluentIterable.from(
Splitter.on('\n').split(result.getStdout().or(""))).filter(
new Predicate<String>() {
@Override
public boolean apply(String input) {
return pattern.matcher(input).matches();
}
}).size();
}
}