From d6f9dfa2f9ab86c82b5200ce57ea550259aa7e0b Mon Sep 17 00:00:00 2001 From: Faisal N Jawdat Date: Sun, 24 May 2026 16:02:25 +0100 Subject: [PATCH] Replace Aruba with direct API calls Aruba is a recurring source of dependency conflicts when updating Rubycritic dependencies*. Update Aruba call sites to call the underlying command line calls directly. Call with Open3 so as to capture results and return status. * Most recently, being able to update to diff-lcs 2.0, which we do in this commit. We ran into it more before when Rubycritic relied on Cucumber, though it doesn't any more. --- CHANGELOG.md | 1 + rubycritic.gemspec | 3 +- test/integration/integration_test_helper.rb | 51 ++++++++++++++++----- test/integration/minimum_score_spec.rb | 28 +++++------ test/integration/options_spec.rb | 24 ++++------ test/integration/rake_task_spec.rb | 32 ++++++------- 6 files changed, 77 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d9d05a3..484719bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * [CHORE] ... * [FEATURE] ... +* [CHANGE] Replace Aruba with direct API calls in specs (by [@faisal][]) * [CHANGE] Replace all Cucumber features with Minitest/Spec specs (by [@faisal][]) # v5.0.0 / 2026-01-26 [(commits)](https://github.com/whitesmith/rubycritic/compare/v4.12.0...v5.0.0) diff --git a/rubycritic.gemspec b/rubycritic.gemspec index 88051dca..5763f156 100644 --- a/rubycritic.gemspec +++ b/rubycritic.gemspec @@ -45,7 +45,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'tty-which', '~> 0.5.0' spec.add_dependency 'virtus', '~> 2.0' - spec.add_development_dependency 'aruba', '~> 2.3.1', '>= 2.3.1' spec.add_development_dependency 'bundler', '>= 2.0.0' if RUBY_PLATFORM == 'java' spec.add_development_dependency 'jar-dependencies', '~> 0.5.5' @@ -53,7 +52,7 @@ Gem::Specification.new do |spec| else spec.add_development_dependency 'byebug', '~> 13.0', '>= 10.0' end - spec.add_development_dependency 'diff-lcs', '~> 1.3' + spec.add_development_dependency 'diff-lcs', '~> 2.0' spec.add_development_dependency 'fakefs', '~> 3.2.0' spec.add_development_dependency 'mdl', '~> 0.15.0', '>= 0.12.0' spec.add_development_dependency 'minitest', '~> 6.0.0' diff --git a/test/integration/integration_test_helper.rb b/test/integration/integration_test_helper.rb index 6c356880..62c6fb35 100644 --- a/test/integration/integration_test_helper.rb +++ b/test/integration/integration_test_helper.rb @@ -1,21 +1,41 @@ # frozen_string_literal: true require_relative '../test_helper' -require 'aruba/api' +require 'open3' +require 'timeout' +require 'tmpdir' +require 'fileutils' require_relative '../../lib/rubycritic' require_relative '../../lib/rubycritic/cli/application' require_relative '../../lib/rubycritic/commands/status_reporter' -Aruba.configure { |config| config.exit_timeout = 30 } - module IntegrationTestHelper - include Aruba::Api + GEM_ROOT = File.expand_path('../..', __dir__) + COMMAND_TIMEOUT = 30 + + CommandResult = Struct.new(:stdout, :stderr, :exit_status) + + def before_setup + super + @sandbox_dir = Dir.mktmpdir('rubycritic-spec-') + @original_pwd = Dir.pwd + Dir.chdir(@sandbox_dir) + end + + def after_teardown + Dir.chdir(@original_pwd) if @original_pwd + FileUtils.remove_entry(@sandbox_dir) if @sandbox_dir && File.directory?(@sandbox_dir) + @sandbox_dir = nil + @original_pwd = nil + super + end + + def write_file(name, contents) + File.write(File.join(Dir.pwd, name), contents) + end def rubycritic(args) - run_command_and_stop( - "rubycritic #{args} --no-browser", - fail_on_error: false - ) + run_command("rubycritic #{args} --no-browser") end def rake(name, task_def) @@ -25,10 +45,7 @@ def rake(name, task_def) RUBY write_file 'Rakefile', header + task_def - run_command_and_stop( - "rake #{name}", - fail_on_error: false - ) + run_command("rake #{name}") end def create_smelly_file @@ -61,4 +78,14 @@ def foo; end def create_empty_file write_file('empty.rb', '') end + + private + + def run_command(command) + env = { 'PATH' => "#{File.join(GEM_ROOT, 'bin')}#{File::PATH_SEPARATOR}#{ENV.fetch('PATH', '')}" } + stdout, stderr, status = Timeout.timeout(COMMAND_TIMEOUT) do + Open3.capture3(env, command) + end + CommandResult.new(stdout, stderr, status.exitstatus) + end end diff --git a/test/integration/minimum_score_spec.rb b/test/integration/minimum_score_spec.rb index 48b79c0e..7e8e7c9d 100644 --- a/test/integration/minimum_score_spec.rb +++ b/test/integration/minimum_score_spec.rb @@ -5,61 +5,57 @@ describe 'Minimum score' do include IntegrationTestHelper - before do - setup_aruba - end - describe 'Status indicates a success when not using --minimum-score' do it 'succeeds without minimum score' do create_smelly_file - rubycritic('smelly.rb') + result = rubycritic('smelly.rb') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS end end describe 'Status indicates an error when score below the minimum' do it 'fails when score below minimum' do create_smelly_file - rubycritic('--minimum-score 100 smelly.rb') + result = rubycritic('--minimum-score 100 smelly.rb') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM end end describe 'Status indicates a success when score is above the minimum' do it 'succeeds when score above minimum' do create_smelly_file - rubycritic('--minimum-score 93 smelly.rb') + result = rubycritic('--minimum-score 93 smelly.rb') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS end end describe 'Status indicates a success when score is equal the minimum' do it 'succeeds when score equals minimum' do create_clean_file - rubycritic('--minimum-score 100 clean.rb') + result = rubycritic('--minimum-score 100 clean.rb') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS end end describe 'Prints the score on output' do it 'prints score' do create_smelly_file - rubycritic('smelly.rb') + result = rubycritic('smelly.rb') - _(last_command_started.stdout).must_include 'Score: 93.19' + _(result.stdout).must_include 'Score: 93.19' end end describe 'Prints a message informing the score is below the minimum' do it 'prints below minimum message' do create_empty_file - rubycritic('--minimum-score 101 empty.rb') + result = rubycritic('--minimum-score 101 empty.rb') - _(last_command_started.stdout).must_include 'Score (100.0) is below the minimum 101.0' + _(result.stdout).must_include 'Score (100.0) is below the minimum 101.0' end end end diff --git a/test/integration/options_spec.rb b/test/integration/options_spec.rb index 9f5bb09a..5db4bcea 100644 --- a/test/integration/options_spec.rb +++ b/test/integration/options_spec.rb @@ -5,34 +5,30 @@ describe 'Command line options' do include IntegrationTestHelper - before do - setup_aruba - end - describe 'return non-zero status on bad option' do it 'fails on bad option' do - rubycritic('--no-such-option') + result = rubycritic('--no-such-option') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM - _(last_command_started.stderr).must_include 'Error: invalid option: --no-such-option' - _(last_command_started.stdout).must_equal '' + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM + _(result.stderr).must_include 'Error: invalid option: --no-such-option' + _(result.stdout).must_equal '' end end describe 'display the current version number' do it 'shows version' do - rubycritic('--version') + result = rubycritic('--version') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS - _(last_command_started.stdout).must_include "RubyCritic #{RubyCritic::VERSION}" + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.stdout).must_include "RubyCritic #{RubyCritic::VERSION}" end end describe 'display the help information' do it 'shows help' do - rubycritic('--help') + result = rubycritic('--help') - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS expected_help = <<~HELP Usage: rubycritic [options] [paths] -p, --path [PATH] Set path where report will be saved (tmp/rubycritic by default) @@ -67,7 +63,7 @@ -h, --help Show this message HELP - _(last_command_started.stdout).must_include expected_help + _(result.stdout).must_include expected_help end end end diff --git a/test/integration/rake_task_spec.rb b/test/integration/rake_task_spec.rb index 53b1b4f9..0a9661a5 100644 --- a/test/integration/rake_task_spec.rb +++ b/test/integration/rake_task_spec.rb @@ -5,29 +5,25 @@ describe 'Rake task' do include IntegrationTestHelper - before do - setup_aruba - end - describe 'paths attribute is respected' do it 'runs rake rubycritic with paths' do create_smelly_file - rake('rubycritic', <<~RUBY) + result = rake('rubycritic', <<~RUBY) RubyCritic::RakeTask.new do |t| t.paths = FileList['smelly.*'] t.options = '--no-browser -f console' end RUBY - _(last_command_started.stdout).must_include '(HighComplexity) AllTheMethods#method_missing has a flog score of 27' - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.stdout).must_include '(HighComplexity) AllTheMethods#method_missing has a flog score of 27' + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS end end describe 'name option changes the task name' do it 'runs rake silky' do create_smelly_file - rake('silky', <<~RUBY) + result = rake('silky', <<~RUBY) RubyCritic::RakeTask.new('silky') do |t| t.paths = FileList['smelly.*'] t.verbose = true @@ -35,14 +31,14 @@ end RUBY - _(last_command_started.stdout).must_include 'Running `silky` rake command' + _(result.stdout).must_include 'Running `silky` rake command' end end describe 'verbose prints details about the execution' do it 'runs rake rubycritic with verbose' do create_smelly_file - rake('rubycritic', <<~RUBY) + result = rake('rubycritic', <<~RUBY) RubyCritic::RakeTask.new do |t| t.paths = FileList['smelly.*'] t.verbose = true @@ -50,15 +46,15 @@ end RUBY - _(last_command_started.stdout).must_include '!!! Running `rubycritic` rake command' - _(last_command_started.stdout).must_include '!!! Inspecting smelly.rb with options --no-browser' + _(result.stdout).must_include '!!! Running `rubycritic` rake command' + _(result.stdout).must_include '!!! Inspecting smelly.rb with options --no-browser' end end describe 'respect --minimum-score' do it 'fails when score below minimum' do create_smelly_file - rake('rubycritic', <<~RUBY) + result = rake('rubycritic', <<~RUBY) RubyCritic::RakeTask.new do |t| t.paths = FileList['smelly.*'] t.verbose = true @@ -66,15 +62,15 @@ end RUBY - _(last_command_started.stdout).must_include 'Score (93.19) is below the minimum 95' - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM + _(result.stdout).must_include 'Score (93.19) is below the minimum 95' + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SCORE_BELOW_MINIMUM end end describe 'fail_on_error when false will exit 0 even when RubyCritic fails' do it 'succeeds despite low score' do create_smelly_file - rake('rubycritic', <<~RUBY) + result = rake('rubycritic', <<~RUBY) RubyCritic::RakeTask.new do |t| t.paths = FileList['smelly.*'] t.fail_on_error = false @@ -82,8 +78,8 @@ end RUBY - _(last_command_started.stdout).must_include 'Score (93.19) is below the minimum 95' - _(last_command_started.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS + _(result.stdout).must_include 'Score (93.19) is below the minimum 95' + _(result.exit_status).must_equal RubyCritic::Command::StatusReporter::SUCCESS end end end