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