tryouts 3.2.2 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/exe/try +1 -1
- data/lib/tryouts/cli/formatters/compact.rb +4 -1
- data/lib/tryouts/cli/formatters/live_status_manager.rb +2 -2
- data/lib/tryouts/cli/formatters/verbose.rb +5 -2
- data/lib/tryouts/cli/opts.rb +4 -0
- data/lib/tryouts/expectation_evaluators/regex_match.rb +11 -3
- data/lib/tryouts/expectation_evaluators/result_type.rb +9 -1
- data/lib/tryouts/file_processor.rb +20 -2
- data/lib/tryouts/parsers/base_parser.rb +23 -0
- data/lib/tryouts/parsers/enhanced_parser.rb +113 -0
- data/lib/tryouts/parsers/prism_parser.rb +120 -0
- data/lib/tryouts/parsers/shared_methods.rb +412 -0
- data/lib/tryouts/test_batch.rb +29 -4
- data/lib/tryouts/test_runner.rb +2 -1
- data/lib/tryouts/version.rb +1 -1
- data/lib/tryouts.rb +2 -1
- metadata +5 -2
- data/lib/tryouts/prism_parser.rb +0 -515
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adb9f46213aee10ed4b9d2a1b9b8d5c9e385ea23f996445debc7458b43351512
|
4
|
+
data.tar.gz: 8d6abfed42e73bb340e13a62991b4855b8c0c18efa3092b4e3244a822a1612c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 571410ed483879bd035b14c053a5c3496d51ad2248cff2534cf40fc06a72ece1aea13a7e61ae2c29b1e1f1768f19d3c5ede8c4e4a30a977c29aacb502c616988
|
7
|
+
data.tar.gz: 6b5186131242edf826ba44303daaee716ce1ec364683e521df5224818d796067209a9a0ae66cacc85d15796cfee92df2349372fc5df762ced52b8753e1196c0e
|
data/README.md
CHANGED
@@ -134,7 +134,7 @@ try -D # debug mode
|
|
134
134
|
|
135
135
|
### Core Components
|
136
136
|
|
137
|
-
- **Prism Parser**:
|
137
|
+
- **Prism Parser**: Inhouse Ruby parsing with pattern matching for line classification
|
138
138
|
- **Data Structures**: Immutable `Data.define` classes for test representation
|
139
139
|
- **Framework Translators**: Convert tryouts to RSpec/Minitest format
|
140
140
|
- **CLI**: Modern command-line interface with framework selection
|
data/exe/try
CHANGED
@@ -17,7 +17,7 @@ if ENV['COVERAGE'] || ENV['SIMPLECOV']
|
|
17
17
|
add_group 'Core', 'lib/tryouts.rb'
|
18
18
|
add_group 'CLI', 'lib/tryouts/cli'
|
19
19
|
add_group 'Formatters', 'lib/tryouts/cli/formatters'
|
20
|
-
add_group 'Parsers', 'lib/tryouts/
|
20
|
+
add_group 'Parsers', 'lib/tryouts/parsers'
|
21
21
|
add_group 'Data Structures', ['lib/tryouts/testcase.rb', 'lib/tryouts/testbatch.rb']
|
22
22
|
add_group 'Translators', 'lib/tryouts/translators'
|
23
23
|
add_group 'Execution', ['lib/tryouts/test_executor.rb', 'lib/tryouts/test_runner.rb', 'lib/tryouts/file_processor.rb']
|
@@ -57,6 +57,8 @@ class Tryouts
|
|
57
57
|
puts Console.color(:red, 'Failed Tests:')
|
58
58
|
puts
|
59
59
|
|
60
|
+
# Number failures sequentially across all files instead of per-file
|
61
|
+
failure_number = 1
|
60
62
|
failure_collector.failures_by_file.each do |file_path, failures|
|
61
63
|
failures.each do |failure|
|
62
64
|
pretty_path = Console.pretty_path(file_path)
|
@@ -68,10 +70,11 @@ class Tryouts
|
|
68
70
|
pretty_path
|
69
71
|
end
|
70
72
|
|
71
|
-
puts " #{location}"
|
73
|
+
puts " #{failure_number}) #{location}"
|
72
74
|
puts " #{Console.color(:red, '✗')} #{failure.description}"
|
73
75
|
puts " #{failure.failure_reason}"
|
74
76
|
puts
|
77
|
+
failure_number += 1
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
@@ -6,7 +6,7 @@ require_relative 'tty_status_display'
|
|
6
6
|
class Tryouts
|
7
7
|
class CLI
|
8
8
|
# Centralized manager for live status display across all formatters
|
9
|
-
# Replaces the decorator pattern with
|
9
|
+
# Replaces the decorator pattern with inhouse integration
|
10
10
|
class LiveStatusManager
|
11
11
|
def initialize(formatter, options = {})
|
12
12
|
@formatter = formatter
|
@@ -20,7 +20,7 @@ class Tryouts
|
|
20
20
|
@display = TTYStatusDisplay.new(@formatter.stdout, options)
|
21
21
|
@status_reserved = false
|
22
22
|
|
23
|
-
debug_log('LiveStatusManager: Enabled with
|
23
|
+
debug_log('LiveStatusManager: Enabled with inhouse integration')
|
24
24
|
end
|
25
25
|
|
26
26
|
def enabled?
|
@@ -56,8 +56,10 @@ class Tryouts
|
|
56
56
|
puts
|
57
57
|
puts Console.color(:red, 'Failed Tests:')
|
58
58
|
|
59
|
+
# Number failures sequentially across all files instead of per-file
|
60
|
+
failure_number = 1
|
59
61
|
failure_collector.failures_by_file.each do |file_path, failures|
|
60
|
-
failures.
|
62
|
+
failures.each do |failure|
|
61
63
|
pretty_path = Console.pretty_path(file_path)
|
62
64
|
|
63
65
|
# Include line number with file path for easy copying/clicking
|
@@ -69,7 +71,7 @@ class Tryouts
|
|
69
71
|
|
70
72
|
puts
|
71
73
|
puts Console.color(:yellow, location)
|
72
|
-
puts " #{
|
74
|
+
puts " #{failure_number}) #{failure.description}"
|
73
75
|
puts " #{Console.color(:red, 'Failure:')} #{failure.failure_reason}"
|
74
76
|
|
75
77
|
# Show source context in verbose mode
|
@@ -80,6 +82,7 @@ class Tryouts
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
puts
|
85
|
+
failure_number += 1
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
data/lib/tryouts/cli/opts.rb
CHANGED
@@ -66,6 +66,10 @@ class Tryouts
|
|
66
66
|
opts.on('-c', '--compact', 'Compact single-line output') { options[:compact] = true }
|
67
67
|
opts.on('-l', '--live', 'Live status display') { options[:live_status] = true }
|
68
68
|
|
69
|
+
opts.separator "\nParser Options:"
|
70
|
+
opts.on('--enhanced-parser', 'Use enhanced parser with inhouse comment extraction (default)') { options[:parser] = :enhanced }
|
71
|
+
opts.on('--legacy-parser', 'Use legacy prism parser') { options[:parser] = :prism }
|
72
|
+
|
69
73
|
opts.separator "\nInspection Options:"
|
70
74
|
opts.on('-i', '--inspect', 'Inspect file structure without running tests') { options[:inspect] = true }
|
71
75
|
|
@@ -40,9 +40,17 @@ class Tryouts
|
|
40
40
|
expectation_result = ExpectationResult.from_result(actual_result)
|
41
41
|
pattern = eval_expectation_content(@expectation.content, expectation_result)
|
42
42
|
|
43
|
-
#
|
44
|
-
|
45
|
-
|
43
|
+
# Auto-detect exceptions and use message for regex matching
|
44
|
+
# This allows #=~> /pattern/ to work naturally with exception messages
|
45
|
+
string_result = if actual_result.is_a?(Exception)
|
46
|
+
# Make error available in context for manual access if needed
|
47
|
+
@context.define_singleton_method(:error) { actual_result }
|
48
|
+
actual_result.message # Match against error message
|
49
|
+
else
|
50
|
+
actual_result.to_s # Normal case: convert to string
|
51
|
+
end
|
52
|
+
|
53
|
+
match_result = string_result =~ pattern
|
46
54
|
|
47
55
|
build_result(
|
48
56
|
passed: !match_result.nil?,
|
@@ -36,7 +36,15 @@ class Tryouts
|
|
36
36
|
|
37
37
|
def evaluate(actual_result = nil)
|
38
38
|
expectation_result = ExpectationResult.from_result(actual_result)
|
39
|
-
|
39
|
+
|
40
|
+
# Try to evaluate in test context first, then fallback to global context for constants
|
41
|
+
begin
|
42
|
+
expected_class = eval_expectation_content(@expectation.content, expectation_result)
|
43
|
+
rescue NameError => e
|
44
|
+
# If we can't find the constant in test context, try global context
|
45
|
+
# This is common for exception classes like ArgumentError, StandardError, etc.
|
46
|
+
expected_class = Object.const_get(@expectation.content.strip)
|
47
|
+
end
|
40
48
|
|
41
49
|
build_result(
|
42
50
|
passed: actual_result.is_a?(expected_class),
|
@@ -1,12 +1,15 @@
|
|
1
1
|
# lib/tryouts/file_processor.rb
|
2
2
|
|
3
|
-
require_relative 'prism_parser'
|
3
|
+
require_relative 'parsers/prism_parser'
|
4
|
+
require_relative 'parsers/enhanced_parser'
|
4
5
|
require_relative 'test_executor'
|
5
6
|
require_relative 'cli/modes/inspect'
|
6
7
|
require_relative 'cli/modes/generate'
|
7
8
|
|
8
9
|
class Tryouts
|
9
10
|
class FileProcessor
|
11
|
+
# Supported parser types for validation and documentation
|
12
|
+
PARSER_TYPES = [:enhanced, :prism].freeze
|
10
13
|
def initialize(file:, options:, output_manager:, translator:, global_tally:)
|
11
14
|
@file = file
|
12
15
|
@options = options
|
@@ -16,7 +19,7 @@ class Tryouts
|
|
16
19
|
end
|
17
20
|
|
18
21
|
def process
|
19
|
-
testrun =
|
22
|
+
testrun = create_parser(@file, @options).parse
|
20
23
|
@global_tally[:file_count] += 1
|
21
24
|
@output_manager.file_parsed(@file, testrun.total_tests)
|
22
25
|
|
@@ -35,6 +38,21 @@ class Tryouts
|
|
35
38
|
|
36
39
|
private
|
37
40
|
|
41
|
+
def create_parser(file, options)
|
42
|
+
parser_type = options[:parser] || :enhanced # enhanced parser is now the default
|
43
|
+
|
44
|
+
unless PARSER_TYPES.include?(parser_type)
|
45
|
+
raise ArgumentError, "Unknown parser: #{parser_type}. Allowed types: #{PARSER_TYPES.join(', ')}"
|
46
|
+
end
|
47
|
+
|
48
|
+
case parser_type
|
49
|
+
when :enhanced
|
50
|
+
EnhancedParser.new(file)
|
51
|
+
when :prism
|
52
|
+
PrismParser.new(file)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
38
56
|
def handle_inspect_mode(testrun)
|
39
57
|
mode = Tryouts::CLI::InspectMode.new(@file, testrun, @options, @output_manager, @translator)
|
40
58
|
mode.handle
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# lib/tryouts/parsers/base_parser.rb
|
2
|
+
|
3
|
+
require 'prism'
|
4
|
+
|
5
|
+
require_relative 'shared_methods'
|
6
|
+
|
7
|
+
class Tryouts
|
8
|
+
# Fixed PrismParser with pattern matching for robust token filtering
|
9
|
+
module Parsers
|
10
|
+
class BaseParser
|
11
|
+
include Tryouts::Parsers::SharedMethods
|
12
|
+
|
13
|
+
def initialize(source_path)
|
14
|
+
@source_path = source_path
|
15
|
+
@source = File.read(source_path)
|
16
|
+
@lines = @source.lines.map(&:chomp)
|
17
|
+
@prism_result = Prism.parse(@source)
|
18
|
+
@parsed_at = Time.now
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# lib/tryouts/parsers/enhanced_parser.rb
|
2
|
+
|
3
|
+
# Enhanced parser using Prism's inhouse comment extraction capabilities
|
4
|
+
# Drop-in replacement for PrismParser that eliminates HEREDOC parsing issues
|
5
|
+
|
6
|
+
require_relative '../test_case'
|
7
|
+
require_relative 'base_parser'
|
8
|
+
|
9
|
+
class Tryouts
|
10
|
+
# Enhanced parser that replaces manual line-by-line parsing with inhouse Prism APIs
|
11
|
+
# while maintaining full compatibility with the original parser's logic structure
|
12
|
+
class EnhancedParser < Tryouts::Parsers::BaseParser
|
13
|
+
|
14
|
+
def parse
|
15
|
+
return handle_syntax_errors if @prism_result.failure?
|
16
|
+
|
17
|
+
# Use inhouse comment extraction instead of line-by-line regex parsing
|
18
|
+
# This automatically excludes HEREDOC content!
|
19
|
+
tokens = tokenize_content_with_inhouse_extraction
|
20
|
+
test_boundaries = find_test_case_boundaries(tokens)
|
21
|
+
tokens = classify_potential_descriptions_with_boundaries(tokens, test_boundaries)
|
22
|
+
test_blocks = group_into_test_blocks(tokens)
|
23
|
+
process_test_blocks(test_blocks)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Inhouse comment extraction - replaces the manual regex parsing
|
29
|
+
def tokenize_content_with_inhouse_extraction
|
30
|
+
tokens = []
|
31
|
+
|
32
|
+
# Get all comments using inhouse Prism extraction
|
33
|
+
comments = Prism.parse_comments(@source)
|
34
|
+
comment_by_line = comments.group_by { |comment| comment.location.start_line }
|
35
|
+
|
36
|
+
# Process each line, handling multiple comments per line
|
37
|
+
@lines.each_with_index do |line, index|
|
38
|
+
line_number = index + 1
|
39
|
+
|
40
|
+
if (comments_for_line = comment_by_line[line_number]) && !comments_for_line.empty?
|
41
|
+
emitted_code = false
|
42
|
+
comments_for_line.sort_by! { |c| c.location.start_column }
|
43
|
+
comments_for_line.each do |comment|
|
44
|
+
comment_content = comment.slice.strip
|
45
|
+
if comment.location.start_column > 0
|
46
|
+
unless emitted_code
|
47
|
+
tokens << { type: :code, content: line, line: index, ast: parse_ruby_line(line) }
|
48
|
+
emitted_code = true
|
49
|
+
end
|
50
|
+
# Inline comment may carry expectations; classify it too
|
51
|
+
tokens << classify_comment_inhousely(comment_content, line_number)
|
52
|
+
else
|
53
|
+
tokens << classify_comment_inhousely(comment_content, line_number)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
59
|
+
# Handle non-comment lines (blank lines and code)
|
60
|
+
token = case line
|
61
|
+
when /^\s*$/
|
62
|
+
{ type: :blank, line: index }
|
63
|
+
else
|
64
|
+
{ type: :code, content: line, line: index, ast: parse_ruby_line(line) }
|
65
|
+
end
|
66
|
+
tokens << token
|
67
|
+
end
|
68
|
+
|
69
|
+
tokens
|
70
|
+
end
|
71
|
+
|
72
|
+
# Inhouse comment classification - replaces complex regex patterns
|
73
|
+
def classify_comment_inhousely(content, line_number)
|
74
|
+
case content
|
75
|
+
when /^##\s*(.*)$/
|
76
|
+
{ type: :description, content: $1.strip, line: line_number - 1 }
|
77
|
+
when /^#\s*TEST\s*\d*:\s*(.*)$/
|
78
|
+
{ type: :description, content: $1.strip, line: line_number - 1 }
|
79
|
+
when /^#\s*=!>\s*(.*)$/
|
80
|
+
{ type: :exception_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
81
|
+
when /^#\s*=<>\s*(.*)$/
|
82
|
+
{ type: :intentional_failure_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
83
|
+
when /^#\s*==>\s*(.*)$/
|
84
|
+
{ type: :true_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
85
|
+
when %r{^#\s*=/=>\s*(.*)$}
|
86
|
+
{ type: :false_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
87
|
+
when /^#\s*=\|>\s*(.*)$/
|
88
|
+
{ type: :boolean_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
89
|
+
when /^#\s*=:>\s*(.*)$/
|
90
|
+
{ type: :result_type_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
91
|
+
when /^#\s*=~>\s*(.*)$/
|
92
|
+
{ type: :regex_match_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
93
|
+
when /^#\s*=%>\s*(.*)$/
|
94
|
+
{ type: :performance_time_expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
95
|
+
when /^#\s*=(\d+)>\s*(.*)$/
|
96
|
+
{ type: :output_expectation, content: $2.strip, pipe: $1.to_i, line: line_number - 1, ast: parse_expectation($2.strip) }
|
97
|
+
when /^#\s*=>\s*(.*)$/
|
98
|
+
{ type: :expectation, content: $1.strip, line: line_number - 1, ast: parse_expectation($1.strip) }
|
99
|
+
when /^##\s*=>\s*(.*)$/
|
100
|
+
{ type: :comment, content: '=>' + $1.strip, line: line_number - 1 }
|
101
|
+
when /^#\s*(.*)$/
|
102
|
+
{ type: :potential_description, content: $1.strip, line: line_number - 1 }
|
103
|
+
else
|
104
|
+
{ type: :comment, content: content.sub(/^#\s*/, ''), line: line_number - 1 }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Parser type identification for metadata
|
109
|
+
def parser_type
|
110
|
+
:enhanced
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# lib/tryouts/parsers/prism_parser.rb
|
2
|
+
|
3
|
+
require_relative '../test_case'
|
4
|
+
require_relative 'base_parser'
|
5
|
+
|
6
|
+
class Tryouts
|
7
|
+
# Fixed PrismParser with pattern matching for robust token filtering
|
8
|
+
class PrismParser < Tryouts::Parsers::BaseParser
|
9
|
+
|
10
|
+
def parse
|
11
|
+
return handle_syntax_errors if @prism_result.failure?
|
12
|
+
|
13
|
+
tokens = tokenize_content
|
14
|
+
test_boundaries = find_test_case_boundaries(tokens)
|
15
|
+
tokens = classify_potential_descriptions_with_boundaries(tokens, test_boundaries)
|
16
|
+
test_blocks = group_into_test_blocks(tokens)
|
17
|
+
process_test_blocks(test_blocks)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Tokenize content using pattern matching for clean line classification
|
23
|
+
def tokenize_content
|
24
|
+
tokens = []
|
25
|
+
|
26
|
+
@lines.each_with_index do |line, index|
|
27
|
+
token = case line
|
28
|
+
in /^##\s*(.*)$/ # Test description format: ## description
|
29
|
+
{ type: :description, content: $1.strip, line: index }
|
30
|
+
in /^#\s*TEST\s*\d*:\s*(.*)$/ # rubocop:disable Lint/DuplicateBranch
|
31
|
+
{ type: :description, content: $1.strip, line: index }
|
32
|
+
in /^#\s*=!>\s*(.*)$/ # Exception expectation (updated for consistency)
|
33
|
+
{ type: :exception_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
34
|
+
in /^#\s*=<>\s*(.*)$/ # Intentional failure expectation
|
35
|
+
{ type: :intentional_failure_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
36
|
+
in /^#\s*==>\s*(.*)$/ # Boolean true expectation
|
37
|
+
{ type: :true_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
38
|
+
in %r{^#\s*=/=>\s*(.*)$} # Boolean false expectation
|
39
|
+
{ type: :false_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
40
|
+
in /^#\s*=\|>\s*(.*)$/ # Boolean (true or false) expectation
|
41
|
+
{ type: :boolean_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
42
|
+
in /^#\s*=:>\s*(.*)$/ # Result type expectation
|
43
|
+
{ type: :result_type_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
44
|
+
in /^#\s*=~>\s*(.*)$/ # Regex match expectation
|
45
|
+
{ type: :regex_match_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
46
|
+
in /^#\s*=%>\s*(.*)$/ # Performance time expectation
|
47
|
+
{ type: :performance_time_expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
48
|
+
in /^#\s*=(\d+)>\s*(.*)$/ # Output expectation (stdout/stderr with pipe number)
|
49
|
+
{ type: :output_expectation, content: $2.strip, pipe: $1.to_i, line: index, ast: parse_expectation($2.strip) }
|
50
|
+
in /^#\s*=>\s*(.*)$/ # Regular expectation
|
51
|
+
{ type: :expectation, content: $1.strip, line: index, ast: parse_expectation($1.strip) }
|
52
|
+
in /^##\s*=>\s*(.*)$/ # Commented out expectation (should be ignored)
|
53
|
+
{ type: :comment, content: '=>' + $1.strip, line: index }
|
54
|
+
in /^#\s*(.*)$/ # Single hash comment - potential description
|
55
|
+
{ type: :potential_description, content: $1.strip, line: index }
|
56
|
+
in /^\s*$/ # Blank line
|
57
|
+
{ type: :blank, line: index }
|
58
|
+
else # Ruby code
|
59
|
+
{ type: :code, content: line, line: index, ast: parse_ruby_line(line) }
|
60
|
+
end
|
61
|
+
|
62
|
+
tokens << token
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return tokens with potential_descriptions - they'll be classified later with test boundaries
|
66
|
+
tokens
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Convert potential_descriptions to descriptions or comments based on context
|
71
|
+
def classify_potential_descriptions(tokens)
|
72
|
+
tokens.map.with_index do |token, index|
|
73
|
+
if token[:type] == :potential_description
|
74
|
+
# Check if this looks like a test description based on content and context
|
75
|
+
content = token[:content].strip
|
76
|
+
|
77
|
+
# Skip if it's clearly just a regular comment (short, lowercase, etc.)
|
78
|
+
# Test descriptions are typically longer and more descriptive
|
79
|
+
looks_like_regular_comment = content.length < 20 &&
|
80
|
+
content.downcase == content &&
|
81
|
+
!content.match?(/test|example|demonstrate|show/i)
|
82
|
+
|
83
|
+
# Check if there's code immediately before this (suggesting it's mid-test)
|
84
|
+
prev_token = index > 0 ? tokens[index - 1] : nil
|
85
|
+
has_code_before = prev_token && prev_token[:type] == :code
|
86
|
+
|
87
|
+
if looks_like_regular_comment || has_code_before
|
88
|
+
# Treat as regular comment
|
89
|
+
token.merge(type: :comment)
|
90
|
+
else
|
91
|
+
# Look ahead for test pattern: code + at least one expectation within reasonable distance
|
92
|
+
following_tokens = tokens[(index + 1)..]
|
93
|
+
|
94
|
+
# Skip blanks and comments to find meaningful content
|
95
|
+
meaningful_following = following_tokens.reject { |t| [:blank, :comment].include?(t[:type]) }
|
96
|
+
|
97
|
+
# Look for test pattern: at least one code token followed by at least one expectation
|
98
|
+
# within the next 10 meaningful tokens (to avoid matching setup/teardown)
|
99
|
+
test_window = meaningful_following.first(10)
|
100
|
+
has_code = test_window.any? { |t| t[:type] == :code }
|
101
|
+
has_expectation = test_window.any? { |t| is_expectation_type?(t[:type]) }
|
102
|
+
|
103
|
+
if has_code && has_expectation
|
104
|
+
token.merge(type: :description)
|
105
|
+
else
|
106
|
+
token.merge(type: :comment)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
else
|
110
|
+
token
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Parser type identification for metadata
|
116
|
+
def parser_type
|
117
|
+
:prism_v2_fixed
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|