1 /* 2 * Copyright 2014 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.base.StandardSystemProperty.JAVA_HOME; 19 import static com.google.common.collect.ImmutableSet.toImmutableSet; 20 import static com.google.common.truth.Truth.assertThat; 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import com.google.auto.value.processor.AutoAnnotationProcessor; 24 import com.google.auto.value.processor.AutoBuilderProcessor; 25 import com.google.auto.value.processor.AutoOneOfProcessor; 26 import com.google.auto.value.processor.AutoValueProcessor; 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableSet; 29 import java.io.File; 30 import java.io.IOException; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import java.util.List; 34 import java.util.Set; 35 import java.util.function.Predicate; 36 import java.util.stream.Stream; 37 import javax.annotation.processing.Processor; 38 import javax.tools.JavaCompiler; 39 import javax.tools.JavaFileObject; 40 import javax.tools.StandardJavaFileManager; 41 import javax.tools.StandardLocation; 42 import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler; 43 import org.junit.BeforeClass; 44 import org.junit.Rule; 45 import org.junit.Test; 46 import org.junit.rules.TemporaryFolder; 47 import org.junit.runner.RunWith; 48 import org.junit.runners.JUnit4; 49 50 /** 51 * Tests that we can compile our AutoValue tests using the Eclipse batch compiler. Since the tests 52 * exercise many AutoValue subtleties, the ability to compile them all is a good indication of 53 * Eclipse support. 54 */ 55 @RunWith(JUnit4.class) 56 public class CompileWithEclipseTest { 57 private static final String SOURCE_ROOT = System.getProperty("basedir"); 58 59 @BeforeClass setSourceRoot()60 public static void setSourceRoot() { 61 assertWithMessage("basedir property must be set - test must be run from Maven") 62 .that(SOURCE_ROOT) 63 .isNotNull(); 64 } 65 66 public @Rule TemporaryFolder tmp = new TemporaryFolder(); 67 68 private static final ImmutableSet<String> IGNORED_TEST_FILES = 69 ImmutableSet.of( 70 "AutoValueNotEclipseTest.java", 71 "CompileWithEclipseTest.java", 72 "CustomFieldSerializerTest.java", 73 "GradleIT.java", 74 75 // AutoBuilder sometimes needs to generate a .class file for Kotlin that is used in the 76 // rest of compilation, and Eclipse doesn't seem to handle that well. Presumably not many 77 // Kotlin users use Eclipse since IntelliJ is obviously much more suitable. 78 "AutoBuilderKotlinTest.java"); 79 80 private static final Predicate<File> JAVA_FILE = 81 f -> f.getName().endsWith(".java") && !IGNORED_TEST_FILES.contains(f.getName()); 82 83 private static final ImmutableSet<String> JAVA8_TEST_FILES = 84 ImmutableSet.of( 85 "AutoBuilderTest.java", 86 "AutoOneOfJava8Test.java", 87 "AutoValueJava8Test.java", 88 "EmptyExtension.java"); 89 private static final Predicate<File> JAVA8_TEST = f -> JAVA8_TEST_FILES.contains(f.getName()); 90 91 @Test compileWithEclipseJava7()92 public void compileWithEclipseJava7() throws Exception { 93 compileWithEclipse("7", JAVA_FILE.and(JAVA8_TEST.negate())); 94 } 95 96 @Test compileWithEclipseJava8()97 public void compileWithEclipseJava8() throws Exception { 98 compileWithEclipse("8", JAVA_FILE); 99 } 100 compileWithEclipse(String version, Predicate<File> predicate)101 private void compileWithEclipse(String version, Predicate<File> predicate) throws IOException { 102 File sourceRootFile = new File(SOURCE_ROOT); 103 File javaDir = new File(sourceRootFile, "src/main/java"); 104 File javatestsDir = new File(sourceRootFile, "src/test/java"); 105 Set<File> sources = 106 new ImmutableSet.Builder<File>() 107 .addAll(filesUnderDirectory(javaDir, predicate)) 108 .addAll(filesUnderDirectory(javatestsDir, predicate)) 109 .build(); 110 assertThat(sources).isNotEmpty(); 111 JavaCompiler compiler = new EclipseCompiler(); 112 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 113 // This hack is only needed in a Google-internal Java 8 environment where symbolic links make it 114 // hard for ecj to find the boot class path. Elsewhere it is unnecessary but harmless. Notably, 115 // on Java 9+ there is no rt.jar. There, fileManager.getLocation(PLATFORM_CLASS_PATH) returns 116 // null, because the relevant classes are in modules inside 117 // fileManager.getLocation(SYSTEM_MODULES). 118 File rtJar = new File(JAVA_HOME.value() + "/lib/rt.jar"); 119 if (rtJar.exists()) { 120 List<File> bootClassPath = 121 ImmutableList.<File>builder() 122 .add(rtJar) 123 .addAll(fileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) 124 .build(); 125 fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath); 126 } 127 Iterable<? extends JavaFileObject> sourceFileObjects = 128 fileManager.getJavaFileObjectsFromFiles(sources); 129 String outputDir = tmp.getRoot().toString(); 130 ImmutableList<String> options = 131 ImmutableList.of( 132 "-d", 133 outputDir, 134 "-s", 135 outputDir, 136 "-source", 137 version, 138 "-target", 139 version, 140 "-warn:-warningToken,-intfAnnotation"); 141 JavaCompiler.CompilationTask task = 142 compiler.getTask(null, fileManager, null, options, null, sourceFileObjects); 143 // Explicitly supply an empty list of extensions for AutoValueProcessor, because otherwise this 144 // test will pick up a test one and get confused. 145 AutoValueProcessor autoValueProcessor = new AutoValueProcessor(ImmutableList.of()); 146 ImmutableList<? extends Processor> processors = 147 ImmutableList.of( 148 autoValueProcessor, 149 new AutoOneOfProcessor(), 150 new AutoAnnotationProcessor(), 151 new AutoBuilderProcessor()); 152 task.setProcessors(processors); 153 assertWithMessage("Compilation should succeed").that(task.call()).isTrue(); 154 } 155 filesUnderDirectory(File dir, Predicate<File> predicate)156 private static ImmutableSet<File> filesUnderDirectory(File dir, Predicate<File> predicate) 157 throws IOException { 158 assertWithMessage(dir.toString()).that(dir.isDirectory()).isTrue(); 159 try (Stream<Path> paths = Files.walk(dir.toPath())) { 160 return paths.map(Path::toFile).filter(predicate).collect(toImmutableSet()); 161 } 162 } 163 } 164