From 9cb448bb150ba16ebec5baa3751ccf8e7eb077ef Mon Sep 17 00:00:00 2001 From: Loic Rouchon Date: Tue, 16 Mar 2021 19:42:26 +0100 Subject: [PATCH] #1346 Add test for AutoComplete custom types path completion --- src/main/java/picocli/AutoComplete.java | 2 +- src/test/java/picocli/AutoCompleteTest.java | 119 +++++++++++++++++++- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/main/java/picocli/AutoComplete.java b/src/main/java/picocli/AutoComplete.java index f0ec9bd60..eca8639e8 100644 --- a/src/main/java/picocli/AutoComplete.java +++ b/src/main/java/picocli/AutoComplete.java @@ -149,7 +149,7 @@ private static class App implements Callable { "as the completion script.") boolean writeCommandScript; - @Option(names = {"-p", "--pathTypes"}, split=",", description = "Comma-separated list of fully " + @Option(names = {"-p", "--pathCompletionTypes"}, split=",", description = "Comma-separated list of fully " + "qualified custom types for which to delegate to built-in path name completion.") List pathCompletionTypes = new ArrayList(); diff --git a/src/test/java/picocli/AutoCompleteTest.java b/src/test/java/picocli/AutoCompleteTest.java index de5a57b89..21cebb387 100644 --- a/src/test/java/picocli/AutoCompleteTest.java +++ b/src/test/java/picocli/AutoCompleteTest.java @@ -15,6 +15,7 @@ */ package picocli; +import java.util.regex.Pattern; import org.hamcrest.CoreMatchers; import org.junit.Rule; import org.junit.Test; @@ -247,7 +248,8 @@ private static String toString(Object obj) { private static final String AUTO_COMPLETE_APP_USAGE = String.format("" + "Usage: picocli.AutoComplete [-fhVw] [-c=] [-n=]%n" + - " [-o=] [@...]%n" + + " [-o=] [-p=%n" + + " [,...]]... [@...]%n" + " %n" + "Generates a bash completion script for the specified command class.%n" + " [@...] One or more argument files containing options.%n" + @@ -272,6 +274,10 @@ private static String toString(Object obj) { " the current directory.%n" + " -w, --writeCommandScript Write a '' sample command script to%n" + " the same directory as the completion script.%n" + + " -p, --pathCompletionTypes=[,...]%n" + + " Comma-separated list of fully qualified custom%n" + + " types for which to delegate to built-in path%n" + + " name completion.%n" + " -f, --force Overwrite existing script files.%n" + " -h, --help Show this help message and exit.%n" + " -V, --version Print version information and exit.%n" + @@ -761,7 +767,7 @@ private String expectedCompletionScriptForAutoCompleteApp() { "\n" + " local commands=\"\"\n" + " local flag_opts=\"-w --writeCommandScript -f --force -h --help -V --version\"\n" + - " local arg_opts=\"-c --factory -n --name -o --completionScript\"\n" + + " local arg_opts=\"-c --factory -n --name -o --completionScript -p --pathCompletionTypes\"\n" + "\n" + " compopt +o default\n" + "\n" + @@ -777,6 +783,9 @@ private String expectedCompletionScriptForAutoCompleteApp() { " COMPREPLY=( $( compgen -f -- \"${curr_word}\" ) ) # files\n" + " return $?\n" + " ;;\n" + + " -p|--pathCompletionTypes)\n" + + " return\n" + + " ;;\n" + " esac\n" + "\n" + " if [[ \"${curr_word}\" == -* ]]; then\n" + @@ -1822,5 +1831,111 @@ public void run() { static class NestedLevel1 implements Runnable { public void run() { } + + } + + @Test + public void testPathCompletionOnCustomTypes() throws IOException { + final String commandName = "bestCommandEver"; + final File completionScript = new File(commandName + "_completion"); + if (completionScript.exists()) {assertTrue(completionScript.delete());} + completionScript.deleteOnExit(); + + AutoComplete.main(String.format("--name=%s", commandName), + String.format("--pathCompletionTypes=%s,%s", + PathCompletionCommand.CustomPath1.class.getName(), + PathCompletionCommand.CustomPath2.class.getName()), + "picocli.AutoCompleteTest$PathCompletionCommand"); + + byte[] completion = readBytes(completionScript); + assertTrue(completionScript.delete()); + + String expected = expectedCommandCompletion(commandName, + "function _picocli_bestCommandEver() {\n" + + " # Get completion data\n" + + " local curr_word=${COMP_WORDS[COMP_CWORD]}\n" + + " local prev_word=${COMP_WORDS[COMP_CWORD-1]}\n" + + "\n" + + " local commands=\"\"\n" + + " local flag_opts=\"\"\n" + + " local arg_opts=\"--file --custom-path-1 --custom-path-2 --custom-type\"\n" + + "\n" + + " compopt +o default\n" + + "\n" + + " case ${prev_word} in\n" + + " --file)\n" + + " compopt -o filenames\n" + + " COMPREPLY=( $( compgen -f -- \"${curr_word}\" ) ) # files\n" + + " return $?\n" + + " ;;\n" + + " --custom-path-1)\n" + + " compopt -o filenames\n" + + " COMPREPLY=( $( compgen -f -- \"${curr_word}\" ) ) # files\n" + + " return $?\n" + + " ;;\n" + + " --custom-path-2)\n" + + " compopt -o filenames\n" + + " COMPREPLY=( $( compgen -f -- \"${curr_word}\" ) ) # files\n" + + " return $?\n" + + " ;;\n" + + " --custom-type)\n" + + " return\n" + + " ;;\n" + + " esac\n" + + "\n" + + " if [[ \"${curr_word}\" == -* ]]; then\n" + + " COMPREPLY=( $(compgen -W \"${flag_opts} ${arg_opts}\" -- \"${curr_word}\") )\n" + + " else\n" + + " local positionals=\"\"\n" + + " COMPREPLY=( $(compgen -W \"${commands} ${positionals}\" -- \"${curr_word}\") )\n" + + " fi\n" + + "}\n"); + + assertEquals(expected, new String(completion, "UTF8")); + } + + private String expectedCommandCompletion(String commandName, String autoCompleteFunctionContent) { + String expected = expectedCompletionScriptForAutoCompleteApp() + .replaceAll("picocli\\.AutoComplete", commandName); + expected = Pattern.compile("function _picocli_" + commandName + "\\(\\) \\{\n" + + "(.+)\n" + + "}\n" + + "\n" + + "# Define a completion specification \\(a compspec\\) for the", Pattern.DOTALL) + .matcher(expected) + .replaceFirst(autoCompleteFunctionContent.replace("$", "\\$") + + "\n# Define a completion specification (a compspec) for the"); + return expected; + } + + @Command(name = "PathCompletion") + static class PathCompletionCommand implements Runnable { + + @Option(names = "--file") + private File file; + + @Option(names = "--custom-path-1") + private CustomPath1 customPath1; + + @Option(names = "--custom-path-2") + private List customPath2; + + @Option(names = "--custom-type") + private CustomType customType; + + public void run() { + } + + static class CustomPath1 { + String value; + } + + static class CustomPath2 { + String value; + } + + static class CustomType { + String value; + } } }