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