BaseCompilationTest.java revision 08119ea342cb47910ca80ff646d746f00e4663ce
1/* 2 * Copyright (C) 2015 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 17package android.databinding.compilationTest; 18 19import org.apache.commons.io.FileUtils; 20import org.apache.commons.io.IOUtils; 21import org.junit.Before; 22import org.junit.Rule; 23import org.junit.rules.TestName; 24 25import android.databinding.tool.store.Location; 26 27import java.io.File; 28import java.io.FileOutputStream; 29import java.io.IOException; 30import java.io.InputStream; 31import java.net.URISyntaxException; 32import java.net.URL; 33import java.nio.file.Files; 34import java.nio.file.Paths; 35import java.nio.file.attribute.PosixFilePermission; 36import java.util.ArrayList; 37import java.util.Collections; 38import java.util.HashMap; 39import java.util.HashSet; 40import java.util.List; 41import java.util.Map; 42import java.util.Set; 43import java.util.regex.Matcher; 44import java.util.regex.Pattern; 45 46import static org.junit.Assert.assertEquals; 47import static org.junit.Assert.assertNotNull; 48import static org.junit.Assert.assertTrue; 49 50 51public class BaseCompilationTest { 52 53 private static final String PRINT_ENCODED_ERRORS_PROPERTY 54 = "android.databinding.injected.print.encoded.errors"; 55 @Rule 56 public TestName name = new TestName(); 57 static Pattern VARIABLES = Pattern.compile("!@\\{([A-Za-z0-9_-]*)}"); 58 59 public static final String KEY_MANIFEST_PACKAGE = "PACKAGE"; 60 public static final String KEY_DEPENDENCIES = "DEPENDENCIES"; 61 public static final String KEY_SETTINGS_INCLUDES = "SETTINGS_INCLUDES"; 62 public static final String DEFAULT_APP_PACKAGE = "com.android.databinding.compilationTest.test"; 63 64 protected final File testFolder = new File("./build/build-test"); 65 66 protected void copyResourceTo(String name, String path) throws IOException { 67 copyResourceTo(name, new File(testFolder, path)); 68 } 69 70 protected void copyResourceDirectory(String name, String targetPath) 71 throws URISyntaxException, IOException { 72 URL dir = getClass().getResource(name); 73 assertNotNull(dir); 74 assertEquals("file", dir.getProtocol()); 75 File folder = new File(dir.toURI()); 76 assertTrue(folder.isDirectory()); 77 File target = new File(testFolder, targetPath); 78 int len = folder.getAbsolutePath().length() + 1; 79 for (File item : FileUtils.listFiles(folder, null, true)) { 80 if (item.getAbsolutePath().equals(folder.getAbsolutePath())) { 81 continue; 82 } 83 String resourcePath = item.getAbsolutePath().substring(len); 84 85 copyResourceTo(name + "/" + resourcePath, new File(target, resourcePath)); 86 } 87 } 88 89 @Before 90 public void clear() throws IOException { 91 if (testFolder.exists()) { 92 FileUtils.forceDelete(testFolder); 93 } 94 } 95 96 /** 97 * Extracts the text in the given location from the the at the given application path. 98 * 99 * @param pathInApp The path, relative to the root of the application under test 100 * @param location The location to extract 101 * @return The string that is contained in the given location 102 * @throws IOException If file is invalid. 103 */ 104 protected String extract(String pathInApp, Location location) throws IOException { 105 File file = new File(testFolder, pathInApp); 106 assertTrue(file.exists()); 107 StringBuilder result = new StringBuilder(); 108 List<String> lines = FileUtils.readLines(file); 109 for (int i = location.startLine; i <= location.endLine; i++) { 110 if (i > location.startLine) { 111 result.append("\n"); 112 } 113 String line = lines.get(i); 114 int start = 0; 115 if (i == location.startLine) { 116 start = location.startOffset; 117 } 118 int end = line.length() - 1; // inclusive 119 if (i == location.endLine) { 120 end = location.endOffset; 121 } 122 result.append(line.substring(start, end + 1)); 123 } 124 return result.toString(); 125 } 126 127 protected void copyResourceTo(String name, File targetFile) throws IOException { 128 File directory = targetFile.getParentFile(); 129 FileUtils.forceMkdir(directory); 130 InputStream contents = getClass().getResourceAsStream(name); 131 FileOutputStream fos = new FileOutputStream(targetFile); 132 IOUtils.copy(contents, fos); 133 IOUtils.closeQuietly(fos); 134 IOUtils.closeQuietly(contents); 135 } 136 137 protected static Map<String, String> toMap(String... keysAndValues) { 138 assertEquals(0, keysAndValues.length % 2); 139 Map<String, String> map = new HashMap<>(); 140 for (int i = 0; i < keysAndValues.length; i += 2) { 141 map.put(keysAndValues[i], keysAndValues[i + 1]); 142 } 143 return map; 144 } 145 146 protected void copyResourceTo(String name, File targetFile, Map<String, String> replacements) 147 throws IOException { 148 if (replacements.isEmpty()) { 149 copyResourceTo(name, targetFile); 150 } 151 InputStream inputStream = getClass().getResourceAsStream(name); 152 final String contents = IOUtils.toString(inputStream); 153 IOUtils.closeQuietly(inputStream); 154 155 StringBuilder out = new StringBuilder(contents.length()); 156 final Matcher matcher = VARIABLES.matcher(contents); 157 int location = 0; 158 while (matcher.find()) { 159 int start = matcher.start(); 160 if (start > location) { 161 out.append(contents, location, start); 162 } 163 final String key = matcher.group(1); 164 final String replacement = replacements.get(key); 165 if (replacement != null) { 166 out.append(replacement); 167 } 168 location = matcher.end(); 169 } 170 if (location < contents.length()) { 171 out.append(contents, location, contents.length()); 172 } 173 174 FileUtils.writeStringToFile(targetFile, out.toString()); 175 } 176 177 protected void prepareProject() throws IOException, URISyntaxException { 178 prepareApp(null); 179 } 180 181 private Map<String, String> addDefaults(Map<String, String> map) { 182 if (map == null) { 183 map = new HashMap<>(); 184 } 185 if (!map.containsKey(KEY_MANIFEST_PACKAGE)) { 186 map.put(KEY_MANIFEST_PACKAGE, DEFAULT_APP_PACKAGE); 187 } 188 if (!map.containsKey(KEY_SETTINGS_INCLUDES)) { 189 map.put(KEY_SETTINGS_INCLUDES, "include ':app'"); 190 } 191 return map; 192 } 193 194 protected void prepareApp(Map<String, String> replacements) throws IOException, 195 URISyntaxException { 196 replacements = addDefaults(replacements); 197 // how to get build folder, pass from gradle somehow ? 198 FileUtils.forceMkdir(testFolder); 199 copyResourceTo("/AndroidManifest.xml", 200 new File(testFolder, "app/src/main/AndroidManifest.xml"), replacements); 201 copyResourceTo("/project_build.gradle", new File(testFolder, "build.gradle"), replacements); 202 copyResourceTo("/app_build.gradle", new File(testFolder, "app/build.gradle"), replacements); 203 copyResourceTo("/settings.gradle", new File(testFolder, "settings.gradle"), replacements); 204 File localProperties = new File("../local.properties"); 205 if (localProperties.exists()) { 206 FileUtils.copyFile(localProperties, new File(testFolder, "local.properties")); 207 } 208 FileUtils.copyFile(new File("../gradlew"), new File(testFolder, "gradlew")); 209 FileUtils.copyDirectory(new File("../gradle"), new File(testFolder, "gradle")); 210 } 211 212 protected void prepareModule(String moduleName, String packageName, 213 Map<String, String> replacements) throws IOException, URISyntaxException { 214 replacements = addDefaults(replacements); 215 replacements.put(KEY_MANIFEST_PACKAGE, packageName); 216 File moduleFolder = new File(testFolder, moduleName); 217 if (moduleFolder.exists()) { 218 FileUtils.forceDelete(moduleFolder); 219 } 220 FileUtils.forceMkdir(moduleFolder); 221 copyResourceTo("/AndroidManifest.xml", 222 new File(moduleFolder, "src/main/AndroidManifest.xml"), replacements); 223 copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"), 224 replacements); 225 } 226 227 protected CompilationResult runGradle(String... params) 228 throws IOException, InterruptedException { 229 setExecutable(); 230 File pathToExecutable = new File(testFolder, "gradlew"); 231 List<String> args = new ArrayList<>(); 232 args.add(pathToExecutable.getAbsolutePath()); 233 args.add("-P" + PRINT_ENCODED_ERRORS_PROPERTY + "=true"); 234 args.add("--project-cache-dir"); 235 args.add(new File("../.caches/", name.getMethodName()).getAbsolutePath()); 236 Collections.addAll(args, params); 237 ProcessBuilder builder = new ProcessBuilder(args); 238 builder.environment().putAll(System.getenv()); 239 builder.directory(testFolder); 240 Process process = builder.start(); 241 String output = IOUtils.toString(process.getInputStream()); 242 String error = IOUtils.toString(process.getErrorStream()); 243 int result = process.waitFor(); 244 return new CompilationResult(result, output, error); 245 } 246 247 private void setExecutable() throws IOException { 248 Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>(); 249 //add owners permission 250 perms.add(PosixFilePermission.OWNER_READ); 251 perms.add(PosixFilePermission.OWNER_WRITE); 252 perms.add(PosixFilePermission.OWNER_EXECUTE); 253 //add group permissions 254 perms.add(PosixFilePermission.GROUP_READ); 255 //add others permissions 256 perms.add(PosixFilePermission.OTHERS_READ); 257 Files.setPosixFilePermissions(Paths.get(new File(testFolder, "gradlew").getAbsolutePath()), 258 perms); 259 } 260 261 262} 263