Package org.springframework.shell.core

Source Code of org.springframework.shell.core.SimpleParserTests$ExpertCompletions

/*
* Copyright 2013 the original author or authors.
*
* 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 org.springframework.shell.core;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import org.hamcrest.Description;
import org.hamcrest.DiagnosingMatcher;
import org.hamcrest.Matcher;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.shell.event.ParseResult;

/**
* Tests for parsing and completion logic.
*
* @author Eric Bottard
*/
public class SimpleParserTests {

  private SimpleParser parser = new SimpleParser();

  private int offset;

  private String buffer;

  private ArrayList<Completion> candidates = new ArrayList<Completion>();

  @Test
  public void testSimpleCommandNameCompletion() {
    parser.add(new MyCommands());

    buffer = "f";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("foo ")))));
  }

  @Test
  public void testSimpleArgumentNameCompletion() {
    parser.add(new MyCommands());

    buffer = "bar --op";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 ")))));
  }

  @Test
  public void testSimpleArgumentValueCompletion() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "ghi")));

    buffer = "bar --option1 a";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 abc")))));
  }

  @Test
  public void testArgumentValueCompletionWhenQuoted() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "ghi")));

    buffer = "bar --option1 \"a";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"abc")))));
  }

  @Test
  public void testCompletionInMiddleOfBuffer() {
    parser.add(new MyCommands());

    buffer = "bar --optimum";
    offset = parser.completeAdvanced(buffer, "bar --opti".length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 ")))));

  }

  @Test
  public void testArgumentValueCompletionWhenAmbiguity() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "abd")));

    buffer = "bar --option1 a";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(startsWith("bar --option1 ab"))));
  }

  @Test
  public void testArgumentValueCompletionWhenAmbiguityUsingQuotes() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "abd")));

    buffer = "bar --option1 \"a";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"abc")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"abd")))));
  }

  @Test
  public void testArgumentValueCompletionUnderstandsEndQuote() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "abd")));

    buffer = "bar --option1 \"ab\"";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, is(empty()));
  }

  @Test
  public void testArgumentValueCompletionAlreadyGiven() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abc", "def", "ghi")));

    buffer = "bar --option1 def";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, is(empty()));
  }

  @Test
  public void testDashDashIntoOption() {
    parser.add(new MyCommands());

    buffer = "bar --";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 ")))));
  }

  @Test
  public void testArgumentValueWithEscapedQuotes() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("he said \"hello\" to me")));

    buffer = "bar --option1 \"he said \\\"he";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"he said \\\"hello\\\" to me")))));

  }

  @Test
  public void testNoCompletionsFound() {
    parser.add(new MyCommands());

    buffer = "notthere";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, empty());

  }

  @Test
  public void testCommandAmbiguity() {
    parser.add(new MyCommands());

    buffer = "b";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bing ")))));

  }

  @Test
  public void testUnfinishedCommandThatHasParams() {
    parser.add(new MyCommands());

    buffer = "ba";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar ")))));

  }

  @Test
  public void testDontMisinterpretDashDashInArgumentValue() {
    parser.add(new MyCommands());

    buffer = "bar --option1 \"I end with --";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, empty());

  }

  @Test
  public void testWithDefaultKey() {
    parser.add(new MyCommands());

    buffer = "testDefaultKey thevalue --optio";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("testDefaultKey thevalue --option2 ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("testDefaultKey thevalue --option3 ")))));
    assertThat(candidates, not(hasItem(completionThat(containsString("option1")))));

    // Let's do it again with default key in the middle
    candidates.clear();
    buffer = "testDefaultKey --option3 foo thevalue --optio";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("testDefaultKey --option3 foo thevalue --option2 ")))));
    assertThat(candidates, not(hasItem(completionThat(endsWith("option3 ")))));

  }

  @Test
  public void testStopAtFirstWhenMandatory() {
    parser.add(new MyCommands());

    buffer = "testMandatory --";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("testMandatory --option1 ")))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("testMandatory --option2 "))))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("testMandatory --option3 "))))));

  }

  @Test
  public void testDontStopAtFirstWhenNotMandatory() {
    parser.add(new MyCommands());

    buffer = "testNotMandatory --";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("testNotMandatory --option1 ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("testNotMandatory --option2 ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("testNotMandatory --option3 ")))));

  }

  @Test
  public void testAtEndOfKeyOption() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abd", "def")));

    buffer = "fileMore";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("fileMore --option ")))));

    // Do it again with a trailing space
    buffer = "fileMore ";
    candidates.clear();
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("fileMore --option ")))));

  }

  @Test
  public void testAtEndOfKeyOptionWithEvenLongerKeyOption() {
    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abd", "def")));

    buffer = "file";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("file ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("fileMore ")))));

    // Do it again with a trailing space
    buffer = "file ";
    candidates.clear();
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    // TODO
    // assertThat(candidates, hasItem(completionThat(is(equalTo("file --option")))));
    // assertThat(candidates, not(hasItem(completionThat(startsWith("fileMore")))));

  }

  @Test
  public void testPrefixMatching() {
    assertThat(SimpleParser.isMatch("hello", "hello", true), is(equalTo("")));
    assertThat(SimpleParser.isMatch("hello there", "hello", true), is(equalTo("there")));
    assertThat(SimpleParser.isMatch("hello there", "hello there", true), is(equalTo("")));
    assertThat(SimpleParser.isMatch("hell", "hello", true), is(equalTo("")));

    assertThat(SimpleParser.isMatch("hello", "hello there", true), is(nullValue()));
    assertThat(SimpleParser.isMatch("hello", "hello there", false), is(equalTo("")));

    assertThat(SimpleParser.isMatch("hi", "hello", true), is(nullValue()));

    assertThat(SimpleParser.isMatch("hello", "hellothere", false), is(equalTo("")));
    assertThat(SimpleParser.isMatch("hello", "hellothere", true), is(equalTo("")));
    // TODO
    // assertThat(SimpleParser.isMatch("hello ", "hellothere", true), is(nullValue()));
  }

  @Test
  public void testValueCompletionsThatCanContinue() {

    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abd", "def"), false));

    // With space as delimiter
    buffer = "bar --option1 ";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 abd")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 def")))));

    // With quotes as delimiter
    buffer = "bar --option1 \"";
    candidates.clear();
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"abd")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"def")))));
  }

  @Test
  public void testValueCompletionsThatCannotContinue() {

    parser.add(new MyCommands());
    parser.add(new StringCompletions(Arrays.asList("abd", "def"), true));

    // With space as delimiter
    buffer = "bar --option1 ";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 abd ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 def ")))));

    // With quotes as delimiter
    buffer = "bar --option1 \"";
    candidates.clear();
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"abd\" ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"def\" ")))));
  }

  @Test
  public void testSuccessiveInvocationsOfCompletion() {

    parser.add(new MyCommands());
    parser.add(new ExpertCompletions());

    buffer = "bar --option1 ";
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 one ")))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("bar --option1 two "))))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("bar --option1 three "))))));

    candidates.clear();
    // Simulate <TAB> twice
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 one ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 two ")))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("bar --option1 three "))))));

    candidates.clear();
    // Simulate <TAB> three times
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 one ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 two ")))));
    assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 three ")))));

    // And now for something completely different
    buffer = "testMandatory --option2 ";
    candidates.clear();
    offset = parser.completeAdvanced(buffer, buffer.length(), candidates);

    assertThat(candidates, hasItem(completionThat(is(equalTo("testMandatory --option2 one ")))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("testMandatory --option2 two "))))));
    assertThat(candidates, not(hasItem(completionThat(is(equalTo("testMandatory --option2 three "))))));

  }

  /**
   * @see https://jira.spring.io/browse/SHL-113
   */
  @Test
  public void testFalseAmbiguity() {
    parser.add(new SamePrefixCommands());
    ParseResult result = parser.parse("foo");
    assertThat(result.getMethod().getName(), equalTo("foo"));
  }

  @Test
  public void testRealAmbiguity() {
    parser.add(new SamePrefixCommands());
    ParseResult result = parser.parse("fo");
    assertThat(result, nullValue(ParseResult.class));
  }

  /**
   * Return a matcher that asserts that a completion, when added to {@link #buffer} at the given {@link #offset},
   * indeed matches the provided matcher.
   */
  private Matcher<Completion> completionThat(final Matcher<String> matcher) {
    return new DiagnosingMatcher<Completion>() {

      @Override
      public void describeTo(Description description) {
        description.appendText("a completion that ").appendDescriptionOf(matcher);
      }

      @Override
      protected boolean matches(Object item, Description mismatchDescription) {
        Completion completion = (Completion) item;
        StringBuilder sb = new StringBuilder(buffer);
        sb.setLength(offset);
        sb.append(completion.getValue());
        boolean match = matcher.matches(sb.toString());
        mismatchDescription.appendText("result was ")
            .appendValue(sb.insert(offset, '[').append(']').toString());
        return match;
      }
    };
  }

  public static class MyCommands implements CommandMarker {

    @CliCommand("foo")
    public void foo() {

    }

    @CliCommand("bar")
    public void bar(@CliOption(key = "option1")
    String option1) {

    }

    @CliCommand("bing")
    public void bang() {

    }

    @CliCommand("testMandatory")
    public void testMandatory(@CliOption(key = "option1", mandatory = true)
    String option1, @CliOption(key = "option2", mandatory = true)
    String option2, @CliOption(key = "option3")
    String option3) {

    }

    @CliCommand("testNotMandatory")
    public void testNotMandatory(@CliOption(key = "option1")
    String option1, @CliOption(key = "option2")
    String option2, @CliOption(key = "option3")
    String option3) {

    }

    @CliCommand("testDefaultKey")
    public void testDefaultKey(@CliOption(key = "")
    String option1, @CliOption(key = "option2")
    String option2, @CliOption(key = "option3")
    String option3) {

    }

    @CliCommand("file")
    public void file(@CliOption(key = "option", mandatory = true)
    String option) {

    }

    @CliCommand("fileMore")
    public void fileMore(@CliOption(key = "option", mandatory = true)
    String option) {

    }
  }

  public static class SamePrefixCommands implements CommandMarker {
    @CliCommand(value = "foo")
    public String foo(@CliOption(key = "")
    String arg) {
      return "foo " + arg;
    }

    @CliCommand(value = "fooBar")
    public String fooBar(@CliOption(key = "")
    String arg) {
      return "fooBar " + arg;
    }
  }

  public static class StringCompletions implements Converter<String> {

    private final List<String> completions;

    private final boolean canContinue;

    public StringCompletions(List<String> completions) {
      this(completions, false);
    }

    public StringCompletions(List<String> completions, boolean canContinue) {
      this.completions = completions;
      this.canContinue = canContinue;
    }

    @Override
    public boolean supports(Class<?> type, String optionContext) {
      return type == String.class;
    }

    @Override
    public String convertFromText(String value, Class<?> targetType, String optionContext) {
      return value;
    }

    @Override
    public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData,
        String optionContext, MethodTarget target) {
      for (String s : this.completions) {
        completions.add(new Completion(s));
      }
      return canContinue;
    }

  }

  public static class ExpertCompletions implements Converter<String> {

    private static final Pattern NUMBER_OF_COMPLETIONS_CAPTURE = Pattern.compile(".*completion-count-(\\d+).*");

    private static final String[] results = new String[] { "one", "two", "three" };

    @Override
    public boolean supports(Class<?> type, String optionContext) {
      return true;
    }

    @Override
    public String convertFromText(String value, Class<?> targetType, String optionContext) {
      return value;
    }

    @Override
    public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData,
        String optionContext, MethodTarget target) {
      java.util.regex.Matcher m = NUMBER_OF_COMPLETIONS_CAPTURE.matcher(optionContext);
      Assert.assertTrue(m.matches());
      int invocations = Integer.parseInt(m.group(1));
      for (int i = 0; i < invocations; i++) {
        completions.add(new Completion(results[i]));
      }
      return true;
    }

  }

}
TOP

Related Classes of org.springframework.shell.core.SimpleParserTests$ExpertCompletions

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.