blob: 814f4aa2cbf82c44d8aa570fa7651022653d35e9 [file] [log] [blame]
/*
* Copyright (C) 2015 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.
*/
package android.databinding.compilationTest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import android.databinding.tool.store.Location;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class BaseCompilationTest {
private static final String PRINT_ENCODED_ERRORS_PROPERTY
= "android.databinding.injected.print.encoded.errors";
@Rule
public TestName name = new TestName();
static Pattern VARIABLES = Pattern.compile("!@\\{([A-Za-z0-9_-]*)}");
public static final String KEY_MANIFEST_PACKAGE = "PACKAGE";
public static final String KEY_DEPENDENCIES = "DEPENDENCIES";
public static final String KEY_SETTINGS_INCLUDES = "SETTINGS_INCLUDES";
public static final String DEFAULT_APP_PACKAGE = "com.android.databinding.compilationTest.test";
public static final String KEY_CLASS_NAME = "CLASSNAME";
public static final String KEY_CLASS_TYPE = "CLASSTYPE";
public static final String KEY_IMPORT_TYPE = "IMPORTTYPE";
public static final String KEY_INCLUDE_ID = "INCLUDEID";
public static final String KEY_VIEW_ID = "VIEWID";
protected final File testFolder = new File("./build/build-test");
protected void copyResourceTo(String name, String path) throws IOException {
copyResourceTo(name, new File(testFolder, path));
}
protected void copyResourceTo(String name, String path, Map<String, String> replacements)
throws IOException {
copyResourceTo(name, new File(testFolder, path), replacements);
}
protected void copyResourceDirectory(String name, String targetPath)
throws URISyntaxException, IOException {
URL dir = getClass().getResource(name);
assertNotNull(dir);
assertEquals("file", dir.getProtocol());
File folder = new File(dir.toURI());
assertTrue(folder.isDirectory());
File target = new File(testFolder, targetPath);
int len = folder.getAbsolutePath().length() + 1;
for (File item : FileUtils.listFiles(folder, null, true)) {
if (item.getAbsolutePath().equals(folder.getAbsolutePath())) {
continue;
}
String resourcePath = item.getAbsolutePath().substring(len);
copyResourceTo(name + "/" + resourcePath, new File(target, resourcePath));
}
}
@Before
public void clear() throws IOException {
if (testFolder.exists()) {
FileUtils.forceDelete(testFolder);
}
}
/**
* Extracts the text in the given location from the the at the given application path.
*
* @param pathInApp The path, relative to the root of the application under test
* @param location The location to extract
* @return The string that is contained in the given location
* @throws IOException If file is invalid.
*/
protected String extract(String pathInApp, Location location) throws IOException {
File file = new File(testFolder, pathInApp);
assertTrue(file.exists());
StringBuilder result = new StringBuilder();
List<String> lines = FileUtils.readLines(file);
for (int i = location.startLine; i <= location.endLine; i++) {
if (i > location.startLine) {
result.append("\n");
}
String line = lines.get(i);
int start = 0;
if (i == location.startLine) {
start = location.startOffset;
}
int end = line.length() - 1; // inclusive
if (i == location.endLine) {
end = location.endOffset;
}
result.append(line.substring(start, end + 1));
}
return result.toString();
}
protected void copyResourceTo(String name, File targetFile) throws IOException {
File directory = targetFile.getParentFile();
FileUtils.forceMkdir(directory);
InputStream contents = getClass().getResourceAsStream(name);
FileOutputStream fos = new FileOutputStream(targetFile);
IOUtils.copy(contents, fos);
IOUtils.closeQuietly(fos);
IOUtils.closeQuietly(contents);
}
protected static Map<String, String> toMap(String... keysAndValues) {
assertEquals(0, keysAndValues.length % 2);
Map<String, String> map = new HashMap<>();
for (int i = 0; i < keysAndValues.length; i += 2) {
map.put(keysAndValues[i], keysAndValues[i + 1]);
}
return map;
}
protected void copyResourceTo(String name, File targetFile, Map<String, String> replacements)
throws IOException {
if (replacements.isEmpty()) {
copyResourceTo(name, targetFile);
}
InputStream inputStream = getClass().getResourceAsStream(name);
final String contents = IOUtils.toString(inputStream);
IOUtils.closeQuietly(inputStream);
StringBuilder out = new StringBuilder(contents.length());
final Matcher matcher = VARIABLES.matcher(contents);
int location = 0;
while (matcher.find()) {
int start = matcher.start();
if (start > location) {
out.append(contents, location, start);
}
final String key = matcher.group(1);
final String replacement = replacements.get(key);
if (replacement != null) {
out.append(replacement);
}
location = matcher.end();
}
if (location < contents.length()) {
out.append(contents, location, contents.length());
}
FileUtils.writeStringToFile(targetFile, out.toString());
}
protected void prepareProject() throws IOException, URISyntaxException {
prepareApp(null);
}
private Map<String, String> addDefaults(Map<String, String> map) {
if (map == null) {
map = new HashMap<>();
}
if (!map.containsKey(KEY_MANIFEST_PACKAGE)) {
map.put(KEY_MANIFEST_PACKAGE, DEFAULT_APP_PACKAGE);
}
if (!map.containsKey(KEY_SETTINGS_INCLUDES)) {
map.put(KEY_SETTINGS_INCLUDES, "include ':app'");
}
return map;
}
protected void prepareApp(Map<String, String> replacements) throws IOException,
URISyntaxException {
replacements = addDefaults(replacements);
// how to get build folder, pass from gradle somehow ?
FileUtils.forceMkdir(testFolder);
copyResourceTo("/AndroidManifest.xml",
new File(testFolder, "app/src/main/AndroidManifest.xml"), replacements);
copyResourceTo("/project_build.gradle", new File(testFolder, "build.gradle"), replacements);
copyResourceTo("/app_build.gradle", new File(testFolder, "app/build.gradle"), replacements);
copyResourceTo("/settings.gradle", new File(testFolder, "settings.gradle"), replacements);
File localProperties = new File("../local.properties");
if (localProperties.exists()) {
FileUtils.copyFile(localProperties, new File(testFolder, "local.properties"));
}
FileUtils.copyFile(new File("../propLoader.gradle"), new File(testFolder, "propLoaderClone.gradle"));
FileUtils.copyFile(new File("../gradlew"), new File(testFolder, "gradlew"));
FileUtils.copyDirectory(new File("../gradle"), new File(testFolder, "gradle"));
}
protected void prepareModule(String moduleName, String packageName,
Map<String, String> replacements) throws IOException, URISyntaxException {
replacements = addDefaults(replacements);
replacements.put(KEY_MANIFEST_PACKAGE, packageName);
File moduleFolder = new File(testFolder, moduleName);
if (moduleFolder.exists()) {
FileUtils.forceDelete(moduleFolder);
}
FileUtils.forceMkdir(moduleFolder);
copyResourceTo("/AndroidManifest.xml",
new File(moduleFolder, "src/main/AndroidManifest.xml"), replacements);
copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"),
replacements);
}
protected CompilationResult runGradle(String... params)
throws IOException, InterruptedException {
setExecutable();
File pathToExecutable = new File(testFolder, "gradlew");
List<String> args = new ArrayList<>();
args.add(pathToExecutable.getAbsolutePath());
args.add("-P" + PRINT_ENCODED_ERRORS_PROPERTY + "=true");
args.add("--project-cache-dir");
args.add(new File("../.caches/", name.getMethodName()).getAbsolutePath());
Collections.addAll(args, params);
ProcessBuilder builder = new ProcessBuilder(args);
builder.environment().putAll(System.getenv());
String javaHome = System.getProperty("java.home");
if (StringUtils.isNotBlank(javaHome)) {
builder.environment().put("JAVA_HOME", javaHome);
}
builder.directory(testFolder);
Process process = builder.start();
String output = IOUtils.toString(process.getInputStream());
String error = IOUtils.toString(process.getErrorStream());
int result = process.waitFor();
return new CompilationResult(result, output, error);
}
private void setExecutable() throws IOException {
Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
//add owners permission
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
//add group permissions
perms.add(PosixFilePermission.GROUP_READ);
//add others permissions
perms.add(PosixFilePermission.OTHERS_READ);
Files.setPosixFilePermissions(Paths.get(new File(testFolder, "gradlew").getAbsolutePath()),
perms);
}
}