package picocli; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ProvideSystemProperty; import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.rules.TestRule; import picocli.CommandLine.Command; import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Model.OptionSpec; import picocli.CommandLine.Model.PositionalParamSpec; import picocli.CommandLine.Model.UsageMessageSpec; import java.io.UnsupportedEncodingException; import static org.junit.Assert.*; import static picocli.TestUtil.usageString; public class ModelUsageMessageSpecTest { // allows tests to set any kind of properties they like, without having to individually roll them back @Rule public final TestRule restoreSystemProperties = new RestoreSystemProperties(); @Rule public final ProvideSystemProperty ansiOFF = new ProvideSystemProperty("picocli.ansi", "false"); @Test public void testEmptyModelUsageHelp() { CommandSpec spec = CommandSpec.create(); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); assertEquals(String.format("Usage:
%n"), actual); } @Test public void testModelUsageHelp() { CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-h", "--help").usageHelp(true).description("show help and exit").build()); spec.addOption(OptionSpec.builder("-V", "--version").versionHelp(true).description("show help and exit").build()); spec.addOption(OptionSpec.builder("-c", "--count").paramLabel("COUNT").arity("1").type(int.class).description("number of times to execute").build()); spec.addOption(OptionSpec.builder("-f", "--fix").paramLabel("FIXED(BOOLEAN)").arity("1").hideParamSyntax(true).required(true).description("run with fixed option").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
[-hV] [-c=COUNT] -f=FIXED(BOOLEAN)%n" + " -c, --count=COUNT number of times to execute%n" + " -f, --fix=FIXED(BOOLEAN) run with fixed option%n" + " -h, --help show help and exit%n" + " -V, --version show help and exit%n"); assertEquals(expected, actual); } @Test public void testModelUsageHelpWithCustomSeparator() { CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-h", "--help").usageHelp(true).description("show help and exit").build()); spec.addOption(OptionSpec.builder("-V", "--version").versionHelp(true).description("show help and exit").build()); spec.addOption(OptionSpec.builder("-c", "--count").paramLabel("COUNT").arity("1").type(int.class).description("number of times to execute").build()); spec.addOption(OptionSpec.builder("-f", "--fix").paramLabel("FIXED(=BOOLEAN)").arity("1").hideParamSyntax(true).required(true).description("run with fixed option").build()); CommandLine commandLine = new CommandLine(spec).setSeparator(" "); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
[-hV] [-c COUNT] -f FIXED(=BOOLEAN)%n" + " -c, --count COUNT number of times to execute%n" + " -f, --fix FIXED(=BOOLEAN)%n" + " run with fixed option%n" + " -h, --help show help and exit%n" + " -V, --version show help and exit%n"); assertEquals(expected, actual); } @Test public void testUsageHelpPositional_empty() { CommandSpec spec = CommandSpec.create(); spec.addPositional(PositionalParamSpec.builder().build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
PARAM%n" + " PARAM%n"); assertEquals(expected, actual); } @Test public void testUsageHelpPositional_withDescription() { CommandSpec spec = CommandSpec.create(); spec.addPositional(PositionalParamSpec.builder().description("positional param").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
PARAM%n" + " PARAM positional param%n"); assertEquals(expected, actual); } @Test public void testUsageHelp_emptyWithAutoHelpMixin() { CommandSpec spec = CommandSpec.create().addMixin("auto", CommandSpec.forAnnotatedObject(new CommandLine.AutoHelpMixin())); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
[-hV]%n" + " -h, --help Show this help message and exit.%n" + " -V, --version Print version information and exit.%n"); assertEquals(expected, actual); } @Test public void testUsageHelp_CustomizedUsageMessage() { CommandSpec spec = CommandSpec.create().addMixin("auto", CommandSpec.forAnnotatedObject(new CommandLine.AutoHelpMixin())); spec.name("the awesome util"); spec.usageMessage() .descriptionHeading("Description heading%n") .description("description line 1", "description line 2") .footerHeading("Footer heading%n") .footer("footer line 1", "footer line 2") .headerHeading("Header heading%n") .header("header line 1", "header line 2") .optionListHeading("Options%n") .parameterListHeading("Positional Parameters%n"); spec.addPositional(PositionalParamSpec.builder().description("positional param").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Header heading%n" + "header line 1%n" + "header line 2%n" + "Usage: the awesome util [-hV] PARAM%n" + "Description heading%n" + "description line 1%n" + "description line 2%n" + "Positional Parameters%n" + " PARAM positional param%n" + "Options%n" + " -h, --help Show this help message and exit.%n" + " -V, --version Print version information and exit.%n" + "Footer heading%n" + "footer line 1%n" + "footer line 2%n"); assertEquals(expected, actual); } @Test public void testUsageHelp_abbreviateSynopsisWithoutPositional() throws UnsupportedEncodingException { CommandSpec spec = CommandSpec.create(); spec.usageMessage().abbreviateSynopsis(true).requiredOptionMarker('!').sortOptions(false); spec.addOption(OptionSpec.builder("-x").required(true).description("required").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
[OPTIONS]%n" + "! -x required%n"); assertEquals(expected, actual); } @Test public void testUsageHelp_abbreviateSynopsisWithPositional() throws UnsupportedEncodingException { CommandSpec spec = CommandSpec.create(); spec.usageMessage().abbreviateSynopsis(true).requiredOptionMarker('!').sortOptions(false); spec.addOption(OptionSpec.builder("-x").required(true).description("required").build()); spec.addPositional(PositionalParamSpec.builder().arity("1").paramLabel("POSITIONAL").description("positional").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, CommandLine.Help.Ansi.OFF); String expected = String.format("" + "Usage:
[OPTIONS] POSITIONAL%n" + "! POSITIONAL positional%n" + "! -x required%n"); assertEquals(expected, actual); } @Test public void testUsageHelp_width_default80() { assertEquals(80, UsageMessageSpec.DEFAULT_USAGE_WIDTH); assertEquals(UsageMessageSpec.DEFAULT_USAGE_WIDTH, new UsageMessageSpec().width()); } @Test public void testUsageHelp_width_configurableWithSystemProperty() { System.setProperty("picocli.usage.width", "67"); try { assertEquals(67, new UsageMessageSpec().width()); } finally { System.clearProperty("picocli.usage.width"); } } @Test public void testUsageHelp_width_SystemPropertyOverrulesSetValue() { System.setProperty("picocli.usage.width", "67"); try { assertEquals(67, new UsageMessageSpec().width(123).width()); } finally { System.clearProperty("picocli.usage.width"); } } @Test public void testUsageHelp_width_setter() { UsageMessageSpec spec = new UsageMessageSpec(); spec.width(67); assertEquals(67, spec.width()); } @Test(expected = CommandLine.InitializationException.class) public void testUsageHelp_width_setterDisallowsValuesBelow55() { new UsageMessageSpec().width(54); } @Test public void testUsageHelp_width_setterAllowsValuesAt55OrHigher() { assertEquals(55, new UsageMessageSpec().width(55).width()); assertEquals(Integer.MAX_VALUE, new UsageMessageSpec().width(Integer.MAX_VALUE).width()); } @Test public void testUsageMessageSpec_synopsisSubcommandLabelSetter() { @Command(name = "blah") class MyApp { @Command void sub() {} } CommandLine cmd = new CommandLine(new MyApp()); String expected = String.format("" + "Usage: blah [COMMAND]%n" + "Commands:%n" + " sub%n"); assertEquals(expected, cmd.getUsageMessage()); UsageMessageSpec spec = cmd.getCommandSpec().usageMessage(); assertEquals("[COMMAND]", spec.synopsisSubcommandLabel()); spec.synopsisSubcommandLabel("xxx"); assertEquals("xxx", spec.synopsisSubcommandLabel()); String expectedAfter = String.format("" + "Usage: blah xxx%n" + "Commands:%n" + " sub%n"); assertEquals(expectedAfter, cmd.getUsageMessage()); } @Test public void testUsageMessageSpec_showAtFileInUsageHelp() { @Command(name = "blah") class MyApp {} CommandLine cmd = new CommandLine(new MyApp()); String expected = String.format("" + "Usage: blah%n"); assertEquals(expected, cmd.getUsageMessage()); UsageMessageSpec spec = cmd.getCommandSpec().usageMessage(); assertFalse(spec.showAtFileInUsageHelp()); spec.showAtFileInUsageHelp(true); assertTrue(spec.showAtFileInUsageHelp()); String expectedAfter = String.format("" + "Usage: blah [@...]%n" + " [@...] One or more argument files containing options.%n"); assertEquals(expectedAfter, cmd.getUsageMessage()); } @Test public void testUsageMessageSpec_showEndOfOptionsDelimiterInUsageHelp() { @Command(name = "blah") class MyApp {} CommandLine cmd = new CommandLine(new MyApp()); String expected = String.format("" + "Usage: blah%n"); assertEquals(expected, cmd.getUsageMessage()); UsageMessageSpec spec = cmd.getCommandSpec().usageMessage(); assertFalse(spec.showEndOfOptionsDelimiterInUsageHelp()); spec.showEndOfOptionsDelimiterInUsageHelp(true); assertTrue(spec.showEndOfOptionsDelimiterInUsageHelp()); String expectedAfter = String.format("" + "Usage: blah [--]%n" + " -- This option can be used to separate command-line options from the list%n" + " of positional parameters.%n"); assertEquals(expectedAfter, cmd.getUsageMessage()); } @Test public void testUsageMessageSpec_updateFromCommand() { @Command(name = "blah", resourceBundle = "picocli.SharedMessages") class MyApp {} UsageMessageSpec spec = new UsageMessageSpec(); assertNull(spec.messages()); Command annotation = MyApp.class.getAnnotation(Command.class); CommandSpec commandSpec = CommandSpec.create(); spec.updateFromCommand(annotation, commandSpec, false); CommandLine.Model.Messages messages = spec.messages(); assertNotNull(messages); assertSame(commandSpec, messages.commandSpec()); assertEquals("picocli.SharedMessages", messages.resourceBundleBaseName()); } }