blob: 3acced6a6d09f3d410c8e4e81ed80c820479d27a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ignite.internal.cli.core.repl.completer;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.ignite.internal.cli.commands.Options;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class DynamicCompleterRegistryTest {
DynamicCompleterRegistry registry;
DynamicCompleter completer1;
DynamicCompleter completer2;
DynamicCompleter completer3;
/** Makes reading easier. */
private static String[] words(String... words) {
return words;
}
@BeforeEach
void setUp() {
registry = new DynamicCompleterRegistry();
completer1 = words -> null;
completer2 = words -> null;
completer3 = words -> null;
}
@Test
void findsCompleterRegisteredWithMultyCommand() {
// Given
registry.register(
CompleterConf.builder()
.command("command1")
.command("command2").build(),
words -> completer1
);
// Then
assertThat(registry.findCompleters(words("command1")), containsInAnyOrder(completer1));
// And
assertThat(registry.findCompleters(words("command2")), containsInAnyOrder(completer1));
}
@Test
void findsCompletersRegisteredWithStaticCommand() {
// Given
registry.register(CompleterConf.forCommand("command1", "subcommand1"), words -> completer1);
registry.register(CompleterConf.forCommand("command1", "subcommand1"), words -> completer2);
registry.register(CompleterConf.forCommand("command2"), words -> completer3);
// When find completers for "command1"
List<DynamicCompleter> completers1 = registry.findCompleters(words("command1", "subcommand1"));
// Then
assertThat(completers1, containsInAnyOrder(completer1, completer2));
// And
List<DynamicCompleter> completers2 = registry.findCompleters(words("command2"));
assertThat(completers2, contains(completer3));
}
@Test
void returnsEmptyCollectionIfThereIsNoSuitableCompleter() {
// Given
registry.register(CompleterConf.forCommand("command1", "subcommand1"), words -> completer1);
registry.register(CompleterConf.forCommand("command1", "subcommand1"), words -> completer2);
registry.register(CompleterConf.forCommand("command2"), words -> completer3);
// Then
assertThat(registry.findCompleters(words("command1")), is(empty()));
assertThat(registry.findCompleters(words("command3")), is(empty()));
// But if command start with one of the registered prefixes
assertThat(
registry.findCompleters(words("command1", "subcommand1", "subsubcommand1")),
containsInAnyOrder(completer1, completer2)
);
}
@Test
void doesntReturnCompleterWithDisableOptions() {
// Given
registry.register(
CompleterConf.builder().command("command1", "subcommand1").disableOptions("--stopWord").build(),
words -> completer1
);
// Then
assertThat(
registry.findCompleters(words("command1", "subcommand1", "subsub1")),
containsInAnyOrder(completer1)
);
assertThat(
registry.findCompleters(words("command1", "subcommand1", "subsub1", "")),
containsInAnyOrder(completer1)
);
assertThat(
registry.findCompleters(words("command1", "subcommand1", "", "")),
containsInAnyOrder(completer1)
);
// But if command ends with a stop word
assertThat(
registry.findCompleters(words("command1", "subcommand1", "--stopWord")),
is(empty())
);
assertThat(
registry.findCompleters(words("command1", "subcommand1", "--stopWord", "")),
is(empty())
);
assertThat(
registry.findCompleters(words("command1", "subcommand1", "--stopWord", "do-not-complete-me")),
is(empty())
);
assertThat(
registry.findCompleters(words("command1", "subcommand1", "--stopWord", "do-not-complete-me", "but-complete-me")),
containsInAnyOrder(completer1)
);
}
@Test
@DisplayName("If enable options are provided than they are taken into account")
void enableOptions() {
// Given completer with enable option
registry.register(
CompleterConf.builder()
.command("command1")
.enableOptions("--complete-after-me", "-com")
.build(),
words -> completer1
);
// Then for words without those options there are no completers
assertThat(registry.findCompleters(words("command1")), is(empty()));
// And enable option should not be completed itself
assertThat(registry.findCompleters(words("command1", "-co")), is(empty()));
// But if any of the enable options are provided then completer is found
assertThat(registry.findCompleters(words("command1", "some", "--complete-after-me", "")), containsInAnyOrder(completer1));
assertThat(registry.findCompleters(words("command1", "-com", "")), containsInAnyOrder(completer1));
assertThat(registry.findCompleters(words("command1", "-com", " ")), containsInAnyOrder(completer1));
assertThat(registry.findCompleters(words("command1", "-com", "autocompleteme")), containsInAnyOrder(completer1));
}
@Test
@DisplayName("Combination of completers with the same enable/disable options")
void combinationOfCompleters() {
// Given first completer with disable option
registry.register(
CompleterConf.builder()
.command("node", "config", "show")
.disableOptions("-n").build(),
words -> completer1
);
// And the second completer with the same enable option
registry.register(
CompleterConf.builder().enableOptions("-n").build(),
(words -> completer2)
);
// Then they do not intersect
assertThat(
registry.findCompleters(words("node", "config", "show", "-n")), // "-n" is competed by completer2
both(hasSize(1)).and(containsInAnyOrder(completer2))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "nodeName")),
both(hasSize(1)).and(containsInAnyOrder(completer2))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "nodeName", " ")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "nodeName", "completeMe")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
}
@Test
@DisplayName("If some completer has exclusive enable option set then all other completers have this option as disable option")
void exclusiveEnableOption() {
// Given completer with exclusive enable option -n
registry.register(
CompleterConf.builder()
.command("node", "config", "show")
.enableOptions(Options.NODE_NAME)
.exclusiveEnableOptions().build(),
words -> completer1
);
// And completer for the same command
registry.register(
CompleterConf.forCommand("node", "config", "show"),
words -> completer2
);
// And common completer for other option
registry.register(
CompleterConf.builder().enableOptions("-l").build(),
words -> completer3
);
// Then exclusive option is on the priority and no other completer is used for -n
assertThat(
registry.findCompleters(words("node", "config", "show", "-n")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "nod")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
// But other cases work well
assertThat(
registry.findCompleters(words("node", "config", "show", "-l", "nod")),
both(hasSize(2)).and(containsInAnyOrder(completer2, completer3))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "node", " ")),
both(hasSize(1)).and(containsInAnyOrder(completer2))
);
}
@Test
@DisplayName(
"If some completer has exclusive enable option set then all other completers have this option as disable option, "
+ "registration order changed"
)
void exclusiveEnableOptionRegisterInAnotherOrder() {
// Given completers without exclusive enable option registered first
registry.register(
CompleterConf.forCommand("node", "config", "show"),
words -> completer2
);
registry.register(
CompleterConf.builder().enableOptions("-l").build(),
words -> completer3
);
// And exclusiveEnableOption is registered last
registry.register(
CompleterConf.builder()
.enableOptions("-n")
.exclusiveEnableOptions().build(),
words -> completer1
);
// Then exclusive option is on the priority and no other completer is used for -n
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "nod")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n")),
both(hasSize(1)).and(containsInAnyOrder(completer1))
);
// But other cases work well
assertThat(
registry.findCompleters(words("node", "config", "show", "-l", "nod")),
both(hasSize(2)).and(containsInAnyOrder(completer2, completer3))
);
assertThat(
registry.findCompleters(words("node", "config", "show", "-n", "node", "")),
both(hasSize(1)).and(containsInAnyOrder(completer2))
);
}
@Test
void doesNotReturnFilteredCandidates() {
// Given
registry.register(CompleterConf.builder()
.command("command1", "subcommand1")
.filter((words, candidates) -> {
return Arrays.stream(candidates)
.filter(it -> !"candidate2".equals(it))
.toArray(String[]::new);
}).build(), words -> ignored -> List.of("candidate1", "candidate2"));
// Then
List<DynamicCompleter> completers = registry.findCompleters(words("command1", "subcommand1"));
assertThat(completers, not(empty()));
List<String> candidates = completers.stream()
.flatMap(it -> it.complete(words("word")).stream())
.collect(Collectors.toList());
assertThat(candidates, contains("candidate1"));
assertThat(candidates, not(contains("candidate2")));
}
@Test
void positionalParameter() {
// Given completer for single positional parameter
registry.register(
CompleterConf.builder()
.command("cluster", "config", "show") // should be real commands
.singlePositionalParameter()
.build(),
words -> completer1
);
// When there is no positional argument typed
List<DynamicCompleter> completers = registry.findCompleters(words("cluster", "config", "show"));
// Then completer is returned
assertThat(completers, contains(completer1));
// When there is one positional argument typed
List<DynamicCompleter> completersWithPositional = registry.findCompleters(words("cluster", "config", "show", "arg1", ""));
// Then completer is not returned
assertThat(completersWithPositional, is(empty()));
}
@Test
void sameOptionDifferentCompleters() {
// Given
registry.register(
CompleterConf.builder()
.command("command", "subcommand1")
.enableOptions("--to")
.exclusiveEnableOptions().build(),
words -> completer1
);
registry.register(
CompleterConf.builder()
.command("command", "subcommand2")
.enableOptions("--to")
.exclusiveEnableOptions().build(),
words -> completer2);
// Then
assertThat(registry.findCompleters(words("command", "subcommand1", "--to")), containsInAnyOrder(completer1));
// And
assertThat(registry.findCompleters(words("command", "subcommand2", "--to")), containsInAnyOrder(completer2));
}
@Test
void positionParameterIsNotCollapsedWithOptions() {
registry.register(
CompleterConf.builder()
.enableOptions(Options.NODE_NAME)
.exclusiveEnableOptions().build(),
words -> completer1
);
registry.register(
CompleterConf.builder()
.command("cluster", "config", "show")
.command("cluster", "config", "update")
.singlePositionalParameter().build(),
words -> completer2
);
// Then
assertThat(
registry.findCompleters(words("cluster", "config", "update", Options.NODE_NAME.fullName(), "")),
hasSize(1)
);
// And
assertThat(
registry.findCompleters(words("cluster", "config", "update", "")),
hasSize(1)
);
}
}