| /* |
| * Copyright 2015 The Kythe Authors. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.devtools.kythe.extractors.java; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; |
| |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| import com.google.devtools.kythe.extractors.shared.CompilationDescription; |
| import com.google.devtools.kythe.extractors.shared.ExtractorUtils; |
| import com.google.devtools.kythe.proto.Analysis.CompilationUnit; |
| import com.google.devtools.kythe.proto.Analysis.CompilationUnit.FileInput; |
| import com.google.devtools.kythe.proto.Analysis.FileInfo; |
| import com.google.devtools.kythe.proto.Java.JavaDetails; |
| import com.google.protobuf.Any; |
| import com.google.protobuf.InvalidProtocolBufferException; |
| import java.io.File; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| import junit.framework.TestCase; |
| |
| /** Tests for {@link JavaCompilationExtractor}. */ |
| // TODO(schroederc): replace asserts with Truth#assertThat |
| public class JavaExtractorTest extends TestCase { |
| |
| private static final String TEST_DATA_DIR = |
| "kythe/javatests/com/google/devtools/kythe/extractors/java/testdata"; |
| |
| private static final String CORPUS = "testCorpus"; |
| private static final String TARGET1 = "target1"; |
| |
| private static final ImmutableList<String> EMPTY = ImmutableList.of(); |
| |
| private static final FileInfo GENERATED_ANNOTATION_CLASS = |
| FileInfo.newBuilder() |
| .setPath(join("!CLASS_PATH_JAR!", "javax/annotation/Generated.class")) |
| // This digest depends on the external javax_annotation_jsr250_api dependency. If it is |
| // updated, this will also need to change. |
| .setDigest("e5ee743f5c6df4923a934cba33c73d3d73e19d277c8ddec5c4e7ac59788fc674") |
| .build(); |
| |
| // Due to the nature of the jsr250 dependency, this class is incidentally |
| // included in some compilation environments but not others. |
| // In order to distinguish these dependencies from "true" dependencies, use this name. |
| private static final FileInfo JDK_ANNOTATION_CLASS = GENERATED_ANNOTATION_CLASS; |
| private static final String JDK_ANNOTATION_PATH = "!CLASS_PATH_JAR!"; |
| |
| /** Tests the basic case of indexing a java compilation with two sources. */ |
| public void testJavaExtractorSimple() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = |
| Lists.newArrayList(join(TEST_DATA_DIR, "/pkg/A.java"), join(TEST_DATA_DIR, "/pkg/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| |
| // With the expected sources as explicit sources. |
| assertThat(unit.getSourceFileCount()).isEqualTo(2); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0), sources.get(1)).inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(sources, JDK_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).containsExactly(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).containsExactly(JDK_ANNOTATION_PATH); |
| } |
| |
| /** Tests that metadata is included when a file specifies it. */ |
| public void testJavaExtractorMetadata() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = Lists.newArrayList(join(TEST_DATA_DIR, "/pkg/M.java")); |
| List<String> dependencies = |
| Lists.newArrayList( |
| join(TEST_DATA_DIR, "/pkg/M.java"), join(TEST_DATA_DIR, "/pkg/M.java.meta")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| |
| // With the expected sources as explicit sources. |
| assertThat(unit.getSourceFileCount()).isEqualTo(1); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0)); |
| |
| // With the expected dependencies as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(dependencies, GENERATED_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).containsExactly(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).containsExactly("!CLASS_PATH_JAR!"); |
| } |
| |
| /** Tests indexing within a symlink root. */ |
| public void testJavaExtractorSymlinkRoot() throws Exception { |
| Path symlinkRoot = Paths.get(System.getenv("TEST_TMPDIR"), "symlinkRoot"); |
| symlinkRoot.toFile().delete(); |
| Files.createSymbolicLink(symlinkRoot, Paths.get(".").toAbsolutePath()); |
| symlinkRoot.toFile().deleteOnExit(); |
| |
| JavaCompilationUnitExtractor java = |
| new JavaCompilationUnitExtractor(CORPUS, symlinkRoot.toString()); |
| |
| List<String> sources = |
| Lists.newArrayList(join(TEST_DATA_DIR, "/pkg/A.java"), join(TEST_DATA_DIR, "/pkg/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| |
| // With the expected sources as explicit sources. |
| assertThat(unit.getSourceFileList()).containsExactlyElementsIn(sources).inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(sources, JDK_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).containsExactly(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).containsExactly(JDK_ANNOTATION_PATH); |
| } |
| |
| /** |
| * Tests the basic case of indexing a java compilation where the sources live in different folders |
| * eventhough they're in the same package. |
| */ |
| public void testJavaExtractorTwoSourceDirs() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| // Pick two sources in the same package that live in different directories. |
| List<String> sources = |
| Lists.newArrayList( |
| join(TEST_DATA_DIR, "one/pkg/A.java"), join(TEST_DATA_DIR, "two/pkg/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| |
| // With the expected sources as explicit sources. |
| assertThat(unit.getSourceFileCount()).isEqualTo(2); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0), sources.get(1)).inOrder(); |
| |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(sources, JDK_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation for both sources. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()) |
| .containsExactly(join(TEST_DATA_DIR, "one"), join(TEST_DATA_DIR, "two")); |
| assertThat(details.getClasspathList()).containsExactly(JDK_ANNOTATION_PATH); |
| } |
| |
| /** |
| * Tests java compilation with classfiles in the classpath. Test ensures that only used classfiles |
| * are stored. |
| */ |
| public void testJavaExtractorClassFiles() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| // Index the specified sources |
| List<String> sources = Lists.newArrayList(join(TEST_DATA_DIR, "child/derived/B.java")); |
| |
| String parentCp = join(TEST_DATA_DIR, "parent") + "/"; |
| List<String> classpath = Lists.newArrayList(parentCp); |
| String classFile = join(parentCp, "base/A.class"); |
| |
| // Index the specified sources and classes from the classpath |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| classpath, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(1); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0)).inOrder(); |
| |
| // Ensure the right class files are picked up from the classpath. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(Arrays.asList(sources.get(0), classFile))); |
| |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).containsExactly(join(TEST_DATA_DIR, "child")); |
| // Ensure the classpath is set for replay. |
| assertThat(details.getClasspathList()).containsExactly(parentCp); |
| } |
| |
| /** |
| * Tests java compilation with classfiles in a jarfile on the classpath. Ensures that only used |
| * classfiles are stored. |
| */ |
| public void testJavaExtractorJar() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| // Index the specified sources. |
| List<String> sources = Lists.newArrayList(join(TEST_DATA_DIR, "child/derived/B.java")); |
| |
| String parentCp = join(TEST_DATA_DIR, "jarred.jar"); |
| List<String> classpath = Lists.newArrayList(parentCp); |
| |
| // Index the specified sources and classes from inside jar on the classpath. |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| classpath, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileList()).containsExactlyElementsIn(sources).inOrder(); |
| |
| // The classpath is adjusted to start wit !CLASS_PATH_JAR! |
| String classFile = join("!CLASS_PATH_JAR!", "base/A.class"); |
| |
| // Ensure the right class files are picked up from the classpath from within the jar. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactly( |
| makeFileInfo(sources.get(0)), |
| makeFileInfo(classFile, join(TEST_DATA_DIR, "parent/base/A.class"))); |
| |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).hasSize(1); |
| assertThat(details.getSourcepathList().get(0)).isEqualTo(join(TEST_DATA_DIR, "child")); |
| // Ensure the magic !CLASS_PATH_JAR! classpath is added. |
| assertThat(details.getClasspathList()).containsExactly("!CLASS_PATH_JAR!"); |
| } |
| |
| /** |
| * Tests case where compile errors exist in the sources under compilation. Compilation should |
| * still be created. |
| */ |
| public void testJavaExtractorCompileError() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = Lists.newArrayList(join(TEST_DATA_DIR, "/error/Crash.java")); |
| |
| // Index the specified sources, reporting compilation failure. |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getRequiredInputCount()).isEqualTo(1); |
| assertThat(unit.getRequiredInput(0).getInfo().getPath()).isEqualTo(sources.get(0)); |
| assertThat(unit.getRequiredInput(0).getInfo().getDigest()) |
| .isEqualTo(ExtractorUtils.digestForPath(sources.get(0))); |
| assertThat(unit.getSourceFileCount()).isEqualTo(1); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0)).inOrder(); |
| |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).hasSize(1); |
| assertThat(details.getSourcepathList().get(0)).isEqualTo(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).isEmpty(); |
| } |
| |
| /** Tests that dependent files are ordered correctly. */ |
| public void testJavaExtractorOrderedDependencies() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = |
| Lists.newArrayList( |
| join(TEST_DATA_DIR, "/deps/A.java"), |
| join(TEST_DATA_DIR, "/deps/C.java"), |
| join(TEST_DATA_DIR, "/deps/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(3); |
| assertThat(unit.getSourceFileList()) |
| .containsExactly(sources.get(0), sources.get(1), sources.get(2)) |
| .inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactly( |
| JDK_ANNOTATION_CLASS, |
| makeFileInfo(sources.get(0)), |
| makeFileInfo(sources.get(2)), |
| makeFileInfo(sources.get(1))) |
| .inOrder(); |
| } |
| |
| /** |
| * Tests the case where one of the sources doesn't follow the java pattern of naming the path to |
| * the source file after the package name. |
| */ |
| public void testJavaExtractorNonConformingPath() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = |
| Lists.newArrayList( |
| join(TEST_DATA_DIR, "/path/sub/A.java"), join(TEST_DATA_DIR, "/path/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(2); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0), sources.get(1)).inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(sources, JDK_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).hasSize(1); |
| assertThat(details.getSourcepathList().get(0)).isEqualTo(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).containsExactly(JDK_ANNOTATION_PATH); |
| } |
| |
| /** |
| * Tests the case where one of the sources defines a package only type that is not conforming to |
| * the classname matching the filename. |
| */ |
| public void testJavaExtractorAdditionalTypeDefinitions() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = |
| Lists.newArrayList( |
| join(TEST_DATA_DIR, "/hitchhikers/A.java"), join(TEST_DATA_DIR, "/hitchhikers/B.java")); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(2); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0), sources.get(1)).inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactlyElementsIn(getExpectedInfos(sources, JDK_ANNOTATION_CLASS)); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).containsExactly(TEST_DATA_DIR); |
| assertThat(details.getClasspathList()).containsExactly(JDK_ANNOTATION_PATH); |
| } |
| |
| /** |
| * Tests that unsupported flags do not crash the extractor and source/header destination options |
| * are not present in the resulting {@link CompilationUnit}. |
| */ |
| public void testJavaExtractorArguments() throws Exception { |
| String testDir = System.getenv("TEST_TMPDIR"); |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS, testDir); |
| |
| File processorFile = |
| Paths.get( |
| "kythe/javatests/com/google/devtools/kythe/extractors/java/SillyProcessor_deploy.jar") |
| .toFile(); |
| if (!processorFile.exists()) { |
| throw new AssertionError("SillyProcessor_deploy.jar does not exist"); |
| } |
| |
| List<String> origSources = testFiles("processor/Silly.java", "processor/SillyUser.java"); |
| |
| List<Path> outputDirs = |
| Arrays.asList( |
| Paths.get(testDir, "output-gensrc.jar.files"), |
| Paths.get(testDir, "output-genhdr.jar.files"), |
| Paths.get(testDir, "classes")); |
| |
| List<String> processorpath = Arrays.asList(processorFile.getPath()); |
| List<String> processors = Arrays.asList("processor.SillyProcessor"); |
| List<String> options = |
| Arrays.asList( |
| "-Xdoclint:-Xdoclint:all/private", // ensure this unsupported flag is saved |
| "-s", |
| outputDirs.get(0).toString(), |
| "-h", |
| outputDirs.get(1).toString(), |
| "-g:lines", // ensure this conjoined arg is handled correctly |
| "-d", |
| outputDirs.get(2).toString()); |
| |
| for (Path dir : outputDirs) { |
| dir.toFile().mkdir(); |
| } |
| |
| // Copy sources from runfiles into test dir |
| List<String> testSources = new ArrayList<>(); |
| for (String source : origSources) { |
| Path destFile = Paths.get(testDir).resolve(source); |
| Files.createDirectories(destFile.getParent()); |
| Files.copy(Paths.get(source), destFile, REPLACE_EXISTING); |
| testSources.add(destFile.toString()); |
| } |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| testSources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| processorpath, |
| processors, |
| Optional.absent(), |
| options, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| |
| // Check that the -s, and -h flags have been removed from the compilation's arguments, but -d |
| // preserved (it is required by modular builds). |
| assertThat(unit.getArgumentList()) |
| .containsExactly("-Xdoclint:-Xdoclint:all/private", "-g:lines") |
| .inOrder(); |
| } |
| |
| /** Tests that targets that contain annotation processors are indexed correctly. */ |
| public void testJavaExtractorAnnotationProcessing() throws Exception { |
| String testDir = System.getenv("TEST_TMPDIR"); |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS, testDir); |
| |
| File processorFile = |
| Paths.get( |
| "kythe/javatests/com/google/devtools/kythe/extractors/java/SillyProcessor_deploy.jar") |
| .toFile(); |
| if (!processorFile.exists()) { |
| throw new AssertionError("SillyProcessor_deploy.jar does not exist"); |
| } |
| |
| List<String> origSources = testFiles("processor/Silly.java", "processor/SillyUser.java"); |
| |
| List<String> processorpath = Arrays.asList(processorFile.getPath()); |
| List<String> processors = Arrays.asList("processor.SillyProcessor"); |
| Path genSrcDir = Paths.get(testDir, "output-gensrc.jar.files"); |
| List<String> options = Arrays.asList("-s", genSrcDir.toString()); |
| genSrcDir.toFile().mkdir(); |
| |
| // Copy sources from runfiles into test dir |
| List<String> testSources = new ArrayList<>(); |
| for (String source : origSources) { |
| Path destFile = Paths.get(testDir).resolve(source); |
| Files.createDirectories(destFile.getParent()); |
| Files.copy(Paths.get(source), destFile, REPLACE_EXISTING); |
| testSources.add(destFile.toString()); |
| } |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| testSources, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| processorpath, |
| processors, |
| Optional.of(genSrcDir), |
| options, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| |
| String sillyGenerated = "output-gensrc.jar.files/processor/SillyGenerated.java"; |
| assertThat(unit.getSourceFileList()) |
| .containsExactly(origSources.get(0), origSources.get(1), sillyGenerated) |
| .inOrder(); |
| |
| // With the expected sources as required inputs. |
| assertThat(getInfos(unit.getRequiredInputList())) |
| .containsExactly( |
| GENERATED_ANNOTATION_CLASS, |
| makeFileInfo(origSources.get(0)), |
| makeFileInfo(origSources.get(1)), |
| makeFileInfo(sillyGenerated, Paths.get(testDir, sillyGenerated).toString())); |
| |
| // And the correct sourcepath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).hasSize(2); |
| assertThat(details.getSourcepathList()) |
| .containsExactly(TEST_DATA_DIR, "output-gensrc.jar.files"); |
| assertThat(details.getClasspathList()).containsExactly("!CLASS_PATH_JAR!"); |
| } |
| |
| /** Tests that the extractor doesn't fall over when it's provided with no sources. */ |
| public void testNoSources() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = Collections.emptyList(); |
| List<String> bootclasspath = testFiles("empty/fake-rt.jar"); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| bootclasspath, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(0); |
| assertThat(unit.getRequiredInputCount()).isEqualTo(0); |
| |
| // And the correct classpath set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).isEmpty(); |
| assertThat(details.getClasspathList()).isEmpty(); |
| } |
| |
| /** |
| * Tests the case where one of the sources defines a package only type that is not conforming to |
| * the classname matching the filename. |
| */ |
| public void testEmptyCompilationUnit() throws Exception { |
| JavaCompilationUnitExtractor java = new JavaCompilationUnitExtractor(CORPUS); |
| |
| List<String> sources = testFiles("empty/Empty.java"); |
| List<String> bootclasspath = testFiles("empty/fake-rt.jar"); |
| |
| // Index the specified sources |
| CompilationDescription description = |
| java.extract( |
| TARGET1, |
| sources, |
| EMPTY, |
| bootclasspath, |
| EMPTY, |
| EMPTY, |
| EMPTY, |
| Optional.absent(), |
| EMPTY, |
| "output"); |
| |
| CompilationUnit unit = description.getCompilationUnit(); |
| assertThat(unit).isNotNull(); |
| assertThat(unit.getVName().getSignature()).isEqualTo(TARGET1); |
| assertThat(unit.getSourceFileCount()).isEqualTo(1); |
| assertThat(unit.getSourceFileList()).containsExactly(sources.get(0)).inOrder(); |
| |
| assertThat(unit.getRequiredInputCount()).isEqualTo(3); |
| List<String> requiredPaths = new ArrayList<>(); |
| for (FileInput input : unit.getRequiredInputList()) { |
| requiredPaths.add(input.getInfo().getPath()); |
| } |
| assertThat(requiredPaths) |
| .containsExactly( |
| sources.get(0), |
| "!PLATFORM_CLASS_PATH_JAR!/java/lang/Fake.class", |
| "!CLASS_PATH_JAR!/javax/annotation/Generated.class"); |
| |
| assertThat(unit.getArgumentList()) |
| .containsNoneOf("-bootclasspath", "-sourcepath", "-cp", "-classpath"); |
| |
| // And the correct source/class locations set to replay the compilation. |
| JavaDetails details = getJavaDetails(unit); |
| assertThat(details.getSourcepathList()).isEmpty(); |
| assertThat(details.getClasspathList()).containsExactly("!CLASS_PATH_JAR!"); |
| assertThat(details.getBootclasspathList()).containsExactly("!PLATFORM_CLASS_PATH_JAR!"); |
| } |
| |
| private List<String> testFiles(String... files) { |
| List<String> res = new ArrayList<>(); |
| for (String file : files) { |
| res.add(join(TEST_DATA_DIR, file)); |
| } |
| return res; |
| } |
| |
| private static List<FileInfo> getInfos(List<FileInput> files) { |
| return Lists.transform(files, FileInput::getInfo); |
| } |
| |
| private static List<FileInfo> getExpectedInfos(List<String> files, FileInfo... extra) { |
| return Stream.concat(files.stream().map(JavaExtractorTest::makeFileInfo), Stream.of(extra)) |
| .collect(Collectors.toList()); |
| } |
| |
| private static FileInfo makeFileInfo(String path) { |
| try { |
| return FileInfo.newBuilder() |
| .setPath(path) |
| .setDigest(ExtractorUtils.digestForPath(path)) |
| .build(); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private static FileInfo makeFileInfo(String path, String localPath) { |
| try { |
| return FileInfo.newBuilder() |
| .setPath(path) |
| .setDigest(ExtractorUtils.digestForPath(localPath)) |
| .build(); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private JavaDetails getJavaDetails(CompilationUnit unit) throws InvalidProtocolBufferException { |
| for (Any any : unit.getDetailsList()) { |
| if (any.getTypeUrl().equals(JavaCompilationUnitExtractor.JAVA_DETAILS_URL)) { |
| return JavaDetails.parseFrom(any.getValue()); |
| } |
| } |
| return null; |
| } |
| |
| private static String join(String base, String... paths) { |
| return Paths.get(base, paths).toString(); |
| } |
| } |