package io.bootique; import com.google.inject.ProvisionException; import io.bootique.meta.application.CommandMetadata; import io.bootique.meta.application.OptionMetadata; import io.bootique.cli.Cli; import io.bootique.command.CommandOutcome; import io.bootique.command.CommandWithMetadata; import io.bootique.config.CliConfigurationSource; import io.bootique.unit.BQInternalTestFactory; import org.junit.Assert; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import java.util.Collection; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class Bootique_CliOptionsIT { @Rule public BQInternalTestFactory runtimeFactory = new BQInternalTestFactory(); @Test public void testConfigOption() { BQRuntime runtime = runtimeFactory.app("--config=abc.yml").createRuntime(); assertEquals(runtime.getInstance(Cli.class).optionStrings(CliConfigurationSource.CONFIG_OPTION), "abc.yml"); } @Test public void testConfigOptions() { BQRuntime runtime = runtimeFactory.app("--config=abc.yml", "--config=xyz.yml").createRuntime(); assertEquals(runtime.getInstance(Cli.class).optionStrings(CliConfigurationSource.CONFIG_OPTION), "abc.yml", "xyz.yml"); } @Test public void testHelpOption() { BQRuntime runtime = runtimeFactory.app("--help").createRuntime(); assertTrue(runtime.getInstance(Cli.class).hasOption("help")); } @Test public void testHelpOption_Short() { BQRuntime runtime = runtimeFactory.app("-h").createRuntime(); assertTrue(runtime.getInstance(Cli.class).hasOption("help")); } @Test public void testNoHelpOption() { BQRuntime runtime = runtimeFactory.app("a", "b").createRuntime(); assertFalse(runtime.getInstance(Cli.class).hasOption("help")); } @Test public void testOverlappingOptions() { BQRuntime runtime = runtimeFactory.app("--o1") .module(b -> BQCoreModule.extend(b).addOptions( OptionMetadata.builder("o1").build(), OptionMetadata.builder("o2").build() )) .createRuntime(); assertTrue(runtime.getInstance(Cli.class).hasOption("o1")); assertFalse(runtime.getInstance(Cli.class).hasOption("o2")); } // TODO: ignoring this test for now. There is a bug in JOpt 5.0.3... // JOpt should detect conflicting options and throw an exception. Instead JOpts triggers second option. @Test(expected = ProvisionException.class) @Ignore public void testOverlappingOptions_Short() { BQRuntime runtime = runtimeFactory.app("-o") .module(b -> BQCoreModule.extend(b).addOptions( OptionMetadata.builder("o1").build(), OptionMetadata.builder("o2").build() )) .createRuntime(); runtime.getInstance(Cli.class); } @Test(expected = ProvisionException.class) public void testCommand_IllegalShort() { BQRuntime runtime = runtimeFactory.app("-x") .module(b -> BQCoreModule.extend(b).addCommand(XaCommand.class)) .createRuntime(); runtime.getInstance(Cli.class); } @Test public void testCommand_ExplicitShort() { BQRuntime runtime = runtimeFactory.app("-A") .module(b -> BQCoreModule.extend(b).addCommand(XaCommand.class)) .createRuntime(); assertTrue(runtime.getInstance(Cli.class).hasOption("xa")); } @Test(expected = ProvisionException.class) public void testOverlappingCommands_IllegalShort() { BQRuntime runtime = runtimeFactory.app("-x") .module(b -> BQCoreModule.extend(b).addCommand(XaCommand.class).addCommand(XbCommand.class)) .createRuntime(); runtime.getInstance(Cli.class); } @Test(expected = ProvisionException.class) public void testIllegalAbbreviation() { BQRuntime runtime = runtimeFactory.app("--xc") .module(b -> BQCoreModule.extend(b).addCommand(XccCommand.class)) .createRuntime(); runtime.getInstance(Cli.class); } @Test public void testOverlappingCommands_Short() { BQRuntime runtime = runtimeFactory.app("-A") .module(b -> BQCoreModule.extend(b).addCommand(XaCommand.class).addCommand(XbCommand.class)) .createRuntime(); assertTrue(runtime.getInstance(Cli.class).hasOption("xa")); assertFalse(runtime.getInstance(Cli.class).hasOption("xb")); } @Test public void testDefaultCommandOptions() { BQRuntime runtime = runtimeFactory.app("-l", "x", "--long=y", "-s") .module(binder -> BQCoreModule.extend(binder).setDefaultCommand(TestCommand.class)) .createRuntime(); Cli cli = runtime.getInstance(Cli.class); assertTrue(cli.hasOption("s")); Assert.assertEquals("x_y", String.join("_", cli.optionStrings("long"))); } private void assertEquals(Collection<String> result, String... expected) { assertArrayEquals(expected, result.toArray()); } static final class TestCommand extends CommandWithMetadata { public TestCommand() { super(CommandMetadata.builder(TestCommand.class) .addOption(OptionMetadata.builder("long").valueRequired()) .addOption(OptionMetadata.builder("s"))); } @Override public CommandOutcome run(Cli cli) { return CommandOutcome.succeeded(); } } static final class XaCommand extends CommandWithMetadata { public XaCommand() { super(CommandMetadata.builder(XaCommand.class).shortName('A')); } @Override public CommandOutcome run(Cli cli) { return CommandOutcome.succeeded(); } } static final class XbCommand extends CommandWithMetadata { public XbCommand() { super(CommandMetadata.builder(XbCommand.class).shortName('B')); } @Override public CommandOutcome run(Cli cli) { return CommandOutcome.succeeded(); } } static final class XccCommand extends CommandWithMetadata { public XccCommand() { super(CommandMetadata.builder(XccCommand.class).shortName('B')); } @Override public CommandOutcome run(Cli cli) { return CommandOutcome.succeeded(); } } }