1 /* 2 * Copyright 2021 Google LLC 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 package com.google.auto.value; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 21 import com.google.common.collect.ImmutableList; 22 import java.io.File; 23 import java.io.IOException; 24 import java.nio.file.Files; 25 import java.nio.file.Path; 26 import java.nio.file.Paths; 27 import java.util.Optional; 28 import java.util.regex.Matcher; 29 import java.util.regex.Pattern; 30 import java.util.stream.Stream; 31 import org.gradle.testkit.runner.BuildResult; 32 import org.gradle.testkit.runner.GradleRunner; 33 import org.gradle.util.GradleVersion; 34 import org.junit.Rule; 35 import org.junit.Test; 36 import org.junit.rules.TemporaryFolder; 37 import org.junit.runner.RunWith; 38 import org.junit.runners.JUnit4; 39 40 @RunWith(JUnit4.class) 41 public class GradleIT { 42 @Rule public TemporaryFolder fakeProject = new TemporaryFolder(); 43 44 private static final String BUILD_GRADLE_TEXT = 45 String.join( 46 "\n", 47 "plugins {", 48 " id 'java-library'", 49 "}", 50 "repositories {", 51 " maven { url = uri('${localRepository}') }", 52 "}", 53 "dependencies {", 54 " compileOnlyApi " 55 + " 'com.google.auto.value:auto-value-annotations:${autoValueVersion}'", 56 " annotationProcessor 'com.google.auto.value:auto-value:${autoValueVersion}'", 57 "}"); 58 59 private static final String FOO_TEXT = 60 String.join( 61 "\n", 62 "package com.example;", 63 "", 64 "import com.google.auto.value.AutoValue;", 65 "", 66 "@AutoValue", 67 "abstract class Foo {", 68 " abstract String bar();", 69 "", 70 " static Foo of(String bar) {", 71 " return new AutoValue_Foo(bar);", 72 " }", 73 "}"); 74 75 private static final Optional<File> GRADLE_INSTALLATION = getGradleInstallation(); 76 77 @Test basic()78 public void basic() throws IOException { 79 String autoValueVersion = System.getProperty("autoValueVersion"); 80 assertThat(autoValueVersion).isNotNull(); 81 String localRepository = System.getProperty("localRepository"); 82 assertThat(localRepository).isNotNull(); 83 84 // Set up the fake Gradle project. 85 String buildGradleText = expandSystemProperties(BUILD_GRADLE_TEXT); 86 writeFile(fakeProject.newFile("build.gradle").toPath(), buildGradleText); 87 Path srcDir = fakeProject.newFolder("src", "main", "java", "com", "example").toPath(); 88 writeFile(srcDir.resolve("Foo.java"), FOO_TEXT); 89 90 // Build it the first time. 91 BuildResult result1 = buildFakeProject(); 92 assertThat(result1.getOutput()) 93 .contains( 94 "Full recompilation is required because no incremental change information is" 95 + " available"); 96 Path output = 97 fakeProject 98 .getRoot() 99 .toPath() 100 .resolve("build/classes/java/main/com/example/AutoValue_Foo.class"); 101 assertThat(Files.exists(output)).isTrue(); 102 103 // Add a source file to the project. 104 String barText = FOO_TEXT.replace("Foo", "Bar"); 105 Path barFile = srcDir.resolve("Bar.java"); 106 writeFile(barFile, barText); 107 108 // Build it a second time. 109 BuildResult result2 = buildFakeProject(); 110 assertThat(result2.getOutput()).doesNotContain("Full recompilation is required"); 111 112 // Remove the second source file and build a third time. If incremental annotation processing 113 // is not working, this will produce a message like this: 114 // Full recompilation is required because com.google.auto.value.processor.AutoValueProcessor 115 // is not incremental 116 Files.delete(barFile); 117 BuildResult result3 = buildFakeProject(); 118 assertThat(result3.getOutput()).doesNotContain("Full recompilation is required"); 119 } 120 buildFakeProject()121 private BuildResult buildFakeProject() throws IOException { 122 GradleRunner runner = 123 GradleRunner.create() 124 .withProjectDir(fakeProject.getRoot()) 125 .withArguments("--info", "compileJava"); 126 if (GRADLE_INSTALLATION.isPresent()) { 127 runner.withGradleInstallation(GRADLE_INSTALLATION.get()); 128 } else { 129 runner.withGradleVersion(GradleVersion.current().getVersion()); 130 } 131 return runner.build(); 132 } 133 getGradleInstallation()134 private static Optional<File> getGradleInstallation() { 135 String gradleHome = System.getenv("GRADLE_HOME"); 136 if (gradleHome != null) { 137 File gradleHomeFile = new File(gradleHome); 138 if (gradleHomeFile.isDirectory()) { 139 return Optional.of(new File(gradleHome)); 140 } 141 } 142 try { 143 Path gradleExecutable = Paths.get("/usr/bin/gradle"); 144 Path gradleLink = gradleExecutable.resolveSibling(Files.readSymbolicLink(gradleExecutable)); 145 if (!gradleLink.endsWith("bin/gradle")) { 146 return Optional.empty(); 147 } 148 Path installationPath = gradleLink.getParent().getParent(); 149 if (!Files.isDirectory(installationPath)) { 150 return Optional.empty(); 151 } 152 Optional<Path> coreJar; 153 Pattern corePattern = Pattern.compile("gradle-core-([0-9]+)\\..*\\.jar"); 154 try (Stream<Path> files = Files.walk(installationPath.resolve("lib"))) { 155 coreJar = 156 files 157 .filter( 158 p -> { 159 Matcher matcher = corePattern.matcher(p.getFileName().toString()); 160 if (matcher.matches()) { 161 int version = Integer.parseInt(matcher.group(1)); 162 if (version >= 5) { 163 return true; 164 } 165 } 166 return false; 167 }) 168 .findFirst(); 169 } 170 return coreJar.map(unused -> installationPath.toFile()); 171 } catch (IOException e) { 172 return Optional.empty(); 173 } 174 } 175 expandSystemProperties(String s)176 private static String expandSystemProperties(String s) { 177 for (String name : System.getProperties().stringPropertyNames()) { 178 String value = System.getProperty(name); 179 s = s.replace("${" + name + "}", value); 180 } 181 return s; 182 } 183 writeFile(Path file, String text)184 private static void writeFile(Path file, String text) throws IOException { 185 Files.write(file, ImmutableList.of(text), UTF_8); 186 } 187 } 188