Migrate completion tests to Cucumber.

Also retire Fish 2.x + macOS test;
installation of custom brew didn't work out anymore.
This commit is contained in:
Raphael Reitzig 2020-05-25 20:17:31 +02:00
parent ed6039e533
commit 0c15f199cd
12 changed files with 364 additions and 236 deletions

View file

@ -0,0 +1,186 @@
Feature: Shell Completion
We want to get the correct completion on the CLI.
Background:
Given SDKMAN! candidate list is up to date
And candidate ant is installed at version 1.9.9
And candidate ant is installed at version 1.10.1
And candidate crash is installed
Scenario: Command list correct
When the user enters " " into the prompt
Then completion should propose "b, broadcast, c, current, d, default, flush, h, help, i, install, list, ls, offline, rm, selfupdate, u, ug, uninstall, update, upgrade, use, v, version"
Scenario Outline: Commands complete
When the user enters "<cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| b | b, broadcast |
| c | c, current |
| d | d, default |
| f | flush |
| h | h, help |
| i | i, install |
| in | install |
| l | list, ls |
| o | offline |
| r | rm |
| s | selfupdate |
| u | u, ug, uninstall, update, upgrade, use |
| un | uninstall |
| up | update, upgrade |
| us | use |
| v | v, version |
# Currently uncovered; include to catch new upstream commands:
| a | |
| e | |
| g | |
| j | |
| k | |
| m | |
| n | |
| p | |
| q | |
| t | |
| w | |
| x | |
| y | |
| z | |
Scenario Outline: Completion for 'install'
When the user enters "install <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| an | ant |
| xyz | |
| 1. | |
| gra | gradle, grails |
| grad | gradle |
| gradk | |
# | ant 1.10. | 1.10.0, 1.10.1 | # TODO: list installable versions --> issue #4
| ant 1.10.2-mine /tm | /tmp/ |
| 'ant 1.10.2-mine /tmp ' | |
Scenario Outline: Completion for 'uninstall'
When the user enters "uninstall <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | ant, crash |
| a | ant |
| j | |
| 1. | |
| an | ant | # installed
| gr | | # none installed
| xyz | | # no such candidate
| 'an ' | | # no such candidate installed
| 'ant 1' | 1.10.1, 1.9.9 |
| 'ant 1.10.' | 1.10.1 |
| 'ant 2' | |
| 'ant 1.10.1 ' | |
Scenario Outline: Completion for 'list'
When the user enters "list <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| an | ant |
| xyz | |
| 1. | |
| 'ant ' | |
Scenario Outline: Completion for 'use'
When the user enters "use <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | ant, crash |
| an | ant |
| j | |
| 1. | |
| 'ant ' | 1.10.1, 1.9.9 |
| 'ant 1.10.1 ' | |
Scenario Outline: Completion for 'default'
When the user enters "default <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | ant, crash |
| an | ant |
| j | |
| 1. | |
| 'ant ' | 1.10.1, 1.9.9 |
| 'ant 1.10.1 ' | |
Scenario Outline: Completion for 'current'
When the user enters "current <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| an | ant | # --> installed version
| ja | java | # --> not installed
| xyz | |
| 1. | |
| 'ant ' | |
Scenario Outline: Completion for 'upgrade'
When the user enters "upgrade <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | ant, crash |
| an | ant |
| j | |
| 1. | |
| 'ant ' | |
Scenario Outline: Completion for 'offline'
When the user enters "offline <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | disable, enable |
| e | enable |
| d | disable |
| a | |
| 'enable ' | |
Scenario Outline: Completion for 'selfupdate'
When the user enters "selfupdate <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | force |
| f | force |
| a | |
| 'force ' | |
Scenario Outline: Completion for 'flush'
When the user enters "flush <cmd>" into the prompt
Then completion should propose "<completions>"
Examples:
| cmd | completions |
| | archives, broadcast, temp |
| b | broadcast |
| a | archives |
| t | temp |
| x | |
| 'temp ' | |
Scenario Outline: Completion for commands without parameters
When the user enters "<cmd>" into the prompt
Then completion should propose ""
Examples:
| cmd |
| 'version ' |
| 'version a' |
| 'broadcast ' |
| 'broadcast a' |
| 'help ' |
| 'help a' |
| 'update ' |
| 'update a' |

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'open3'
module CompletionHelper
def complete(cmd)
completions = run_fish_command("complete -C\"sdk #{cmd}\"")
completions.split("\n") \
.map { |line| line.split(/\s+/)[0].strip } \
.sort \
.uniq \
.join(', ')
# TODO: Why do we get duplicates in the Docker container?
# --> remove uniq
end
end
World CompletionHelper
When('the user enters {string} into the prompt') do |cmd|
@response = complete(cmd.gsub(/["']/, ''))
end
Then(/^completion should propose "(.*)"$/) do |completions|
expect(@response).to eq(completions)
end

View file

@ -0,0 +1,31 @@
$index_updated = false # TODO: Hack since Cucumber doesn't have Feature-level hooks
Given(/^SDKMAN! candidate list is up to date$/) do
unless $index_updated
run_bash_command('sdk update')
$index_updated = true
end
end
Given(/^candidate (\w+) is installed at version (\d+(?:\.\d+)*)$/) do |candidate, version|
run_bash_command("sdk install #{candidate} #{version}") unless installed?(candidate, version)
end
Given(/^candidate (\w+) is installed$/) do |candidate|
run_bash_command("sdk install #{candidate}") unless installed?(candidate)
end
# Uninstall all SDKMAN! candidates
# TODO: Run after every scenario, this makes tests very slow.
# Currently, Cucumber doesn't have Feature-level hooks, so we have to work around:
# --> install only if not already installed;
# if the test needs a candidate to _not_ be there, make it explicit.
# --> clean up after _all_ features at least
at_exit do
Dir["#{ENV['HOME']}/.sdkman/candidates/*/*"].each do |candidate_dir|
%r{/([^/]+)/([^/]+)$}.match(candidate_dir) do |match|
candidate = match[1]
version = match[2]
run_bash_command("sdk rm #{candidate} #{version}") unless version == 'current'
end
end
end

View file

@ -0,0 +1,42 @@
# frozen_string_literal: true
def list_installed_candidates
candidates = {}
Dir["#{ENV['HOME']}/.sdkman/candidates/*/*"].each do |candidate_dir|
%r{/([^/]+)/([^/]+)$}.match(candidate_dir) do |match|
candidate = match[1]
version = match[2]
candidates[candidate] = [] unless candidates.key?(candidate)
candidates[candidate].push version unless version == 'current'
end
end
candidates
end
def installed?(candidate, version = nil)
candidates = list_installed_candidates
candidates.key?(candidate) && (version.nil? || candidates[candidate].include?(version))
end
def run_bash_command(cmd)
stdout, stderr, status = Open3.capture3("bash -c 'source \"$HOME/.sdkman/bin/sdkman-init.sh\"; #{cmd}'")
unless status.success?
warn(stderr)
raise "Bash command failed: #{stderr}"
end
stdout
end
def run_fish_command(cmd)
# NB: Fish errors out if we don't set terminal dimensions
stdout, stderr, status = Open3.capture3("fish -c 'stty rows 80 columns 80; #{cmd}'")
unless status.success?
warn(stderr)
raise 'Fish command failed'
end
stdout
end