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