From 0c15f199cd34a26737d2cc811e091157c3633986 Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Mon, 25 May 2020 20:17:31 +0200
Subject: [PATCH 1/9] Migrate completion tests to Cucumber.
Also retire Fish 2.x + macOS test;
installation of custom brew didn't work out anymore.
---
.idea/runConfigurations/Test.xml | 17 ++
.travis.yml | 16 +-
README.md | 16 ++
test/Dockerfile | 33 ++++
test/Gemfile | 6 +
test/Homebrew-Formula-fish-2.7.1.rb | 60 ------
test/completion.rb | 162 ----------------
test/features/completions.feature | 186 +++++++++++++++++++
test/features/step_definitions/completion.rb | 26 +++
test/features/step_definitions/setup.rb | 31 ++++
test/features/support/helpers.rb | 42 +++++
test/prepare_tests.sh | 5 +-
12 files changed, 364 insertions(+), 236 deletions(-)
create mode 100644 .idea/runConfigurations/Test.xml
create mode 100644 test/Dockerfile
create mode 100644 test/Gemfile
delete mode 100644 test/Homebrew-Formula-fish-2.7.1.rb
delete mode 100644 test/completion.rb
create mode 100644 test/features/completions.feature
create mode 100644 test/features/step_definitions/completion.rb
create mode 100644 test/features/step_definitions/setup.rb
create mode 100644 test/features/support/helpers.rb
diff --git a/.idea/runConfigurations/Test.xml b/.idea/runConfigurations/Test.xml
new file mode 100644
index 0000000..700aee0
--- /dev/null
+++ b/.idea/runConfigurations/Test.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 9ae19b0..7a17061 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,13 +16,6 @@ matrix:
- sourceline: "ppa:fish-shell/release-3"
packages:
- fish
- - os: osx
- env: FISH=2
- addons:
- homebrew:
- packages:
- - 'test/Homebrew-Formula-fish-2.7.1.rb'
- update: true # TODO: build should be green without, but isn't
- os: osx
env: FISH=3
addons:
@@ -33,18 +26,19 @@ matrix:
before_install:
- curl -s "https://get.sdkman.io" | bash
- - bash test/prepare_tests.sh
+ - bundle install --gemfile=test/Gemfile --no-cache
+ - uname -a; fish --version; sdk version; ruby --version; cucumber --version
install:
- mkdir -p "${HOME}"/.config/fish/{completions,conf.d,functions}
- cp completions/* "${HOME}"/.config/fish/completions/
- cp conf.d/* "${HOME}"/.config/fish/conf.d/
- cp functions/* "${HOME}"/.config/fish/functions/
- - uname -a; fish --version
script:
- - ruby test/completion.rb
- - fish test/wrapper.fish
+ - (cd test && cucumber)
+ # TODO: Migrate these to Cucumber:
+ - bash test/prepare_tests.sh && fish test/wrapper.fish
- fish test/reinitialize.fish
- fish -c "sdk install crash 1.3.0; and sdk uninstall crash 1.3.0" > /dev/null && fish test/check_for_path_zombies.fish
- bash test/remove_sdkman.sh > /dev/null && fish -c "echo 'y' | sdk" > /dev/null && fish -c "sdk version"
diff --git a/README.md b/README.md
index 38e6031..56b3490 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,22 @@ _Note:_
It's all in the background; you should be able to run `sdk` and binaries installed
with `sdk` as you would expect.
+## Contribute
+
+When you make changes,
+please run the tests at least on one platform before creating a pull request.
+
+As the tests may mess up your own setup
+-- you have been warned! --
+the recommended way is to run the tests in a Docker container:
+
+```bash
+docker build -t sdkman-for-fish-tests -f test/Dockerfile .
+docker run --rm sdkman-for-fish-tests
+```
+
+A run configuration for Jetbrains IDEs is included.
+
## Acknowledgements
* Completion originally by [Ted Wise](https://github.com/ctwise); see his
diff --git a/test/Dockerfile b/test/Dockerfile
new file mode 100644
index 0000000..09f8669
--- /dev/null
+++ b/test/Dockerfile
@@ -0,0 +1,33 @@
+FROM ruby:2.5.8-slim-buster
+
+# Install dependencies
+RUN apt-get update \
+ && apt-get -y install \
+ fish \
+ curl \
+ unzip \
+ zip \
+ && apt-get clean
+
+WORKDIR app
+COPY test/Gemfile ./
+RUN bundle install \
+ && rm Gemfile
+
+# Switch to non-root user for test context
+ARG TEST_HOME="/home/test"
+RUN groupadd -r test \
+ && useradd --no-log-init -r -g test -m -d $TEST_HOME test
+USER test
+RUN curl -s "https://get.sdkman.io" | bash
+
+# "Install" sdkman-for-fish
+RUN mkdir -p $TEST_HOME/.config/fish/
+COPY completions $TEST_HOME/.config/fish/completions/
+COPY conf.d $TEST_HOME/.config/fish/conf.d/
+COPY completions $TEST_HOME/.config/fish/functions/
+RUN ls -R $TEST_HOME/.config/fish/
+
+# Run tests
+COPY test ./
+CMD cucumber
diff --git a/test/Gemfile b/test/Gemfile
new file mode 100644
index 0000000..70d69fe
--- /dev/null
+++ b/test/Gemfile
@@ -0,0 +1,6 @@
+source "https://rubygems.org"
+
+group :test do
+ gem 'cucumber', '~> 3.1.0'
+ gem 'rspec', '~> 3.7.0'
+end
diff --git a/test/Homebrew-Formula-fish-2.7.1.rb b/test/Homebrew-Formula-fish-2.7.1.rb
deleted file mode 100644
index 3a463db..0000000
--- a/test/Homebrew-Formula-fish-2.7.1.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-class HomebrewFormulaFish271 < Formula
- desc "User-friendly command-line shell for UNIX-like operating systems"
- homepage "https://fishshell.com"
- url "https://github.com/fish-shell/fish-shell/releases/download/2.7.1/fish-2.7.1.tar.gz"
- mirror "https://fishshell.com/files/2.7.1/fish-2.7.1.tar.gz"
- sha256 "e42bb19c7586356905a58578190be792df960fa81de35effb1ca5a5a981f0c5a"
-
- bottle do
- sha256 "affac16a396410a500241266dbbbd8752562c9b800d9e4f2ef8de279c6fdb6aa" => :high_sierra
- sha256 "335538a7ea7f9613474f7321af0a1d519b61b0fc4be97a1744a7ea7bef7ff7e3" => :sierra
- sha256 "463cfa8edc0603761f25e0ba4e49524f69a1d856263d370d1de5fb8698dd5ccf" => :el_capitan
- end
-
- head do
- url "https://github.com/fish-shell/fish-shell.git", :shallow => false
-
- depends_on "autoconf" => :build
- depends_on "automake" => :build
- depends_on "doxygen" => :build
- end
-
- depends_on "pcre2"
-
- def install
- system "autoreconf", "--no-recursive" if build.head?
-
- # In Homebrew's 'superenv' sed's path will be incompatible, so
- # the correct path is passed into configure here.
- args = %W[
- --prefix=#{prefix}
- --with-extra-functionsdir=#{HOMEBREW_PREFIX}/share/fish/vendor_functions.d
- --with-extra-completionsdir=#{HOMEBREW_PREFIX}/share/fish/vendor_completions.d
- --with-extra-confdir=#{HOMEBREW_PREFIX}/share/fish/vendor_conf.d
- SED=/usr/bin/sed
- ]
- system "./configure", *args
- system "make", "install"
- end
-
- def caveats; <<~EOS
- You will need to add:
- #{HOMEBREW_PREFIX}/bin/fish
- to /etc/shells.
-
- Then run:
- chsh -s #{HOMEBREW_PREFIX}/bin/fish
- to make fish your default shell.
- EOS
- end
-
- def post_install
- (pkgshare/"vendor_functions.d").mkpath
- (pkgshare/"vendor_completions.d").mkpath
- (pkgshare/"vendor_conf.d").mkpath
- end
-
- test do
- system "#{bin}/fish", "-c", "echo"
- end
-end
diff --git a/test/completion.rb b/test/completion.rb
deleted file mode 100644
index 8ddf73d..0000000
--- a/test/completion.rb
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env ruby
-
-# Includes completion examples with the intent to cover
-# all sdk commands
-# Beware, pasta follows.
-
-test_cases = {
- # Basic commands (in the order of `sdk help`):
- "i" => ["i", "install"],
- "u" => ["u", "ug", "uninstall", "update", "upgrade", "use"],
- "r" => ["rm"],
- "l" => ["list", "ls"],
- "d" => ["d", "default"],
- "c" => ["c", "current"],
- "v" => ["v", "version"],
- "b" => ["b", "broadcast"],
- "h" => ["h", "help"],
- "o" => ["offline"],
- "s" => ["selfupdate"],
- "f" => ["flush"],
- # Currently uncovered; include to catch new upstream commands:
- "a" => [],
- "e" => [],
- "g" => [],
- "j" => [],
- "k" => [],
- "m" => [],
- "n" => [],
- "p" => [],
- "q" => [],
- "t" => [],
- "w" => [],
- "x" => [],
- "y" => [],
- "z" => [],
-
- # Second parameters complete correctly
- "install an" => ["ant"],
- "install xyz" => [],
- "install 1." => [],
-
- "uninstall " => ["ant"],
- "uninstall a" => ["ant"],
- "uninstall j" => [],
- "uninstall 1." => [],
-
- "list an" => ["ant"],
- "list xyz" => [],
- "list 1." => [],
-
- "use " => ["ant"],
- "use an" => ["ant"],
- "use j" => [],
- "use 1." => [],
-
- "default " => ["ant"],
- "default an" => ["ant"],
- "default j" => [],
- "default 1." => [],
-
- "current an" => ["ant"],
- "current xyz" => [],
- "current 1." => [],
-
- "upgrade " => ["ant"],
- "upgrade an" => ["ant"],
- "upgrade j" => [],
- "upgrade 1." => [],
-
- "version " => [],
- "version a" => [],
-
- "broadcast " => [],
- "broadcast a" => [],
-
- "help " => [],
- "help a" => [],
-
- "offline " => ["enable", "disable"],
- "offline a" => [],
-
- "selfupdate " => ["force"],
- "selfupdate a" => [],
-
- "update " => [],
- "update a" => [],
-
- "flush " => ["broadcast", "archives", "temp"],
- "flush x" => [],
-
- # Third parameters complete correctly
- #"install ant 1.10." => ["1.10.0", "1.10.1"], # TODO: issue #4
- "uninstall ant 1.10." => ["1.10.1"],
- "list ant " => [],
- "use ant " => ["1.9.9", "1.10.1"],
- "default ant " => ["1.9.9", "1.10.1"],
- "current ant " => [],
- "upgrade ant " => [],
- "offline ant " => [],
- "selfupdate ant " => [],
- "flush ant " => [],
-
- # Fourth parameters complete correctly
- "install ant 1.10.2-mine /tm" => ["/tmp/"],
- "uninstall ant 1.10.1 " => [],
- "use ant 1.10.1 " => [],
- "default ant 1.10.1 " => [],
-
- # Fifth parameters complete correctly
- "install ant 1.10.2-mine /tmp " => [],
-
- # Lists of all candidates work
- "install gr" => ["gradle", "grails", "groovy", "groovyserv"],
- "install grad" => ["gradle"],
- "install gradk" => [],
-
- # Lists of installed candidates work
- "uninstall an" => ["ant"],
- "uninstall gr" => [],
- "uninstall xyz" => [],
-
- # List of all versions work
- # TODO
-
- # List of installed versions work
- "uninstall ant 1" => ["1.9.9", "1.10.1"],
- "uninstall ant 2" => [],
- "uninstall vertx " => [],
- "uninstall an " => []
-}
-
-def fish_command(prompt)
- # Fish errors out if we don't set terminal dimensions
- "fish -c 'stty rows 80 columns 80; complete -C\"sdk #{prompt}\"'"
-end
-
-def extract(completion_output)
- completion_output.split("\n").map { |line|
- line.split(/\s+/)[0].strip
- }
-end
-
-puts "Testing sdk completions"
-failures = 0
-test_cases.each { |prompt, results|
- results.sort!
-
- print " Test: 'sdk #{prompt}'"
- completions = extract(`#{fish_command(prompt)}`).sort
- if completions != results
- puts " -- bad!"
- puts " - Expected: #{results}"
- puts " - Actual: #{completions}"
- failures += 1
- else
- puts " -- ok!"
- end
-}
-
-puts "Ran #{test_cases.size} checks each."
-puts "#{failures}/#{test_cases.size} checks failed."
-exit failures > 0 ? 1 : 0
\ No newline at end of file
diff --git a/test/features/completions.feature b/test/features/completions.feature
new file mode 100644
index 0000000..74ee349
--- /dev/null
+++ b/test/features/completions.feature
@@ -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 "" into the prompt
+ Then completion should propose ""
+ 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 " into the prompt
+ Then completion should propose ""
+ 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 " into the prompt
+ Then completion should propose ""
+ 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 " into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd | completions |
+ | an | ant |
+ | xyz | |
+ | 1. | |
+ | 'ant ' | |
+
+ Scenario Outline: Completion for 'use'
+ When the user enters "use " into the prompt
+ Then completion should propose ""
+ 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 " into the prompt
+ Then completion should propose ""
+ 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 " into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd | completions |
+ | an | ant | # --> installed version
+ | ja | java | # --> not installed
+ | xyz | |
+ | 1. | |
+ | 'ant ' | |
+
+ Scenario Outline: Completion for 'upgrade'
+ When the user enters "upgrade " into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd | completions |
+ | | ant, crash |
+ | an | ant |
+ | j | |
+ | 1. | |
+ | 'ant ' | |
+
+ Scenario Outline: Completion for 'offline'
+ When the user enters "offline " into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd | completions |
+ | | disable, enable |
+ | e | enable |
+ | d | disable |
+ | a | |
+ | 'enable ' | |
+
+ Scenario Outline: Completion for 'selfupdate'
+ When the user enters "selfupdate " into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd | completions |
+ | | force |
+ | f | force |
+ | a | |
+ | 'force ' | |
+
+ Scenario Outline: Completion for 'flush'
+ When the user enters "flush " into the prompt
+ Then completion should propose ""
+ 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 "" into the prompt
+ Then completion should propose ""
+ Examples:
+ | cmd |
+ | 'version ' |
+ | 'version a' |
+ | 'broadcast ' |
+ | 'broadcast a' |
+ | 'help ' |
+ | 'help a' |
+ | 'update ' |
+ | 'update a' |
diff --git a/test/features/step_definitions/completion.rb b/test/features/step_definitions/completion.rb
new file mode 100644
index 0000000..69f8cea
--- /dev/null
+++ b/test/features/step_definitions/completion.rb
@@ -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
diff --git a/test/features/step_definitions/setup.rb b/test/features/step_definitions/setup.rb
new file mode 100644
index 0000000..0609b47
--- /dev/null
+++ b/test/features/step_definitions/setup.rb
@@ -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
diff --git a/test/features/support/helpers.rb b/test/features/support/helpers.rb
new file mode 100644
index 0000000..f6096d8
--- /dev/null
+++ b/test/features/support/helpers.rb
@@ -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
diff --git a/test/prepare_tests.sh b/test/prepare_tests.sh
index 981d4e0..6305b42 100644
--- a/test/prepare_tests.sh
+++ b/test/prepare_tests.sh
@@ -3,8 +3,7 @@
source "${HOME}"/.sdkman/bin/sdkman-init.sh
# Set up an SDK with two installed versions
-# --> test of `sdk use` in wrapper.fish
-# --> tests in completion.rb
+# --> test of `sdk use` in wrapper.fish
sdk install ant 1.9.9
echo "y" | sdk install ant 1.10.1
-sdk default ant 1.10.1
\ No newline at end of file
+sdk default ant 1.10.1
From 479fa1e541f7549d45bfa21382c89235476cb189 Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 00:00:04 +0200
Subject: [PATCH 2/9] Account for fuzzy completions.
Introduced in Fish 3.1
cf. https://github.com/fish-shell/fish-shell/issues/5467
Needed to make tests less strict.
Instead of checking the exact list of matches,
we require the expected ones and exclude some others.
---
completions/sdk.fish | 6 +-
test/features/completions.feature | 223 ++++++++++---------
test/features/step_definitions/completion.rb | 19 +-
test/features/support/parameter_types.rb | 21 ++
4 files changed, 154 insertions(+), 115 deletions(-)
create mode 100644 test/features/support/parameter_types.rb
diff --git a/completions/sdk.fish b/completions/sdk.fish
index 17fcb7e..054c203 100644
--- a/completions/sdk.fish
+++ b/completions/sdk.fish
@@ -88,14 +88,14 @@ complete -c sdk -f -n '__fish_sdkman_no_command' \
-d 'Install new version'
complete -c sdk -f -n '__fish_sdkman_using_command i install' \
-a "(__fish_sdkman_candidates)"
+# TODO complete available versions --> issue #4
complete -c sdk -f -n '__fish_sdkman_specifying_candidate i install' \
- # TODO complete available versions --> #4
-a 'a.b.c' \
-d "version list unavailable"
complete -c sdk -f -n '__fish_sdkman_specifying_candidate i install' \
-a 'x.y.z' \
- -d "Add your own; specify path!"
- # Implicit: complete files as fourth parameter
+ -d "Specify path to install custom version."
+# Implicit: complete files as fourth parameter
complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 3 i install'
# block
diff --git a/test/features/completions.feature b/test/features/completions.feature
index 74ee349..d2a2710 100644
--- a/test/features/completions.feature
+++ b/test/features/completions.feature
@@ -14,166 +14,179 @@ Feature: Shell Completion
Scenario Outline: Commands complete
When the user enters "" into the prompt
Then completion should propose ""
+ But completion should not propose
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 | |
+ | cmd | completions | exclusions |
+ | b | b, broadcast | /^[^b]+$/ |
+ | c | c, current | /^[^c]+$/ |
+ | d | d, default | /^[^d]+$/ |
+ | f | flush | /^[^f]+$/ |
+ | h | h, help | /^[^h]+$/ |
+ | i | i, install | /^[^i]+$/ |
+ | in | install | |
+ | l | list, ls | /^[^l]+$/ |
+ | o | offline | /^[^o]+$/ |
+ | r | rm | /^[^r]+$/ |
+ | s | selfupdate | /^[^s]+$/ |
+ | u | u, ug, uninstall, update, upgrade, use | /^[^u]+$/ |
+ | un | uninstall | |
+ | up | update, upgrade | |
+ | us | use | |
+ | v | v, version | /^[^v]+$/ |
+ # Currently uncovered (except by fuzzy matches);
+ # include negatives to prevent accidents:
+ | a | | /^a/ |
+ | e | | /^e/ |
+ | g | | /^g/ |
+ | j | | /^j/ |
+ | k | | /^k/ |
+ | m | | /^m/ |
+ | n | | /^n/ |
+ | p | | /^p/ |
+ | q | | /^q/ |
+ | t | | /^t/ |
+ | w | | /^w/ |
+ | x | | /^x/ |
+ | y | | /^y/ |
+ | z | | /^z/ |
Scenario Outline: Completion for 'install'
When the user enters "install " into the prompt
Then completion should propose ""
+ But completion should not propose
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 ' | |
+ | cmd | completions | exclusions |
+ | an | ant | gradle |
+ | xyz | | /.*/ |
+ | 1. | | /.*/ |
+ | gra | gradle, grails | ant |
+ | grad | gradle | ant, grails |
+ | gradk | | /.*/ |
+# | ant 1.10. | 1.10.0, 1.10.1 | | # TODO: list installable versions --> issue #4
+ | ant 1.10.2-mine /tm | /tmp/ | /bin |
+ | 'ant 1.10.2-mine /tmp ' | | /.*/ |
+ # NB: Excluding wildcard pattern /.*/ expresses "do not offer any completions"
Scenario Outline: Completion for 'uninstall'
When the user enters "uninstall " into the prompt
Then completion should propose ""
+ But completion should not propose
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 ' | |
+ | cmd | completions | exclusions |
+ | | ant, crash | gradle |
+ | a | ant | gradle |
+ | j | | /.*/ |
+ | 1. | | /.*/ |
+ | an | ant | gradle, crash | # some installed
+ | gr | | /.*/ | # none installed
+ | xyz | | /.*/ | # no such candidate
+ | 'an ' | | /.*/ | # no such candidate installed
+ | 'ant 1' | 1.10.1, 1.9.9 | /^\w+$/ |
+ | 'ant 1.10.' | 1.10.1 | 1.9.9 |
+ | 'ant 2' | | /.*/ |
+ | 'ant 1.10.1 ' | | /.*/ | # only one version at a time
Scenario Outline: Completion for 'list'
When the user enters "list " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | an | ant |
- | xyz | |
- | 1. | |
- | 'ant ' | |
+ | cmd | completions | exclusions |
+ | an | ant | crash |
+ | xyz | | /.*/ |
+ | 1. | | /.*/ |
+ | 'ant ' | | /.*/ |
Scenario Outline: Completion for 'use'
When the user enters "use " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | ant, crash |
- | an | ant |
- | j | |
- | 1. | |
- | 'ant ' | 1.10.1, 1.9.9 |
- | 'ant 1.10.1 ' | |
+ | cmd | completions | exclusions |
+ | | ant, crash | gradle |
+ | an | ant | crash, gradle |
+ | j | | /.*/ |
+ | 1. | | /.*/ |
+ | 'ant ' | 1.10.1, 1.9.9 | /^\w+$/ |
+ | 'ant 1.10.1 ' | | /.*/ |
Scenario Outline: Completion for 'default'
When the user enters "default " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | ant, crash |
- | an | ant |
- | j | |
- | 1. | |
- | 'ant ' | 1.10.1, 1.9.9 |
- | 'ant 1.10.1 ' | |
+ | cmd | completions | exclusions |
+ | | ant, crash | gradle |
+ | an | ant | crash, gradle |
+ | j | | /.*/ |
+ | 1. | | /.*/ |
+ | 'ant ' | 1.10.1, 1.9.9 | /^\w+$/ |
+ | 'ant 1.10.1 ' | | /.*/ |
Scenario Outline: Completion for 'current'
When the user enters "current " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | an | ant | # --> installed version
- | ja | java | # --> not installed
- | xyz | |
- | 1. | |
- | 'ant ' | |
+ | cmd | completions | exclusions |
+ | an | ant | gradle | # --> installed version
+ | gr | gradle | ant | # --> not installed
+ | xyz | | /.*/ |
+ | 1. | | /.*/ |
+ | 'ant ' | | /.*/ |
Scenario Outline: Completion for 'upgrade'
When the user enters "upgrade " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | ant, crash |
- | an | ant |
- | j | |
- | 1. | |
- | 'ant ' | |
+ | cmd | completions | exclusions |
+ | | ant, crash | gradle |
+ | an | ant | crash, gradle |
+ | j | | /.*/ |
+ | 1. | | /.*/ |
+ | 'ant ' | | /^\w+$/ |
Scenario Outline: Completion for 'offline'
When the user enters "offline " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | disable, enable |
- | e | enable |
- | d | disable |
- | a | |
- | 'enable ' | |
+ | cmd | completions | exclusions |
+ | | disable, enable | /^(?!disable\|enable).*$/ | # NB: \| escaped to get it past Gherkin's parser
+ | en | enable | /^(?!enable).*$/ |
+ | di | disable | /^(?!disable).*$/ |
+ | an | | /.*/ |
+ | 'enable ' | | /.*/ |
Scenario Outline: Completion for 'selfupdate'
When the user enters "selfupdate " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | force |
- | f | force |
- | a | |
- | 'force ' | |
+ | cmd | completions | exclusions |
+ | | force | /^(?!force).*$/ |
+ | f | force | /^(?!force).*$/ |
+ | a | | /.*/ |
+ | 'force ' | | /.*/ |
Scenario Outline: Completion for 'flush'
When the user enters "flush " into the prompt
Then completion should propose ""
+ But completion should not propose
Examples:
- | cmd | completions |
- | | archives, broadcast, temp |
- | b | broadcast |
- | a | archives |
- | t | temp |
- | x | |
- | 'temp ' | |
+ | cmd | completions | exclusions |
+ | | archives, broadcast, temp | /^(?!archives\|broadcast\|temp).*$/ |
+ | b | broadcast | /^(?!broadcast).*$/ |
+ | a | archives | /^(?!archives\|broadcast).*$/ |
+ | t | temp | /^(?!temp\|broadcast).*$/ |
+ | x | | /.*/ |
+ | 'temp ' | | /.*/ |
Scenario Outline: Completion for commands without parameters
When the user enters "" into the prompt
- Then completion should propose ""
+ Then completion should not propose /.*/
Examples:
| cmd |
| 'version ' |
diff --git a/test/features/step_definitions/completion.rb b/test/features/step_definitions/completion.rb
index 69f8cea..d7651dd 100644
--- a/test/features/step_definitions/completion.rb
+++ b/test/features/step_definitions/completion.rb
@@ -7,12 +7,8 @@ module CompletionHelper
completions = run_fish_command("complete -C\"sdk #{cmd}\"")
completions.split("\n") \
- .map { |line| line.split(/\s+/)[0].strip } \
- .sort \
- .uniq \
- .join(', ')
+ .map { |line| line.split(/\s+/)[0].strip }
# TODO: Why do we get duplicates in the Docker container?
- # --> remove uniq
end
end
World CompletionHelper
@@ -21,6 +17,15 @@ 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)
+Then('completion should propose {string}') do |completions|
+ completions = completions.split(',').map(&:strip)
+ expect(@response).to include(*completions)
+end
+
+Then('completion should not propose {patterns}') do |exclusions_patterns|
+ exclusions_patterns.each do |p|
+ @response.each do |r|
+ expect(r).not_to match(p)
+ end
+ end
end
diff --git a/test/features/support/parameter_types.rb b/test/features/support/parameter_types.rb
new file mode 100644
index 0000000..a1f5f76
--- /dev/null
+++ b/test/features/support/parameter_types.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+ParameterType(
+ name: 'patterns',
+ regexp: %r{([^\s]*|'[^']*'|/[^/]*/)(,\s*([^\s]*|'[^']*'|/[^/]*/))*},
+ type: Array,
+ transformer: lambda do |*patterns|
+ patterns \
+ .map(&:strip) \
+ .map do |s|
+ s = if %r{^/(.*)/$} =~ s
+ Regexp.last_match(1)
+ elsif %r{^'(.*)'$} =~ s
+ "^#{Regexp.escape(Regexp.last_match(1))}$"
+ else
+ "^#{Regexp.escape(s)}$"
+ end
+ Regexp.compile(s)
+ end
+ end
+)
From 56bc601b174ad3c8a1b4fecf07db4375611a06e5 Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 02:49:06 +0200
Subject: [PATCH 3/9] Migrate wrapper test to Cucumber.
---
.travis.yml | 1 -
test/Dockerfile | 6 +-
test/features/step_definitions/completion.rb | 5 +-
test/features/step_definitions/wrapper.rb | 39 ++++++++++
test/features/support/helpers.rb | 75 ++++++++++++++++----
test/features/support/parameter_types.rb | 9 +++
test/features/wrapper.feature | 30 ++++++++
test/prepare_tests.sh | 9 ---
test/wrapper.fish | 64 -----------------
9 files changed, 144 insertions(+), 94 deletions(-)
create mode 100644 test/features/step_definitions/wrapper.rb
create mode 100644 test/features/wrapper.feature
delete mode 100644 test/prepare_tests.sh
delete mode 100644 test/wrapper.fish
diff --git a/.travis.yml b/.travis.yml
index 7a17061..dda17be 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,7 +38,6 @@ install:
script:
- (cd test && cucumber)
# TODO: Migrate these to Cucumber:
- - bash test/prepare_tests.sh && fish test/wrapper.fish
- fish test/reinitialize.fish
- fish -c "sdk install crash 1.3.0; and sdk uninstall crash 1.3.0" > /dev/null && fish test/check_for_path_zombies.fish
- bash test/remove_sdkman.sh > /dev/null && fish -c "echo 'y' | sdk" > /dev/null && fish -c "sdk version"
diff --git a/test/Dockerfile b/test/Dockerfile
index 09f8669..4956943 100644
--- a/test/Dockerfile
+++ b/test/Dockerfile
@@ -23,9 +23,9 @@ RUN curl -s "https://get.sdkman.io" | bash
# "Install" sdkman-for-fish
RUN mkdir -p $TEST_HOME/.config/fish/
-COPY completions $TEST_HOME/.config/fish/completions/
-COPY conf.d $TEST_HOME/.config/fish/conf.d/
-COPY completions $TEST_HOME/.config/fish/functions/
+COPY --chown=test:test completions $TEST_HOME/.config/fish/completions/
+COPY --chown=test:test conf.d $TEST_HOME/.config/fish/conf.d/
+COPY --chown=test:test functions $TEST_HOME/.config/fish/functions/
RUN ls -R $TEST_HOME/.config/fish/
# Run tests
diff --git a/test/features/step_definitions/completion.rb b/test/features/step_definitions/completion.rb
index d7651dd..474038b 100644
--- a/test/features/step_definitions/completion.rb
+++ b/test/features/step_definitions/completion.rb
@@ -4,10 +4,9 @@ require 'open3'
module CompletionHelper
def complete(cmd)
- completions = run_fish_command("complete -C\"sdk #{cmd}\"")
+ completions = run_fish_command("complete -C\"sdk #{cmd}\"")[:stdout]
- completions.split("\n") \
- .map { |line| line.split(/\s+/)[0].strip }
+ completions.map { |line| line.split(/\s+/)[0].strip }
# TODO: Why do we get duplicates in the Docker container?
end
end
diff --git a/test/features/step_definitions/wrapper.rb b/test/features/step_definitions/wrapper.rb
new file mode 100644
index 0000000..8869d50
--- /dev/null
+++ b/test/features/step_definitions/wrapper.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module WrapperHelper
+ def reject_then_select(lines, exclude, select)
+ lines.select do |e|
+ (exclude.nil? || e !~ exclude) && e =~ select
+ end.sort
+ end
+
+ def compare_env(exclude, include)
+ env_bash = reject_then_select(@response_bash[:env], exclude, include)
+ env_fish = reject_then_select(@response_fish[:env], exclude, include)
+ expect(env_fish).to eq(env_bash)
+ end
+end
+World WrapperHelper
+
+When('we run {string} in Bash and Fish') do |command|
+ @response_bash = run_bash_command(command)
+ @response_fish = run_fish_command(command)
+end
+
+Then('the exit code is the same') do
+ expect(@response_fish[:status]).to eq(@response_bash[:status])
+end
+
+Then('the output is the same') do
+ %i[stdout stderr].each do |out|
+ expect(@response_fish[out]).to eq(@response_bash[out])
+ end
+end
+
+Then('environment variable(s) {env_glob} is/are the same') do |pattern|
+ compare_env(nil, pattern)
+end
+
+Then('environment variable(s) {env_glob} is/are the same except for {env_glob}') do |pattern, exclude_pattern|
+ compare_env(exclude_pattern, pattern)
+end
diff --git a/test/features/support/helpers.rb b/test/features/support/helpers.rb
index f6096d8..ae57b3c 100644
--- a/test/features/support/helpers.rb
+++ b/test/features/support/helpers.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+require 'fileutils'
+require 'tmpdir'
+
def list_installed_candidates
candidates = {}
@@ -17,26 +20,70 @@ end
def installed?(candidate, version = nil)
candidates = list_installed_candidates
- candidates.key?(candidate) && (version.nil? || candidates[candidate].include?(version))
+ 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
+ Dir.mktmpdir(%w[sdkman-for-fish-test_ _fish]) do |tmp_dir|
+ files = %i[status stdout stderr env].map { |s|
+ [s, FileUtils.touch("#{tmp_dir}/#{s}")[0]]
+ }.to_h
- stdout
+ out, status = Open3.capture2e(<<~BASH
+ bash -c 'source "#{ENV['HOME']}/.sdkman/bin/sdkman-init.sh" && \
+ #{cmd} > #{files[:stdout]} 2> #{files[:stderr]}; \
+ echo "$?" > #{files[:status]}; \
+ env > #{files[:env]}; \
+ '
+ BASH
+ )
+
+ unless status.success?
+ warn(out)
+ raise "Bash command failed: #{out}"
+ end
+
+ {
+ status: File.read(files[:status]).to_i,
+ stdout: File.readlines(files[:stdout]),
+ stderr: File.readlines(files[:stderr]),
+ env: File.readlines(files[:env])
+ }
+ end
end
+# # For nicer diffs: one entry per line, sorted
+# string split ":" (cat path_bash) | sort > path_bash
+# string split ":" (cat path_fish) \
+# | string split " " \
+# | sort > path_fish
+# # split by spaces for fish 2.*
+
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
+ Dir.mktmpdir(%w[sdkman-for-fish-test_ _fish]) do |tmp_dir|
+ files = %i[status stdout stderr env].map { |s|
+ [s, FileUtils.touch("#{tmp_dir}/#{s}")[0]]
+ }.to_h
- stdout
+ out, status = Open3.capture2e(<<~FISH
+ fish -c '#{cmd} > #{files[:stdout]} ^ #{files[:stderr]}; \
+ echo $status > #{files[:status]}; \
+ env > #{files[:env]}; \
+ '
+ FISH
+ )
+
+ unless status.success?
+ warn(out)
+ raise "Fish command failed: #{out}"
+ end
+
+ {
+ status: File.read(files[:status]).to_i,
+ stdout: File.readlines(files[:stdout]),
+ stderr: File.readlines(files[:stderr]),
+ env: File.readlines(files[:env])
+ }
+ end
end
diff --git a/test/features/support/parameter_types.rb b/test/features/support/parameter_types.rb
index a1f5f76..27db9af 100644
--- a/test/features/support/parameter_types.rb
+++ b/test/features/support/parameter_types.rb
@@ -19,3 +19,12 @@ ParameterType(
end
end
)
+
+ParameterType(
+ name: 'env_glob',
+ regexp: /[A-Z_*]+/,
+ type: Regexp,
+ transformer: lambda do |glob|
+ /^#{glob.gsub('*', '[A-Z_]*')}=/
+ end
+)
diff --git a/test/features/wrapper.feature b/test/features/wrapper.feature
new file mode 100644
index 0000000..529c61f
--- /dev/null
+++ b/test/features/wrapper.feature
@@ -0,0 +1,30 @@
+Feature: Wrapping of Bash
+ All calls to sdk are performed through Bash;
+ we need to wrap those calls in such a way that
+ the effect sdk has on the Bash environment carries
+ over the current Fish session.
+
+ We verifiy equality of (standard) output, exit code, and environment variables.
+
+ 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
+
+ Scenario Outline:
+ When we run "" in Bash and Fish
+ Then the exit code is the same
+ And the output is the same
+ And environment variable PATH is the same
+ And environment variables *_HOME are the same
+ And environment variables SDKMAN_* are the same except for SDKMAN_OFFLINE_MODE
+ # NB: SDKMAN_OFFLINE_MODE is not an environment variable in bash, so ignore it here.
+ Examples:
+ | command |
+ | sdk |
+ | sdk version |
+ | sdk list java |
+ | sdk update |
+ | sdk use ant 1.9.9 |
+ | sdk offline enable > /dev/null; sdk install ant foo |
+ | sdk use ant 1.9.9 > /dev/null; sdk broadcast |
diff --git a/test/prepare_tests.sh b/test/prepare_tests.sh
deleted file mode 100644
index 6305b42..0000000
--- a/test/prepare_tests.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-source "${HOME}"/.sdkman/bin/sdkman-init.sh
-
-# Set up an SDK with two installed versions
-# --> test of `sdk use` in wrapper.fish
-sdk install ant 1.9.9
-echo "y" | sdk install ant 1.10.1
-sdk default ant 1.10.1
diff --git a/test/wrapper.fish b/test/wrapper.fish
deleted file mode 100644
index 3103723..0000000
--- a/test/wrapper.fish
+++ /dev/null
@@ -1,64 +0,0 @@
-# Test that a couple of commands have the same effect when run through
-# the fish wrapper and directly.
-# Verifies equality of (standard) output, exit code, and PATH.
-
-set test_commands \
- "sdk" \
- "sdk version" \
- "sdk list java" \
- "sdk update" \
- "sdk use ant 1.9.9" \
- "sdk offline enable > /dev/null; sdk install ant foo" \
- "sdk use ant 1.9.9 > /dev/null; sdk broadcast"
-set test_count (count $test_commands)
-set check_count (math "3 * $test_count")
-
-set sdk_init "$HOME/.sdkman/bin/sdkman-init.sh"
-
-if [ (uname) = "Linux" ]
- function checksum -a file
- sha256sum $file | cut -d " " -f 1
- end
-else # assume macOS
- function checksum -a file
- shasum -a 256 $file | cut -d " " -f 1
- end
-end
-
-echo "Testing the sdk wrapper"
-set failures 0
-for sdk_cmd in $test_commands
- echo " Testing '$sdk_cmd'"
- bash -c "source \"$sdk_init\" && $sdk_cmd > sout_bash;
- echo \"\$?\" > status_bash;
- echo \"\$PATH\" > path_bash;
- echo \"\$ANT_HOME\" > anthome_bash"
- fish -c "$sdk_cmd > sout_fish;
- echo \"\$status\" > status_fish;
- echo \"\$PATH\" > path_fish;
- echo \"\$ANT_HOME\" > anthome_fish"
-
- # For nicer diffs: one entry per line, sorted
- string split ":" (cat path_bash) | sort > path_bash
- string split ":" (cat path_fish) \
- | string split " " \
- | sort > path_fish
- # split by spaces for fish 2.*
-
- for out in sout status path anthome
- if [ (checksum "$out"_bash) != (checksum "$out"_fish) ]
- echo " - $out bad:"
- diff "$out"_bash "$out"_fish | sed -e 's/^/ /'
- set failures (math $failures + 1)
- else
- echo " - $out ok!"
- end
- end
- echo ""
-end
-
-rm {sout,status,path}_{bash,fish}
-
-echo "Ran $test_count commands with 3 checks each."
-echo "$failures/$check_count checks failed."
-exit $failures
From 0a948c81c1ac35adad5621b1ccc1dedea7500bfe Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 04:22:01 +0200
Subject: [PATCH 4/9] Migrate reinitialization test to Cucumber.
---
.travis.yml | 1 -
test/features/corner_cases.feature | 13 ++++++
.../features/step_definitions/corner_cases.rb | 45 +++++++++++++++++++
test/features/support/helpers.rb | 4 +-
test/features/support/parameter_types.rb | 7 +++
test/reinitialize.fish | 27 -----------
6 files changed, 67 insertions(+), 30 deletions(-)
create mode 100644 test/features/corner_cases.feature
create mode 100644 test/features/step_definitions/corner_cases.rb
delete mode 100755 test/reinitialize.fish
diff --git a/.travis.yml b/.travis.yml
index dda17be..8f9305c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,6 +38,5 @@ install:
script:
- (cd test && cucumber)
# TODO: Migrate these to Cucumber:
- - fish test/reinitialize.fish
- fish -c "sdk install crash 1.3.0; and sdk uninstall crash 1.3.0" > /dev/null && fish test/check_for_path_zombies.fish
- bash test/remove_sdkman.sh > /dev/null && fish -c "echo 'y' | sdk" > /dev/null && fish -c "sdk version"
diff --git a/test/features/corner_cases.feature b/test/features/corner_cases.feature
new file mode 100644
index 0000000..4327d06
--- /dev/null
+++ b/test/features/corner_cases.feature
@@ -0,0 +1,13 @@
+Feature: Corner Cases
+
+ Scenario: SDKMAN_DIR unset
+ Given environment variable SDKMAN_DIR is not set
+ When a new Fish shell is launched
+ Then environment variable SDKMAN_DIR has the original value
+
+ Scenario: SDKMAN_DIR set to a location the current user can't write at
+ Given environment variable SDKMAN_DIR is set to "/"
+ When a new Fish shell is launched
+ Then environment variable SDKMAN_DIR has the original value
+
+ # TODO: add test that fails if `test` in conf.d/sdk.fish:80 errors (cf issue #28 et al.)
diff --git a/test/features/step_definitions/corner_cases.rb b/test/features/step_definitions/corner_cases.rb
new file mode 100644
index 0000000..8152faa
--- /dev/null
+++ b/test/features/step_definitions/corner_cases.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+Given('environment variable {env_name} is not set') do |name|
+ @name = name
+ @expect_intermediate_value = false
+ @command = <<~BASH
+ ( \\
+ env | grep -E "^#{name}="; \\
+ export -n #{name}; \\
+ env | grep -E "^#{name}="; \\
+ BASH
+end
+
+Given('environment variable {env_name} is set to {string}') do |name, new_value|
+ @name = name
+ @expect_intermediate_value = true
+ @command = <<~BASH
+ ( \\
+ env | grep -E "^#{name}="; \\
+ export #{name}=#{new_value}; \\
+ env | grep -E "^#{name}="; \\
+ BASH
+end
+
+When('a new Fish shell is launched') do
+ @command += <<~BASH
+ fish -lc "env | grep -E \\"^#{@name}=\\"" \\
+ ) \\
+ BASH
+
+ @response = run_bash_command(@command)
+end
+
+Then('environment variable {env_name} has the original value') do |name|
+ expect(name).to eq(@name) # otherwise the test doesn't make sense
+
+ if @expect_intermediate_value
+ expect(@response[:stdout].count).to eq(3)
+ expect(@response[:stdout][0]).to_not eq(@response[:stdout][1]) # destruction effective
+ else
+ expect(@response[:stdout].count).to eq(2)
+ end
+
+ expect(@response[:stdout][-1]).to eq(@response[:stdout][0]) # reinitialization effective
+end
diff --git a/test/features/support/helpers.rb b/test/features/support/helpers.rb
index ae57b3c..ba1ce4e 100644
--- a/test/features/support/helpers.rb
+++ b/test/features/support/helpers.rb
@@ -48,7 +48,7 @@ def run_bash_command(cmd)
status: File.read(files[:status]).to_i,
stdout: File.readlines(files[:stdout]),
stderr: File.readlines(files[:stderr]),
- env: File.readlines(files[:env])
+ env: File.readlines(files[:env]).map { |l| l.strip.split('=', 2) }.to_h
}
end
end
@@ -83,7 +83,7 @@ def run_fish_command(cmd)
status: File.read(files[:status]).to_i,
stdout: File.readlines(files[:stdout]),
stderr: File.readlines(files[:stderr]),
- env: File.readlines(files[:env])
+ env: File.readlines(files[:env]).map { |l| l.strip.split('=', 2) }.to_h
}
end
end
diff --git a/test/features/support/parameter_types.rb b/test/features/support/parameter_types.rb
index 27db9af..492bdde 100644
--- a/test/features/support/parameter_types.rb
+++ b/test/features/support/parameter_types.rb
@@ -20,6 +20,13 @@ ParameterType(
end
)
+ParameterType(
+ name: 'env_name',
+ regexp: /[A-Z_]+/,
+ type: String,
+ transformer: ->(s) { s }
+)
+
ParameterType(
name: 'env_glob',
regexp: /[A-Z_*]+/,
diff --git a/test/reinitialize.fish b/test/reinitialize.fish
deleted file mode 100755
index 564e74b..0000000
--- a/test/reinitialize.fish
+++ /dev/null
@@ -1,27 +0,0 @@
-# If either of
-# - $SDKMAN_DIR is unset
-# - $SDKMAN_DIR points to a directory not owned by the current user
-# is true, sdkman-for-fish should run sdkman's init script.
-
-# Assumes sdkman-for-fish is installed
-set proper_value "$SDKMAN_DIR"
-
-begin
- set -e SDKMAN_DIR
- set in_new_shell (fish -lc 'echo $SDKMAN_DIR')
- if [ "$in_new_shell" != "$proper_value" ]
- echo "SDKMAN_DIR initialized to $in_new_shell instead of $proper_value"
- exit 1
- end
-end
-
-begin
- set -x SDKMAN_DIR "/" # belongs to root, who hopefully doesn't run this
- set in_new_shell (fish -lc 'echo $SDKMAN_DIR')
- if [ "$in_new_shell" != "$proper_value" ]
- echo "SDKMAN_DIR reinitialized to $in_new_shell instead of $proper_value"
- exit 1
- end
-end
-
-# TODO: add test that fails if `test` in conf.d/sdk.fish:80 errors (cf issue #28 et al.)
From 42aff3b4c5ff348c7400866cc94010f9d19ff72b Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 04:48:12 +0200
Subject: [PATCH 5/9] Migrate PATH zombie test to Cucumber.
---
.travis.yml | 1 -
test/check_for_path_zombies.fish | 9 --------
test/features/corner_cases.feature | 5 +++++
.../features/step_definitions/corner_cases.rb | 5 +++++
test/features/step_definitions/setup.rb | 22 ++++++++++++++-----
5 files changed, 27 insertions(+), 15 deletions(-)
delete mode 100644 test/check_for_path_zombies.fish
diff --git a/.travis.yml b/.travis.yml
index 8f9305c..cec1ac2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,5 +38,4 @@ install:
script:
- (cd test && cucumber)
# TODO: Migrate these to Cucumber:
- - fish -c "sdk install crash 1.3.0; and sdk uninstall crash 1.3.0" > /dev/null && fish test/check_for_path_zombies.fish
- bash test/remove_sdkman.sh > /dev/null && fish -c "echo 'y' | sdk" > /dev/null && fish -c "sdk version"
diff --git a/test/check_for_path_zombies.fish b/test/check_for_path_zombies.fish
deleted file mode 100644
index ff928a6..0000000
--- a/test/check_for_path_zombies.fish
+++ /dev/null
@@ -1,9 +0,0 @@
-switch "$PATH"
-case "*sdkman/candidates/crash/*"
- echo "Uninstalled candidate in PATH"
- sdk list crash | head -10
- echo $PATH
- exit 1
-case "*"
- echo "OKAY"
-end
diff --git a/test/features/corner_cases.feature b/test/features/corner_cases.feature
index 4327d06..8a8a443 100644
--- a/test/features/corner_cases.feature
+++ b/test/features/corner_cases.feature
@@ -11,3 +11,8 @@ Feature: Corner Cases
Then environment variable SDKMAN_DIR has the original value
# TODO: add test that fails if `test` in conf.d/sdk.fish:80 errors (cf issue #28 et al.)
+
+ Scenario: PATH should contain only valid paths
+ Given candidate crash is installed
+ When candidate crash is uninstalled
+ Then environment variable PATH cannot contain "sdkman/candidates/crash/"
diff --git a/test/features/step_definitions/corner_cases.rb b/test/features/step_definitions/corner_cases.rb
index 8152faa..198cae4 100644
--- a/test/features/step_definitions/corner_cases.rb
+++ b/test/features/step_definitions/corner_cases.rb
@@ -43,3 +43,8 @@ Then('environment variable {env_name} has the original value') do |name|
expect(@response[:stdout][-1]).to eq(@response[:stdout][0]) # reinitialization effective
end
+
+Then('environment variable {env_name} cannot contain {string}') do |name, value|
+ env = run_fish_command('echo noop')[:env]
+ expect(env[name]).to_not match(/#{Regexp.escape(value)}/)
+end
diff --git a/test/features/step_definitions/setup.rb b/test/features/step_definitions/setup.rb
index 0609b47..82b6766 100644
--- a/test/features/step_definitions/setup.rb
+++ b/test/features/step_definitions/setup.rb
@@ -14,6 +14,22 @@ Given(/^candidate (\w+) is installed$/) do |candidate|
run_bash_command("sdk install #{candidate}") unless installed?(candidate)
end
+def _uninstall_candidate_version(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
+
+When(/^candidate (\w+) is uninstalled$/) do |candidate|
+ puts `ls ~/.sdkman/candidates/#{candidate}`
+ Dir["#{ENV['HOME']}/.sdkman/candidates/#{candidate}/*"].each do |candidate_dir|
+ _uninstall_candidate_version(candidate_dir)
+ end
+ puts `ls ~/.sdkman/candidates/#{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:
@@ -22,10 +38,6 @@ end
# --> 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
+ _uninstall_candidate_version(candidate_dir)
end
end
From 7e97c4c1c19b30dbf6a85baa659c7cd538e5a10a Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 05:07:24 +0200
Subject: [PATCH 6/9] Migrate installer test to Cucumber.
---
.travis.yml | 2 --
test/features/installer.feature | 11 ++++++++++
test/features/step_definitions/installer.rb | 23 +++++++++++++++++++++
test/remove_sdkman.sh | 5 -----
4 files changed, 34 insertions(+), 7 deletions(-)
create mode 100644 test/features/installer.feature
create mode 100644 test/features/step_definitions/installer.rb
delete mode 100644 test/remove_sdkman.sh
diff --git a/.travis.yml b/.travis.yml
index cec1ac2..27836d2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,5 +37,3 @@ install:
script:
- (cd test && cucumber)
- # TODO: Migrate these to Cucumber:
- - bash test/remove_sdkman.sh > /dev/null && fish -c "echo 'y' | sdk" > /dev/null && fish -c "sdk version"
diff --git a/test/features/installer.feature b/test/features/installer.feature
new file mode 100644
index 0000000..aacdefa
--- /dev/null
+++ b/test/features/installer.feature
@@ -0,0 +1,11 @@
+Feature: Install SDKMAN! if necessary
+
+ Scenario:
+ Given SDKMAN! is not installed
+ When sdk is called and user answers "n"
+ Then SDKMAN! is absent
+
+ Scenario:
+ Given SDKMAN! is not installed
+ When sdk is called and user answers "y"
+ Then SDKMAN! is present
diff --git a/test/features/step_definitions/installer.rb b/test/features/step_definitions/installer.rb
new file mode 100644
index 0000000..2ed427e
--- /dev/null
+++ b/test/features/step_definitions/installer.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'fileutils'
+
+Given(/^SDKMAN! is not installed$/) do
+ FileUtils.rm_rf("#{ENV['HOME']}/.sdkman")
+end
+
+When('sdk is called and user answers {string}') do |answer|
+ run_fish_command("echo '#{answer}' | sdk version")
+end
+
+Then(/^SDKMAN! is absent$/) do
+ expect(Dir["#{ENV['HOME']}/.sdkman/*"].count).to eq(0)
+ response = run_bash_command("sdk version")
+ expect(response[:status]).to_not eq(0)
+end
+
+Then('SDKMAN! is present') do
+ expect(Dir["#{ENV['HOME']}/.sdkman/*"].count).to be > 1
+ response = run_bash_command("sdk version")
+ expect(response[:status]).to eq(0)
+end
diff --git a/test/remove_sdkman.sh b/test/remove_sdkman.sh
deleted file mode 100644
index f8674cb..0000000
--- a/test/remove_sdkman.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
- rm -rf "${HOME}/.sdkman" \
-&& sed -i'.bak' -E -e 's/^.*(sdkman|SDKMAN).*$//g' "${HOME}/.bashrc" \
-&& echo 'SDKMAN! uninstalled'
From efd9cf0c0b746ee068ba5e0cdeab0c233fc07249 Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 05:35:28 +0200
Subject: [PATCH 7/9] Polish Travis build.
---
.travis.yml | 18 ++++++++++++------
test/features/support/helpers.rb | 1 +
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 27836d2..d17c78f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,19 +21,25 @@ matrix:
addons:
homebrew:
packages:
- - fish # --> latest, i.e. >=3.0.2
+ - fish # --> latest, i.e. >=3.1.2
update: true # TODO: build should be green without, but isn't
before_install:
- curl -s "https://get.sdkman.io" | bash
- bundle install --gemfile=test/Gemfile --no-cache
- - uname -a; fish --version; sdk version; ruby --version; cucumber --version
+ - |-
+ uname -a;
+ fish --version;
+ { source ~/.bash_profile || source ~/.bashrc; } && sdk version;
+ ruby --version;
+ echo "cucumber $(cucumber --version)";
install:
- - mkdir -p "${HOME}"/.config/fish/{completions,conf.d,functions}
- - cp completions/* "${HOME}"/.config/fish/completions/
- - cp conf.d/* "${HOME}"/.config/fish/conf.d/
- - cp functions/* "${HOME}"/.config/fish/functions/
+ - |-
+ mkdir -p "${HOME}"/.config/fish/{completions,conf.d,functions}
+ cp completions/* "${HOME}"/.config/fish/completions/
+ cp conf.d/* "${HOME}"/.config/fish/conf.d/
+ cp functions/* "${HOME}"/.config/fish/functions/
script:
- (cd test && cucumber)
diff --git a/test/features/support/helpers.rb b/test/features/support/helpers.rb
index ba1ce4e..99cad9e 100644
--- a/test/features/support/helpers.rb
+++ b/test/features/support/helpers.rb
@@ -44,6 +44,7 @@ def run_bash_command(cmd)
raise "Bash command failed: #{out}"
end
+ puts File.readlines(files[:env]) # TODO remove
{
status: File.read(files[:status]).to_i,
stdout: File.readlines(files[:stdout]),
From 2afb22f6afe64bdffc15a0396cf62990f09bb01e Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 06:01:37 +0200
Subject: [PATCH 8/9] Fix tests on macOS. Also clarifies a test description.
---
test/features/corner_cases.feature | 4 ++--
test/features/support/helpers.rb | 28 ++++++++++++++--------------
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/test/features/corner_cases.feature b/test/features/corner_cases.feature
index 8a8a443..a2c211f 100644
--- a/test/features/corner_cases.feature
+++ b/test/features/corner_cases.feature
@@ -1,11 +1,11 @@
Feature: Corner Cases
- Scenario: SDKMAN_DIR unset
+ Scenario: sdk not initialized in this shell
Given environment variable SDKMAN_DIR is not set
When a new Fish shell is launched
Then environment variable SDKMAN_DIR has the original value
- Scenario: SDKMAN_DIR set to a location the current user can't write at
+ Scenario: sdk initialized for another user in this shell
Given environment variable SDKMAN_DIR is set to "/"
When a new Fish shell is launched
Then environment variable SDKMAN_DIR has the original value
diff --git a/test/features/support/helpers.rb b/test/features/support/helpers.rb
index 99cad9e..4ea155c 100644
--- a/test/features/support/helpers.rb
+++ b/test/features/support/helpers.rb
@@ -26,9 +26,9 @@ end
def run_bash_command(cmd)
Dir.mktmpdir(%w[sdkman-for-fish-test_ _fish]) do |tmp_dir|
- files = %i[status stdout stderr env].map { |s|
+ files = %i[status stdout stderr env].map do |s|
[s, FileUtils.touch("#{tmp_dir}/#{s}")[0]]
- }.to_h
+ end.to_h
out, status = Open3.capture2e(<<~BASH
bash -c 'source "#{ENV['HOME']}/.sdkman/bin/sdkman-init.sh" && \
@@ -44,28 +44,24 @@ def run_bash_command(cmd)
raise "Bash command failed: #{out}"
end
- puts File.readlines(files[:env]) # TODO remove
{
status: File.read(files[:status]).to_i,
stdout: File.readlines(files[:stdout]),
stderr: File.readlines(files[:stderr]),
- env: File.readlines(files[:env]).map { |l| l.strip.split('=', 2) }.to_h
+ env: File.readlines(files[:env]).map do |l|
+ l.strip.split('=', 2) \
+ if l.include?('=') # NB: on macOS, weird stuff is printed by env
+ end.compact \
+ .to_h
}
end
end
-# # For nicer diffs: one entry per line, sorted
-# string split ":" (cat path_bash) | sort > path_bash
-# string split ":" (cat path_fish) \
-# | string split " " \
-# | sort > path_fish
-# # split by spaces for fish 2.*
-
def run_fish_command(cmd)
Dir.mktmpdir(%w[sdkman-for-fish-test_ _fish]) do |tmp_dir|
- files = %i[status stdout stderr env].map { |s|
+ files = %i[status stdout stderr env].map do |s|
[s, FileUtils.touch("#{tmp_dir}/#{s}")[0]]
- }.to_h
+ end.to_h
out, status = Open3.capture2e(<<~FISH
fish -c '#{cmd} > #{files[:stdout]} ^ #{files[:stderr]}; \
@@ -84,7 +80,11 @@ def run_fish_command(cmd)
status: File.read(files[:status]).to_i,
stdout: File.readlines(files[:stdout]),
stderr: File.readlines(files[:stderr]),
- env: File.readlines(files[:env]).map { |l| l.strip.split('=', 2) }.to_h
+ env: File.readlines(files[:env]).map do |l|
+ l.strip.split('=', 2) \
+ if l.include?('=') # NB: on macOS, weird stuff is printed by env
+ end.compact \
+ .to_h
}
end
end
From 15997dcba8e0aa413836e912180ea8c2efe33e88 Mon Sep 17 00:00:00 2001
From: Raphael Reitzig <4246780+reitzig@users.noreply.github.com>
Date: Tue, 26 May 2020 16:35:31 +0200
Subject: [PATCH 9/9] Allow to pass parameters to Cucumber in Docker.
Also add some comments.
---
README.md | 27 ++++++++++++++++++++-----
test/Dockerfile | 10 ++++++++-
test/features/step_definitions/setup.rb | 9 +++++++++
3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 56b3490..39fe94e 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,13 @@
[![Build Status][travis-badge]][travis-link]
-Makes command `sdk` from [SDKMAN!] usable from fish, including auto-completion.
+Makes command `sdk` from [SDKMAN!] usable from [fish], including auto-completion.
Also adds binaries from installed SDKs to the PATH.
-Version 1.4.0 tested with
+Version 1.5.0 tested with
- - fish 2.7.1 and 3.0.2, and
- - SDKMAN! 5.7.4, on
+ - fish 2.7.1 and 3.1.2, and
+ - SDKMAN! 5.8.2, on
- Ubuntu 18.04 LTS and macOS 10.13
## Install
@@ -38,13 +38,29 @@ As the tests may mess up your own setup
-- you have been warned! --
the recommended way is to run the tests in a Docker container:
-```bash
+```fish
docker build -t sdkman-for-fish-tests -f test/Dockerfile .
docker run --rm sdkman-for-fish-tests
```
A run configuration for Jetbrains IDEs is included.
+It is a also possible to run individual features, for instance:
+
+```fish
+docker run --rm sdkman-for-fish-tests features/completions.feature
+```
+
+As a corollary, this is the fastest way to run all tests
+(if you do not care about the report):
+
+```fish
+for f in features/*.feature
+ docker run --rm sdkman-for-fish-tests "$f" &
+done
+wait
+```
+
## Acknowledgements
* Completion originally by [Ted Wise](https://github.com/ctwise); see his
@@ -53,6 +69,7 @@ A run configuration for Jetbrains IDEs is included.
see [his comment on sdkman/sdkman-cli#294](https://github.com/sdkman/sdkman-cli/issues/294#issuecomment-318252058).
[SDKMAN!]: https://github.com/sdkman/sdkman-cli
+[fish]: https://fishshell.com/
[fisher]: https://github.com/jorgebucaran/fisher
[travis-link]: https://travis-ci.org/reitzig/sdkman-for-fish
[travis-badge]: https://travis-ci.org/reitzig/sdkman-for-fish.svg?branch=master
diff --git a/test/Dockerfile b/test/Dockerfile
index 4956943..4044d2b 100644
--- a/test/Dockerfile
+++ b/test/Dockerfile
@@ -21,6 +21,13 @@ RUN groupadd -r test \
USER test
RUN curl -s "https://get.sdkman.io" | bash
+# To speed up tests, uncomment this shared setup:
+#SHELL ["/bin/bash", "-c"]
+#RUN source "$TEST_HOME/.sdkman/bin/sdkman-init.sh" \
+# && sdk install ant 1.9.9 \
+# && sdk install ant 1.10.1 \
+# && sdk install crash
+
# "Install" sdkman-for-fish
RUN mkdir -p $TEST_HOME/.config/fish/
COPY --chown=test:test completions $TEST_HOME/.config/fish/completions/
@@ -30,4 +37,5 @@ RUN ls -R $TEST_HOME/.config/fish/
# Run tests
COPY test ./
-CMD cucumber
+ENTRYPOINT ["cucumber"]
+CMD []
diff --git a/test/features/step_definitions/setup.rb b/test/features/step_definitions/setup.rb
index 82b6766..69fdd04 100644
--- a/test/features/step_definitions/setup.rb
+++ b/test/features/step_definitions/setup.rb
@@ -7,6 +7,15 @@ Given(/^SDKMAN! candidate list is up to date$/) do
end
Given(/^candidate (\w+) is installed at version (\d+(?:\.\d+)*)$/) do |candidate, version|
+ # TODO: Can we mock-install instead?
+ # Something like
+ #
+ # mkdir -p ${SDKMAN_CANDIDATES_DIR}/${candidate}/{version}/bin \
+ # && touch ${SDKMAN_CANDIDATES_DIR}/${candidate}/${version}/bin/${candidate} &&
+ # ln -s ${SDKMAN_CANDIDATES_DIR}/${candidate}/current ${SDKMAN_CANDIDATES_DIR}/${candidate}/${version}
+ #
+ # should be quite enough to trick sdk as far as we need it to trick.
+ # Or is it?
run_bash_command("sdk install #{candidate} #{version}") unless installed?(candidate, version)
end