Skip to content

Commit 45ecdce

Browse files
authored
Merge pull request rails#51006 from kddnewton/parse-with-prism
Parse tests with prism
2 parents 6cfd568 + 105e05e commit 45ecdce

File tree

2 files changed

+90
-38
lines changed

2 files changed

+90
-38
lines changed

railties/lib/rails/test_unit/test_parser.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
# frozen_string_literal: true
22

3+
begin
4+
require "prism"
5+
rescue LoadError
6+
# If Prism isn't available (because of using an older Ruby version) then we'll
7+
# define a fallback parser using ripper.
8+
end
9+
10+
if defined?(Prism)
11+
module Rails
12+
module TestUnit
13+
# Parse a test file to extract the line ranges of all tests in both
14+
# method-style (def test_foo) and declarative-style (test "foo" do)
15+
module TestParser
16+
# Helper to translate a method object into the path and line range where
17+
# the method was defined.
18+
def self.definition_for(method)
19+
filepath, start_line = method.source_location
20+
queue = [Prism.parse_file(filepath).value]
21+
22+
while (node = queue.shift)
23+
case node.type
24+
when :def_node
25+
if node.name.start_with?("test") && node.location.start_line == start_line
26+
return [filepath, start_line..node.location.end_line]
27+
end
28+
when :call_node
29+
if node.name == :test && node.location.start_line == start_line
30+
return [filepath, start_line..node.location.end_line]
31+
end
32+
end
33+
34+
queue.concat(node.compact_child_nodes)
35+
end
36+
37+
nil
38+
end
39+
end
40+
end
41+
end
42+
43+
# If we have Prism, then we don't need to define the fallback parser using
44+
# ripper.
45+
return
46+
end
47+
348
require "ripper"
449

550
module Rails
Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,65 @@
11
# frozen_string_literal: true
22

3+
require "active_support/deprecator"
34
require "active_support/test_case"
45
require "active_support/testing/autorun"
56
require "rails/test_unit/test_parser"
67

7-
class TestParserTest < ActiveSupport::TestCase
8-
def test_parser
9-
example_test = <<~RUBY
10-
require "test_helper"
8+
class TestParserTestFixture < ActiveSupport::TestCase
9+
def test_method
10+
assert true
1111

12-
class ExampleTest < ActiveSupport::TestCase
13-
def test_method
14-
assert true
12+
assert true
13+
end
1514

15+
def test_oneline; assert true; end
1616

17-
end
17+
test "declarative" do
18+
assert true
19+
20+
assert true
21+
end
1822

19-
def test_oneline; assert true; end
23+
test("declarative w/parens") do
24+
assert true
25+
end
2026

21-
test "declarative" do
22-
assert true
23-
end
27+
self.test "declarative explicit receiver" do
28+
assert true
2429

25-
test("declarative w/parens") do
26-
assert true
30+
assert true
31+
end
2732

28-
end
33+
test("declarative oneline") { assert true }
2934

30-
self.test "declarative explicit receiver" do
31-
assert true
32-
end
35+
test("declarative oneline do") do assert true end
3336

34-
test("declarative oneline") { assert true }
37+
test("declarative multiline w/ braces") {
38+
assert true
39+
assert_not false
40+
}
41+
end
3542

36-
test("declarative oneline do") do assert true end
43+
class TestParserTest < ActiveSupport::TestCase
44+
def test_parser
45+
actual =
46+
TestParserTestFixture
47+
.instance_methods(false)
48+
.map { |method| TestParserTestFixture.instance_method(method) }
49+
.sort_by { |method| method.source_location[1] }
50+
.map { |method| [method.name, *Rails::TestUnit::TestParser.definition_for(method)] }
3751

38-
test("declarative multiline w/ braces") {
39-
assert true
40-
refute false
41-
}
42-
end
43-
RUBY
52+
expected = [
53+
[:test_method, __FILE__, 9..13],
54+
[:test_oneline, __FILE__, 15..15],
55+
[:test_declarative, __FILE__, 17..21],
56+
[:"test_declarative_w/parens", __FILE__, 23..25],
57+
[:test_declarative_explicit_receiver, __FILE__, 27..31],
58+
[:test_declarative_oneline, __FILE__, 33..33],
59+
[:test_declarative_oneline_do, __FILE__, 35..35],
60+
[:"test_declarative_multiline_w/_braces", __FILE__, 37..40]
61+
]
4462

45-
parser = Rails::TestUnit::TestParser.new(example_test, "example_test.rb")
46-
expected_map = {
47-
4 => 8, # test_method
48-
10 => 10, # test_oneline
49-
12 => 14, # declarative
50-
16 => 19, # declarative w/parens
51-
21 => 23, # declarative explicit receiver
52-
25 => 25, # declarative oneline
53-
27 => 27, # declarative oneilne do
54-
29 => 32 # declarative multiline w/braces
55-
}
56-
assert_equal expected_map, parser.parse
63+
assert_equal expected, actual
5764
end
5865
end

0 commit comments

Comments
 (0)