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