From 7db376641edf5188a72be7b6fd3b88e26bf39656 Mon Sep 17 00:00:00 2001 From: Alexandre Barret Date: Sun, 24 Nov 2024 21:49:55 +1300 Subject: [PATCH] Refactoring * Cleanup runner and commands * Remove all_test_runner * Refactor format batch of Ruby and Rake --- exe/retest | 11 +-- features/git-ruby/retest/retest_test.rb | 2 +- features/rails-app/retest/retest_test.rb | 4 +- lib/retest.rb | 1 + lib/retest/command/base.rb | 26 +++++-- lib/retest/command/hardcoded.rb | 9 +-- lib/retest/command/rails.rb | 15 ++-- lib/retest/command/rake.rb | 17 +++-- lib/retest/command/rspec.rb | 15 ++-- lib/retest/command/ruby.rb | 8 +- lib/retest/program.rb | 17 +++-- lib/retest/runner.rb | 96 +++++++++++++----------- test/retest/command/command_interface.rb | 6 ++ test/retest/command/hardcoded_test.rb | 64 ++++++++++------ test/retest/command/ruby_test.rb | 2 +- test/retest/runner/runner_interface.rb | 10 --- test/retest/runner_test.rb | 19 +++-- 17 files changed, 178 insertions(+), 144 deletions(-) diff --git a/exe/retest b/exe/retest index ae013c58..1624af4e 100755 --- a/exe/retest +++ b/exe/retest @@ -29,11 +29,6 @@ command = Retest::Command.for_options(options) runner = Retest::Runner.new(command) sounds = Retest::Sounds.for(options) -# All test runner -all_test_command = Retest::Command.for_options(options.merge(%w[--all]), stdout: nil) -all_test_runner = Retest::Runner.new(all_test_command) -all_test_runner.add_observer(sounds) - sounds.play(:start) runner.add_observer(sounds) prompt.add_observer(sounds) @@ -69,7 +64,7 @@ Retest.listen(options) do |modified, added, removed| end $stdout.puts "Ready to refactor! You can make file changes now" -def run_command(input:, program:, all_test_runner:) +def run_command(input:, program:) case input when /^file changed:\s(.*)$/ puts "File changed: #{$1}" @@ -95,7 +90,7 @@ def run_command(input:, program:, all_test_runner:) program.run(nil, force_run: true) when 'ra', 'run all' puts "Running all tests\n" - all_test_runner.run + program.run_all when /^di?f?f?\s(.*)$/ program.diff($1) when 'h', 'help' @@ -123,6 +118,6 @@ loop do readable_connections = ready[0] readable_connections.each do |conn| data = conn.readpartial(4096) - run_command(input: data.to_s.chomp, program: program, all_test_runner: all_test_runner) + run_command(input: data.to_s.chomp, program: program) end end diff --git a/features/git-ruby/retest/retest_test.rb b/features/git-ruby/retest/retest_test.rb index 058c035f..ca9244e7 100644 --- a/features/git-ruby/retest/retest_test.rb +++ b/features/git-ruby/retest/retest_test.rb @@ -60,7 +60,7 @@ def test_diffs_from_other_branch sleep 2 assert_match <<~EXPECTED, @output.read - Tests found: + Tests selected: - test/created_with_test_file_test.rb - test/renamed_with_test_file_test.rb - test/to_be_renamed_test.rb diff --git a/features/rails-app/retest/retest_test.rb b/features/rails-app/retest/retest_test.rb index 0542491e..a8c5c483 100644 --- a/features/rails-app/retest/retest_test.rb +++ b/features/rails-app/retest/retest_test.rb @@ -126,12 +126,10 @@ def test_diffs_from_other_branch assert_match <<~EXPECTED, @output.read Setup identified: [RAILS]. Using command: 'bin/rails test ' - Tests found: + Tests selected: - test/controllers/books_controller_test.rb - test/models/book_test.rb - test/system/books_test.rb - Running tests... - Test Files Selected: test/controllers/books_controller_test.rb test/models/book_test.rb test/system/books_test.rb EXPECTED assert_match <<~EXPECTED, @output.read diff --git a/lib/retest.rb b/lib/retest.rb index 0535a4aa..6fd7eb9f 100644 --- a/lib/retest.rb +++ b/lib/retest.rb @@ -20,6 +20,7 @@ module Retest class Error < StandardError; end + class FileNotFound < StandardError; end def self.listen(options, listener: Listen) listener.to('.', only: options.extension, relative: true, force_polling: options.force_polling?) do |modified, added, removed| diff --git a/lib/retest/command/base.rb b/lib/retest/command/base.rb index 72f342f9..e82295b7 100644 --- a/lib/retest/command/base.rb +++ b/lib/retest/command/base.rb @@ -1,5 +1,7 @@ module Retest class Command + class MultipleTestsNotSupported < StandardError; end + class Base def initialize(all: false, file_system: FileSystem, command: nil) @file_system = file_system @@ -7,28 +9,40 @@ def initialize(all: false, file_system: FileSystem, command: nil) @command = command end - def changed_type? + def clone(params = {}) + self.class.new(**{ all: all, file_system: file_system, command: command }.merge(params)) + end + + def has_changed? to_s.include?('') end - def test_type? + def has_test? to_s.include?('') end + def changed_type? + !has_test? && has_changed? + end + + def test_type? + has_test? && !has_changed? + end + def variable_type? - test_type? && changed_type? + has_test? && has_changed? end def hardcoded_type? - !test_type? && !changed_type? + !has_test? && !has_changed? end def to_s - raise NotImplementedError + @command end def format_batch(*files) - raise NotImplementedError + raise MultipleTestsNotSupported, "Multiple test files run not supported for '#{to_s}'" end private diff --git a/lib/retest/command/hardcoded.rb b/lib/retest/command/hardcoded.rb index 2742095b..f4a44dfe 100644 --- a/lib/retest/command/hardcoded.rb +++ b/lib/retest/command/hardcoded.rb @@ -1,12 +1,5 @@ module Retest class Command - class Hardcoded < Base - def to_s - @command - end - - def format_batch(*files) - end - end + class Hardcoded < Base; end end end diff --git a/lib/retest/command/rails.rb b/lib/retest/command/rails.rb index e7284960..c1b7aa42 100644 --- a/lib/retest/command/rails.rb +++ b/lib/retest/command/rails.rb @@ -2,8 +2,11 @@ module Retest class Command class Rails < Base def to_s - return "#{root_command} " unless all - root_command + if all + root_command + else + "#{root_command} " + end end def format_batch(*files) @@ -13,9 +16,11 @@ def format_batch(*files) private def root_command - return 'bin/rails test' if file_system.exist? 'bin/rails' - - 'bundle exec rails test' + if file_system.exist? 'bin/rails' + 'bin/rails test' + else + 'bundle exec rails test' + end end end end diff --git a/lib/retest/command/rake.rb b/lib/retest/command/rake.rb index 7384cfff..9cb7330f 100644 --- a/lib/retest/command/rake.rb +++ b/lib/retest/command/rake.rb @@ -2,20 +2,25 @@ module Retest class Command class Rake < Base def to_s - return "#{root_command} TEST=" unless all - root_command + if all + root_command + else + "#{root_command} TEST=" + end end def format_batch(*files) - files.size > 1 ? "\"{#{files.join(',')}}\"" : files.first + files.size > 1 ? %Q{"{#{files.join(',')}}"} : files.first end private def root_command - return 'bin/rake test' if file_system.exist? 'bin/rake' - - 'bundle exec rake test' + if file_system.exist? 'bin/rake' + 'bin/rake test' + else + 'bundle exec rake test' + end end end end diff --git a/lib/retest/command/rspec.rb b/lib/retest/command/rspec.rb index 87ca8581..cdbd39b1 100644 --- a/lib/retest/command/rspec.rb +++ b/lib/retest/command/rspec.rb @@ -2,8 +2,11 @@ module Retest class Command class Rspec < Base def to_s - return "#{root_command} " unless all - root_command + if all + root_command + else + "#{root_command} " + end end def format_batch(*files) @@ -13,9 +16,11 @@ def format_batch(*files) private def root_command - return 'bin/rspec' if file_system.exist? 'bin/rspec' - - 'bundle exec rspec' + if file_system.exist? 'bin/rspec' + 'bin/rspec' + else + 'bundle exec rspec' + end end end end diff --git a/lib/retest/command/ruby.rb b/lib/retest/command/ruby.rb index 921f02e6..fdb26bca 100644 --- a/lib/retest/command/ruby.rb +++ b/lib/retest/command/ruby.rb @@ -1,10 +1,6 @@ module Retest class Command class Ruby < Base - def format_batch(*files) - %Q{-e "#{files.map { |file| "require './#{file}';" }.join}"} - end - def to_s if file_system.exist? 'Gemfile.lock' 'bundle exec ruby ' @@ -12,6 +8,10 @@ def to_s 'ruby ' end end + + def format_batch(*files) + files.size > 1 ? %Q{-e "#{files.map { |file| "require './#{file}';" }.join}"} : files.first + end end end end \ No newline at end of file diff --git a/lib/retest/program.rb b/lib/retest/program.rb index 15b789b3..8cc0f0ea 100644 --- a/lib/retest/program.rb +++ b/lib/retest/program.rb @@ -20,24 +20,25 @@ def run(file, force_run: false) return end - test_file = repository.find_test(file) if runner.command.test_type? + test_file = if runner.has_test? + repository.find_test(file) + end + runner.run changed_files: [file], test_files: [test_file] end def diff(branch) raise "Git not installed" unless VersionControl::Git.installed? test_files = repository.find_tests VersionControl::Git.diff_files(branch) + run_selected(test_files) + end - @stdout.puts "Tests found:" - test_files.each { |test_file| @stdout.puts " - #{test_file}" } - - @stdout.puts "Running tests..." - runner.run_all_tests command.format_batch(*test_files) + def run_all + runner.run_all end def run_selected(test_files) - @stdout.puts "Running tests..." - runner.run_all_tests command.format_batch(*test_files) + runner.run(test_files: test_files) end def clear_terminal diff --git a/lib/retest/runner.rb b/lib/retest/runner.rb index e2726e84..8c7a100f 100644 --- a/lib/retest/runner.rb +++ b/lib/retest/runner.rb @@ -2,86 +2,92 @@ module Retest class Runner + extend Forwardable include Observable include CachedTestFile + def_delegators :command, + :has_changed?, :has_test?, + :changed_type?, :test_type?, :variable_type?, :harcoded_type? + attr_accessor :command, :stdout def initialize(command, stdout: $stdout) @stdout = stdout @command = command end - def ==(obj) - return false unless obj.command + def run(changed_files: [], test_files: []) + system_run format_instruction(changed_files: changed_files, test_files: test_files) + rescue FileNotFound => e + log("FileNotFound - #{e.message}") + rescue Command::MultipleTestsNotSupported => e + log("Command::MultipleTestsNotSupported - #{e.message}") + end - command.to_s == obj.command.to_s && self.class == obj.class + def run_all + system_run command.clone(all: true).to_s end - def run(changed_files: [], test_files: []) - changed_file = changed_files.is_a?(Array) ? changed_files.first : changed_files - test_file = test_files.is_a?(Array) ? test_files.first : test_files + def format_instruction(changed_files: [], test_files: []) + if changed_files.size == 0 && test_files.size >= 1 + instruction = command.clone(all: false).to_s + tests_string = command.format_batch(*test_files) + log("Tests selected:") + test_files.each { |test_file| log(" - #{test_file}") } + return instruction.gsub('', tests_string) + end + + instruction = command.to_s + instruction = format_changed_files(instruction: instruction, files: changed_files) + instruction = format_test_files(instruction: instruction, files: test_files) + end - self.cached_test_file = test_file + def format_test_files(instruction:, files:) + return instruction unless has_test? - if command.to_s.include?('') - if changed_file.nil? - print_changed_file_not_found - return - end - log("Changed file: #{changed_file}") - end + self.cached_test_file = files.first - if command.to_s.include?('') - if cached_test_file.nil? - print_test_file_not_found - return - end - log("Test file: #{cached_test_file}") + if cached_test_file.nil? + raise FileNotFound, "Retest could not find a matching test file to run." end - log("\n") - system_run command.to_s - .gsub('', cached_test_file.to_s) - .gsub('', changed_file.to_s) + log("Test file: #{cached_test_file}") + instruction.gsub('', cached_test_file) end - def run_all_tests(tests_string) - log("Test Files Selected: #{tests_string}") - system_run command.to_s.gsub('', tests_string) + def format_changed_files(instruction:, files:) + return instruction unless has_changed? + changed_file = files.first + + if changed_file.nil? + raise FileNotFound, "Retest could not find a changed file to run." + end + + log("Changed file: #{changed_file}") + instruction.gsub('', changed_file) end def sync(added:, removed:) purge_test_file(removed) end - def running? - @running - end - private + def print_test_file_not_found + log(<<~ERROR) + FileNotFound - Retest could not find a matching test file to run. + ERROR + end + def system_run(command) - @running = true + log("\n") result = system(command) ? :tests_pass : :tests_fail changed notify_observers(result) - @running = false end def log(message) stdout.puts(message) end - - def print_changed_file_not_found - log(<<~ERROR) - FileNotFound - Retest could not find a changed file to run. - ERROR - end - - def print_test_file_not_found - log(<<~ERROR) - FileNotFound - Retest could not find a matching test file to run. - ERROR - end end end diff --git a/test/retest/command/command_interface.rb b/test/retest/command/command_interface.rb index 4e34ef8b..b9b5bdd6 100644 --- a/test/retest/command/command_interface.rb +++ b/test/retest/command/command_interface.rb @@ -4,6 +4,12 @@ module CommandInterface def test_interface assert_respond_to @subject, :format_batch assert_respond_to @subject, :to_s + assert_respond_to @subject, :has_test? + assert_respond_to @subject, :has_changed? + assert_respond_to @subject, :test_type? + assert_respond_to @subject, :changed_type? + assert_respond_to @subject, :variable_type? + assert_respond_to @subject, :hardcoded_type? end def test_initializatioin diff --git a/test/retest/command/hardcoded_test.rb b/test/retest/command/hardcoded_test.rb index 8385f011..ccd69e65 100644 --- a/test/retest/command/hardcoded_test.rb +++ b/test/retest/command/hardcoded_test.rb @@ -4,38 +4,50 @@ module Retest class Command class HardcodedTest < MiniTest::Test + include CommandInterface + def setup @subject = Hardcoded.new(command: 'echo "hello world"') end - include CommandInterface - - def test_test? - refute Hardcoded.new(command: 'echo "hello world"').test_type? - assert Hardcoded.new(command: 'echo ').test_type? - refute Hardcoded.new(command: 'echo ').test_type? - assert Hardcoded.new(command: 'echo & ').test_type? + def test_a_hardcoded_command_status + command = Hardcoded.new(command: 'echo "hello world"') + refute command.has_test? + refute command.has_changed? + refute command.test_type? + refute command.changed_type? + refute command.variable_type? + assert command.hardcoded_type? end - def test_variable? - refute Hardcoded.new(command: 'echo "hello world"').variable_type? - refute Hardcoded.new(command: 'echo ').variable_type? - refute Hardcoded.new(command: 'echo ').variable_type? - assert Hardcoded.new(command: 'echo & ').variable_type? + def test_a_test_and_changed_command_status + command = Hardcoded.new(command: 'echo & ') + assert command.has_test? + assert command.has_changed? + refute command.test_type? + refute command.changed_type? + assert command.variable_type? + refute command.hardcoded_type? end - def test_changed? - refute Hardcoded.new(command: 'echo "hello world"').changed_type? - refute Hardcoded.new(command: 'echo ').changed_type? - assert Hardcoded.new(command: 'echo ').changed_type? - assert Hardcoded.new(command: 'echo & ').changed_type? + def test_a_test_command_status + command = Hardcoded.new(command: 'echo ') + assert command.has_test? + refute command.has_changed? + assert command.test_type? + refute command.changed_type? + refute command.variable_type? + refute command.hardcoded_type? end - def test_hardcoded? - assert Hardcoded.new(command: 'echo "hello world"').hardcoded_type? - refute Hardcoded.new(command: 'echo ').hardcoded_type? - refute Hardcoded.new(command: 'echo ').hardcoded_type? - refute Hardcoded.new(command: 'echo & ').hardcoded_type? + def test_a_changed_command_status + command = Hardcoded.new(command: 'echo ') + refute command.has_test? + assert command.has_changed? + refute command.test_type? + assert command.changed_type? + refute command.variable_type? + refute command.hardcoded_type? end def test_to_s @@ -43,11 +55,15 @@ def test_to_s end def test_format_with_one_file - assert_nil @subject.format_batch('a/file/path.rb') + assert_raises(Command::MultipleTestsNotSupported) do + @subject.format_batch('a/file/path.rb') + end end def test_format_with_multiple_files - assert_nil @subject.format_batch('a/file/path.rb', 'another/file/path.rb') + assert_raises(Command::MultipleTestsNotSupported) do + @subject.format_batch('a/file/path.rb', 'another/file/path.rb') + end end end end diff --git a/test/retest/command/ruby_test.rb b/test/retest/command/ruby_test.rb index 3b5230bc..3758d6ef 100644 --- a/test/retest/command/ruby_test.rb +++ b/test/retest/command/ruby_test.rb @@ -37,7 +37,7 @@ def test_to_s end def test_format_with_one_file - assert_equal %Q{-e "require './a/file/path.rb';"}, @subject.format_batch('a/file/path.rb') + assert_equal 'a/file/path.rb', @subject.format_batch('a/file/path.rb') end def test_format_with_multiple_files diff --git a/test/retest/runner/runner_interface.rb b/test/retest/runner/runner_interface.rb index 131b3925..26139c1a 100644 --- a/test/retest/runner/runner_interface.rb +++ b/test/retest/runner/runner_interface.rb @@ -4,22 +4,12 @@ module RunnerInterfaceTest def test_behaviour assert_respond_to @subject, :== assert_respond_to @subject, :run - assert_respond_to @subject, :run_all_tests assert_respond_to @subject, :sync end def test_run_accepts_the_right_parameter _, _ = capture_subprocess_io { @subject.run changed_files: ['some-path.rb'], test_files: ['some-test-path.rb'] } end - - def test_equal - runner1 = @subject.class.new('hello') - runner2 = @subject.class.new('hello') - runner3 = @subject.class.new('world') - - assert_equal runner1, runner2 - refute_equal runner1, runner3 - end end end end diff --git a/test/retest/runner_test.rb b/test/retest/runner_test.rb index 01ce1f86..e67757c8 100644 --- a/test/retest/runner_test.rb +++ b/test/retest/runner_test.rb @@ -111,7 +111,7 @@ def output end def test_run_with_no_file_found - _, _ = capture_subprocess_io { @subject.run } + @subject.run assert_equal(<<~EXPECTED, output) FileNotFound - Retest could not find a changed file to run. @@ -159,16 +159,15 @@ def test_returns_last_command assert_match "touch file_path_test.rb", out end - def test_run_all_tests - out, _ = capture_subprocess_io { @subject.run_all_tests('file_path.rb file_path_two.rb') } + def test_run_multiple_tests + assert_raises(Command::MultipleTestsNotSupported) do + @subject.command = @command + @subject.format_instruction(test_files: ['file_path.rb', 'file_path_two.rb']) + end - assert_equal(<<~EXPECATIONS, @subject.stdout.string) - Test Files Selected: file_path.rb file_path_two.rb - EXPECATIONS - - assert_equal(<<~EXPECATIONS, out) - touch file_path.rb file_path_two.rb - EXPECATIONS + @subject.command = Command::Rails.new(all: false) + instruction = @subject.format_instruction(test_files: ['file_path.rb', 'file_path_two.rb']) + assert_equal 'bundle exec rails test file_path.rb file_path_two.rb', instruction end end end