/* * Copyright 2014-present Facebook, Inc. * * 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.facebook.buck.jvm.java; import static com.facebook.buck.jvm.java.JavacOptions.TARGETED_JAVA_VERSION; import static org.easymock.EasyMock.createMock; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; import com.facebook.buck.cli.BuckConfig; import com.facebook.buck.cli.BuckConfigTestUtils; import com.facebook.buck.cli.FakeBuckConfig; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.environment.Architecture; import com.facebook.buck.util.environment.Platform; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.nio.file.Path; import java.util.Optional; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; public class JavaBuckConfigTest { @Rule public TemporaryPaths temporaryFolder = new TemporaryPaths(); private ProjectFilesystem defaultFilesystem; @Before public void setUpDefaultFilesystem() throws InterruptedException { defaultFilesystem = new ProjectFilesystem(temporaryFolder.getRoot()); } @Test public void whenJavaIsNotSetThenJavaFromPathIsReturned() throws IOException { JavaBuckConfig config = createWithDefaultFilesystem(new StringReader("")); JavaOptions javaOptions = config.getDefaultJavaOptions(); assertEquals(Optional.empty(), javaOptions.getJavaPath()); assertEquals("java", javaOptions.getJavaRuntimeLauncher().getCommand()); JavaOptions javaForTestsOptions = config.getDefaultJavaOptionsForTests(); assertEquals(Optional.empty(), javaForTestsOptions.getJavaPath()); } @Test public void whenJavaExistsAndIsExecutableThenItIsReturned() throws IOException { Path java = temporaryFolder.newExecutableFile(); Path javaForTests = temporaryFolder.newExecutableFile(); String javaCommand = java.toString(); String javaForTestsCommand = javaForTests.toString(); JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections( ImmutableMap.of( "tools", ImmutableMap.of( "java", javaCommand, "java_for_tests", javaForTestsCommand))) .build() .getView(JavaBuckConfig.class); JavaOptions javaOptions = config.getDefaultJavaOptions(); assertEquals(Optional.of(java), javaOptions.getJavaPath()); assertEquals(javaCommand, javaOptions.getJavaRuntimeLauncher().getCommand()); JavaOptions javaForTestsOptions = config.getDefaultJavaOptionsForTests(); assertEquals(Optional.of(javaForTests), javaForTestsOptions.getJavaPath()); assertEquals(javaForTestsCommand, javaForTestsOptions.getJavaRuntimeLauncher().getCommand()); } @Test public void whenJavaExistsAndIsRelativePathThenItsAbsolutePathIsReturned() throws IOException { Path java = temporaryFolder.newExecutableFile(); String javaFilename = java.getFileName().toString(); JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections(ImmutableMap.of("tools", ImmutableMap.of("java", javaFilename))) .build() .getView(JavaBuckConfig.class); JavaOptions options = config.getDefaultJavaOptions(); assertEquals(Optional.of(java), options.getJavaPath()); assertEquals(java.toString(), options.getJavaRuntimeLauncher().getCommand()); } @Test public void whenJavaForTestsIsNotSetThenJavaIsReturned() throws IOException { Path java = temporaryFolder.newExecutableFile(); String javaCommand = java.toString(); JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections(ImmutableMap.of("tools", ImmutableMap.of("java", javaCommand))) .build() .getView(JavaBuckConfig.class); JavaOptions options = config.getDefaultJavaOptionsForTests(); assertEquals(Optional.of(java), options.getJavaPath()); assertEquals(javaCommand, options.getJavaRuntimeLauncher().getCommand()); } @Test public void whenJavacIsNotSetThenAbsentIsReturned() throws IOException { JavaBuckConfig config = createWithDefaultFilesystem(new StringReader("")); assertEquals(Optional.empty(), config.getJavacPath()); } @Test public void whenJavacExistsAndIsExecutableThenCorrectPathIsReturned() throws IOException { Path javac = temporaryFolder.newExecutableFile(); Reader reader = new StringReader( Joiner.on('\n') .join("[tools]", " javac = " + javac.toString().replace("\\", "\\\\"))); JavaBuckConfig config = createWithDefaultFilesystem(reader); assertEquals(Optional.of(javac), config.getJavacPath()); } @Test public void whenJavacDoesNotExistThenHumanReadableExceptionIsThrown() throws IOException { String invalidPath = temporaryFolder.getRoot().toAbsolutePath() + "DoesNotExist"; Reader reader = new StringReader( Joiner.on('\n').join("[tools]", " javac = " + invalidPath.replace("\\", "\\\\"))); JavaBuckConfig config = createWithDefaultFilesystem(reader); try { config.getJavacPath(); fail("Should throw exception as javac file does not exist."); } catch (HumanReadableException e) { assertEquals( "Overridden tools:javac path not found: " + invalidPath, e.getHumanReadableErrorMessage()); } } @Test public void whenJavacIsNotExecutableThenHumanReadableExeceptionIsThrown() throws IOException { assumeThat( "Files on Windows are executable by default.", Platform.detect(), is(not(Platform.WINDOWS))); Path javac = temporaryFolder.newFile(); Reader reader = new StringReader(Joiner.on('\n').join("[tools]", " javac = " + javac.toString())); JavaBuckConfig config = createWithDefaultFilesystem(reader); try { config.getJavacPath(); fail("Should throw exception as javac file is not executable."); } catch (HumanReadableException e) { assertEquals(e.getHumanReadableErrorMessage(), "javac is not executable: " + javac); } } @Test public void whenJavacJarDoesNotExistThenHumanReadableExceptionIsThrown() throws IOException { String invalidPath = temporaryFolder.getRoot().toAbsolutePath() + "DoesNotExist"; Reader reader = new StringReader( Joiner.on('\n') .join("[tools]", " javac_jar = " + invalidPath.replace("\\", "\\\\"))); JavaBuckConfig config = createWithDefaultFilesystem(reader); try { config.getJavacSpec().getJavacJarPath(); fail("Should throw exception as javac file does not exist."); } catch (HumanReadableException e) { assertEquals( "Overridden tools:javac_jar path not found: " + invalidPath, e.getHumanReadableErrorMessage()); } } @Test public void shouldSetJavaTargetAndSourceVersionFromConfig() throws IOException, InterruptedException { String sourceLevel = "source-level"; String targetLevel = "target-level"; String localConfig = String.format("[java]\nsource_level = %s\ntarget_level = %s", sourceLevel, targetLevel); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(localConfig)); JavacOptions options = config.getDefaultJavacOptions(); assertEquals(sourceLevel, options.getSourceLevel()); assertEquals(targetLevel, options.getTargetLevel()); } @Test public void shouldSetJavaTargetAndSourceVersionDefaultToSaneValues() throws IOException, InterruptedException { JavaBuckConfig config = createWithDefaultFilesystem(new StringReader("")); JavacOptions options = config.getDefaultJavacOptions(); assertEquals(TARGETED_JAVA_VERSION, options.getSourceLevel()); assertEquals(TARGETED_JAVA_VERSION, options.getTargetLevel()); } @Test public void shouldPopulateTheMapOfSourceLevelToBootclasspath() throws IOException, InterruptedException { String localConfig = "[java]\nbootclasspath-6 = one.jar\nbootclasspath-7 = two.jar"; JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(localConfig)); JavacOptions options = config.getDefaultJavacOptions(); JavacOptions jse5 = JavacOptions.builder(options).setSourceLevel("5").build(); JavacOptions jse6 = JavacOptions.builder(options).setSourceLevel("6").build(); JavacOptions jse7 = JavacOptions.builder(options).setSourceLevel("7").build(); assertOptionKeyAbsent(jse5, "bootclasspath"); assertOptionsContains(jse6, "bootclasspath", "one.jar"); assertOptionsContains(jse7, "bootclasspath", "two.jar"); } @Test public void whenJavacIsNotSetInBuckConfigConfiguredRulesCreateJavaLibraryRuleWithJsr199Javac() throws IOException, NoSuchBuildTargetException, InterruptedException { BuckConfig buckConfig = FakeBuckConfig.builder().build(); JavaBuckConfig javaConfig = buckConfig.getView(JavaBuckConfig.class); Javac javac = JavacFactory.create(null, javaConfig, null); assertTrue(javac.getClass().toString(), javac instanceof Jsr199Javac); } @Test public void whenJavacIsSetInBuckConfigConfiguredRulesCreateJavaLibraryRuleWithJavacSet() throws IOException, NoSuchBuildTargetException, InterruptedException { final String javac = temporaryFolder.newExecutableFile().toString(); ImmutableMap<String, ImmutableMap<String, String>> sections = ImmutableMap.of("tools", ImmutableMap.of("javac", javac)); BuckConfig buckConfig = FakeBuckConfig.builder().setFilesystem(defaultFilesystem).setSections(sections).build(); JavaBuckConfig javaConfig = buckConfig.getView(JavaBuckConfig.class); assertEquals( javac, ((ExternalJavac) JavacFactory.create(null, javaConfig, null)).getShortName()); } @Test public void trackClassUsageCanBeDisabled() { JavaBuckConfig config = FakeBuckConfig.builder() .setSections(ImmutableMap.of("java", ImmutableMap.of("track_class_usage", "false"))) .build() .getView(JavaBuckConfig.class); assumeThat(config.getJavacSpec().getJavacSource(), is(Javac.Source.JDK)); assertFalse(config.trackClassUsage()); } @Test public void doNotTrackClassUsageByDefaultForExternJavac() throws IOException { JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections( ImmutableMap.of( "tools", ImmutableMap.of("javac", temporaryFolder.newExecutableFile().toString()))) .build() .getView(JavaBuckConfig.class); assumeThat(config.getJavacSpec().getJavacSource(), is(Javac.Source.EXTERNAL)); assertFalse(config.trackClassUsage()); } @Test public void doNotTrackClassUsageEvenIfAskedForExternJavac() throws IOException { JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections( ImmutableMap.of( "tools", ImmutableMap.of("javac", temporaryFolder.newExecutableFile().toString()), "java", ImmutableMap.of("track_class_usage", "true"))) .build() .getView(JavaBuckConfig.class); assumeThat(config.getJavacSpec().getJavacSource(), is(Javac.Source.EXTERNAL)); assertFalse(config.trackClassUsage()); } @Test public void trackClassUsageByDefaultForJavacFromJar() throws IOException { JavaBuckConfig config = FakeBuckConfig.builder() .setFilesystem(defaultFilesystem) .setSections( ImmutableMap.of( "tools", ImmutableMap.of("javac_jar", temporaryFolder.newExecutableFile().toString()))) .build() .getView(JavaBuckConfig.class); assumeThat(config.getJavacSpec().getJavacSource(), is(Javac.Source.JAR)); assertTrue(config.trackClassUsage()); } @Test public void trackClassUsageByDefaultForJavacFromJDK() { JavaBuckConfig config = FakeBuckConfig.builder().build().getView(JavaBuckConfig.class); assumeThat(config.getJavacSpec().getJavacSource(), is(Javac.Source.JDK)); assertTrue(config.trackClassUsage()); } @Test public void testJavaLocationOutOfProcess() throws IOException, NoSuchBuildTargetException, InterruptedException { String content = Joiner.on('\n').join("[java]", " location = OUT_OF_PROCESS"); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(content)); assertThat( config.getJavacSpec().getJavacLocation(), Matchers.equalTo(Javac.Location.OUT_OF_PROCESS)); } @Test public void testJavaLocationInProcessByDefault() throws IOException, NoSuchBuildTargetException, InterruptedException { JavaBuckConfig config = createWithDefaultFilesystem(new StringReader("")); assertThat( config.getJavacSpec().getJavacLocation(), Matchers.equalTo(Javac.Location.IN_PROCESS)); } @Test public void testJavaLocationInProcess() throws IOException, NoSuchBuildTargetException, InterruptedException { String content = Joiner.on('\n').join("[java]", " location = IN_PROCESS"); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(content)); assertThat( config.getJavacSpec().getJavacLocation(), Matchers.equalTo(Javac.Location.IN_PROCESS)); } @Test public void testCompileFullJarsByDefault() throws IOException { JavaBuckConfig config = createWithDefaultFilesystem(new StringReader("")); JavacOptions options = config.getDefaultJavacOptions(); assertThat(options.getCompilationMode(), Matchers.equalTo(Javac.CompilationMode.FULL)); } @Test public void testSourceWithDepsABI() throws IOException { String content = Joiner.on('\n').join("[java]", " abi_generation_mode = source_with_deps"); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(content)); JavacOptions options = config.getDefaultJavacOptions(); assertThat(options.getCompilationMode(), Matchers.equalTo(Javac.CompilationMode.FULL)); } @Test public void testMigratingToSourceABI() throws IOException { String content = Joiner.on('\n').join("[java]", " abi_generation_mode = migrating_to_source"); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(content)); JavacOptions options = config.getDefaultJavacOptions(); assertThat( options.getCompilationMode(), Matchers.equalTo(Javac.CompilationMode.FULL_CHECKING_REFERENCES)); } @Test public void testSourceABINoDeps() throws IOException { String content = Joiner.on('\n').join("[java]", " abi_generation_mode = source"); JavaBuckConfig config = createWithDefaultFilesystem(new StringReader(content)); JavacOptions options = config.getDefaultJavacOptions(); assertThat( options.getCompilationMode(), Matchers.equalTo(Javac.CompilationMode.FULL_ENFORCING_REFERENCES)); } private void assertOptionKeyAbsent(JavacOptions options, String key) { OptionAccumulator optionsConsumer = visitOptions(options); assertThat(optionsConsumer.keyVals, not(hasKey(key))); } private void assertOptionsContains(JavacOptions options, String key, String value) { OptionAccumulator optionsConsumer = visitOptions(options); assertThat(optionsConsumer.keyVals, hasEntry(key, value)); } private OptionAccumulator visitOptions(JavacOptions options) { OptionAccumulator optionsConsumer = new OptionAccumulator(); options.appendOptionsTo( optionsConsumer, createMock(SourcePathResolver.class), defaultFilesystem); return optionsConsumer; } private JavaBuckConfig createWithDefaultFilesystem(Reader reader) throws IOException { BuckConfig raw = BuckConfigTestUtils.createFromReader( reader, defaultFilesystem, Architecture.detect(), Platform.detect(), ImmutableMap.copyOf(System.getenv())); return raw.getView(JavaBuckConfig.class); } }