Skip to content

Commit

Permalink
Add rudimentary regexp-based run by line number (#3)
Browse files Browse the repository at this point in the history
* Refactor to add a fixtures_path test helper

* Add rudimentary regexp-based run by line number

* Small regexp tweaks
  • Loading branch information
mattbrictson authored Feb 16, 2024
1 parent ae0de3c commit 9421d21
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 5 deletions.
1 change: 1 addition & 0 deletions lib/mighty_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module MightyTest
autoload :CLI, "mighty_test/cli"
autoload :MinitestRunner, "mighty_test/minitest_runner"
autoload :OptionParser, "mighty_test/option_parser"
autoload :TestParser, "mighty_test/test_parser"
end
13 changes: 13 additions & 0 deletions lib/mighty_test/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def run(argv: ARGV)
print_help
elsif options[:version]
puts VERSION
elsif path_args.grep(/.:\d+$/).any?
run_test_by_line_number
else
run_tests_by_path
end
Expand All @@ -31,6 +33,17 @@ def print_help
runner.print_help_and_exit!
end

def run_test_by_line_number
path, line = path_args.first.match(/^(.+):(\d+)$/).captures
test_name = TestParser.new(path).test_name_at_line(line.to_i)

if test_name
runner.run_inline_and_exit!(path, args: ["-n", "/^#{Regexp.quote(test_name)}$/"] + extra_args)
else
runner.run_inline_and_exit!(args: extra_args)
end
end

def run_tests_by_path
runner.run_inline_and_exit!(*path_args, args: extra_args)
end
Expand Down
33 changes: 33 additions & 0 deletions lib/mighty_test/test_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module MightyTest
class TestParser
def initialize(test_path)
@path = test_path.to_s
end

def test_name_at_line(number)
method_name = nil
lines = File.read(path).lines
lines[2...number].reverse_each.find do |line|
method_name =
match_minitest_method_name(line) ||
match_active_support_test_string(line)&.then { "test_#{_1.gsub(/\s+/, '_')}" }
end
method_name
end

private

attr_reader :path

def match_minitest_method_name(line)
line[/^\s*(?:focus\s+)?def\s+(test_\w+)/, 1]
end

def match_active_support_test_string(line)
match = line.match(/^\s*test\s+(?:"(.+?)"|'(.+?)')\s*do\s*(?:#.*?)?$/)
return unless match

match.captures.compact.first
end
end
end
11 changes: 11 additions & 0 deletions test/fixtures/active_support_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "rails_helper"

class ActiveSupportTest < ActiveSupport::TestCase
test "it's important" do # Trailing comment OK
assert true # rubocop:disable Minitest/UselessAssertion
end

test 'it does something "interesting"' do
assert true # rubocop:disable Minitest/UselessAssertion
end
end
4 changes: 4 additions & 0 deletions test/fixtures/example_project/test/failing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ class FailingTest < Minitest::Test
def test_assertion_fails
assert_equal "foo", "bar"
end

def test_assertion_succeeds
assert true # rubocop:disable Minitest/UselessAssertion
end
end
28 changes: 23 additions & 5 deletions test/integration/mt_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

module MightyTest
class MtTest < Minitest::Test
include FixturesPath

def test_mt_can_run_and_print_version
result = bundle_exec_mt(argv: ["--version"])

assert_equal(VERSION, result.stdout.chomp)
end

def test_mt_runs_a_successful_test
project_dir = File.expand_path("../fixtures/example_project", __dir__)
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["test/example_test.rb"], chdir: project_dir)

assert_match(/Run options:.* --seed \d+/, result.stdout)
Expand All @@ -18,27 +20,43 @@ def test_mt_runs_a_successful_test
end

def test_mt_runs_a_failing_test_and_exits_with_non_zero_status
project_dir = File.expand_path("../fixtures/example_project", __dir__)
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["test/failing_test.rb"], chdir: project_dir, raise_on_failure: false)

assert_predicate(result, :failure?)
assert_match(/\d runs, \d assertions, 1 failures, 0 errors/, result.stdout)
end

def test_mt_supports_test_focus
project_dir = File.expand_path("../fixtures/example_project", __dir__)
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["test/focused_test.rb"], chdir: project_dir)

assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, result.stdout)
assert_match(/\b1 runs, 1 assertions, 0 failures, 0 errors/, result.stdout)
end

def test_mt_passes_fail_fast_flag_to_minitest
project_dir = File.expand_path("../fixtures/example_project", __dir__)
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["--fail-fast", "test/example_test.rb"], chdir: project_dir)

assert_match(/Run options:.* --fail-fast/, result.stdout)
end

def test_mt_runs_a_single_test_by_line_number_with_verbose_output
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["--verbose", "test/failing_test.rb:9"], chdir: project_dir)

assert_includes(result.stdout, "FailingTest#test_assertion_succeeds")
assert_match(/\b1 assertions/, result.stdout)
end

def test_mt_runs_no_tests_if_line_number_doesnt_match
project_dir = fixtures_path.join("example_project")
result = bundle_exec_mt(argv: ["--verbose", "test/failing_test.rb:2"], chdir: project_dir)

assert_match(/Run options:.* --verbose/, result.stdout)
refute_match(/FailingTest/, result.stdout)
end

private

def bundle_exec_mt(argv:, env: { "CI" => nil }, chdir: nil, raise_on_failure: true)
Expand Down
38 changes: 38 additions & 0 deletions test/mighty_test/test_parser_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require "test_helper"

module MightyTest
class TestParserTest < Minitest::Test
include FixturesPath

def test_returns_nil_if_no_test_found
name = test_name_at_line(fixtures_path.join("example_project/test/example_test.rb"), 3)
assert_nil name
end

def test_finds_traditional_test_name_by_line_number
name = test_name_at_line(fixtures_path.join("example_project/test/example_test.rb"), 5)
assert_equal "test_that_it_has_a_version_number", name
end

def test_finds_traditional_test_name_by_line_number_even_with_focus
name = test_name_at_line(fixtures_path.join("example_project/test/focused_test.rb"), 5)
assert_equal "test_this_test_is_run", name
end

def test_finds_active_support_test_name_by_line_number
name = test_name_at_line(fixtures_path.join("active_support_test.rb"), 5)
assert_equal "test_it's_important", name
end

def test_finds_single_quoted_active_support_test_name_by_line_number
name = test_name_at_line(fixtures_path.join("active_support_test.rb"), 9)
assert_equal 'test_it_does_something_"interesting"', name
end

private

def test_name_at_line(path, line_number)
TestParser.new(path).test_name_at_line(line_number)
end
end
end
7 changes: 7 additions & 0 deletions test/support/fixtures_path.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module FixturesPath
private

def fixtures_path
Pathname.new(File.expand_path("../fixtures", __dir__))
end
end

0 comments on commit 9421d21

Please sign in to comment.