summaryrefslogtreecommitdiff
path: root/test/prism/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'test/prism/ruby')
-rw-r--r--test/prism/ruby/location_test.rb9
-rw-r--r--test/prism/ruby/parameters_signature_test.rb2
-rw-r--r--test/prism/ruby/parser_test.rb51
-rw-r--r--test/prism/ruby/ripper_test.rb108
-rw-r--r--test/prism/ruby/ruby_parser_test.rb45
5 files changed, 158 insertions, 57 deletions
diff --git a/test/prism/ruby/location_test.rb b/test/prism/ruby/location_test.rb
index 33f844243c..5e2ab63802 100644
--- a/test/prism/ruby/location_test.rb
+++ b/test/prism/ruby/location_test.rb
@@ -13,19 +13,22 @@ module Prism
assert_equal 0, joined.start_offset
assert_equal 10, joined.length
- assert_raise(RuntimeError, "Incompatible locations") do
+ e = assert_raise(RuntimeError) do
argument.location.join(receiver.location)
end
+ assert_equal "Incompatible locations", e.message
other_argument = Prism.parse_statement("1234 + 567").arguments.arguments.first
- assert_raise(RuntimeError, "Incompatible sources") do
+ e = assert_raise(RuntimeError) do
other_argument.location.join(receiver.location)
end
+ assert_equal "Incompatible sources", e.message
- assert_raise(RuntimeError, "Incompatible sources") do
+ e = assert_raise(RuntimeError) do
receiver.location.join(other_argument.location)
end
+ assert_equal "Incompatible sources", e.message
end
def test_character_offsets
diff --git a/test/prism/ruby/parameters_signature_test.rb b/test/prism/ruby/parameters_signature_test.rb
index af5b54ed91..ea1eea106b 100644
--- a/test/prism/ruby/parameters_signature_test.rb
+++ b/test/prism/ruby/parameters_signature_test.rb
@@ -54,7 +54,7 @@ module Prism
assert_parameters([[:keyrest, :**]], "**")
end
- if RUBY_ENGINE != "truffleruby"
+ if RUBY_ENGINE == "ruby"
def test_key_ordering
assert_parameters([[:keyreq, :a], [:keyreq, :b], [:key, :c], [:key, :d]], "a:, c: 1, b:, d: 2")
end
diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb
index cd52758f2e..55c12cab6f 100644
--- a/test/prism/ruby/parser_test.rb
+++ b/test/prism/ruby/parser_test.rb
@@ -5,8 +5,6 @@ require_relative "../test_helper"
begin
verbose, $VERBOSE = $VERBOSE, nil
require "parser/ruby33"
- require "prism/translation/parser33"
- require "prism/translation/parser34"
rescue LoadError
# In CRuby's CI, we're not going to test against the parser gem because we
# don't want to have to install it. So in this case we'll just skip this test.
@@ -62,8 +60,14 @@ module Prism
"alias.txt",
"seattlerb/bug_215.txt",
+ # %Q with newline delimiter and heredoc interpolation
+ "heredoc_percent_q_newline_delimiter.txt",
+
# 1.. && 2
"ranges.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
]
# These files contain code that is being parsed incorrectly by the parser
@@ -97,18 +101,11 @@ module Prism
# Regex with \c escape
"unescaping.txt",
"seattlerb/regexp_esc_C_slash.txt",
- ]
- # These files are either failing to parse or failing to translate, so we'll
- # skip them for now.
- skip_all = skip_incorrect | [
+ # https://github.com/whitequark/parser/issues/1084
+ "unary_method_calls.txt",
]
- # Not sure why these files are failing on JRuby, but skipping them for now.
- if RUBY_ENGINE == "jruby"
- skip_all.push("emoji_method_calls.txt", "symbols.txt")
- end
-
# These files are failing to translate their lexer output into the lexer
# output expected by the parser gem, so we'll skip them for now.
skip_tokens = [
@@ -143,11 +140,11 @@ module Prism
"whitequark/space_args_block.txt"
]
- Fixture.each(except: skip_syntax_error) do |fixture|
+ Fixture.each_for_version(except: skip_syntax_error, version: "3.3") do |fixture|
define_method(fixture.test_name) do
assert_equal_parses(
fixture,
- compare_asts: !skip_all.include?(fixture.path),
+ compare_asts: !skip_incorrect.include?(fixture.path),
compare_tokens: !skip_tokens.include?(fixture.path),
compare_comments: fixture.path != "embdoc_no_newline_at_end.txt"
)
@@ -166,24 +163,44 @@ module Prism
if RUBY_VERSION >= "3.3"
def test_current_parser_for_current_ruby
- major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
+ major, minor = CURRENT_MAJOR_MINOR.split(".")
# Let's just hope there never is a Ruby 3.10 or similar
- expected = major * 10 + minor
+ expected = major.to_i * 10 + minor.to_i
assert_equal(expected, Translation::ParserCurrent.new.version)
end
end
+ def test_invalid_syntax
+ code = <<~RUBY
+ foo do
+ case bar
+ when
+ end
+ end
+ RUBY
+ buffer = Parser::Source::Buffer.new("(string)")
+ buffer.source = code
+
+ parser = Prism::Translation::Parser33.new
+ parser.diagnostics.all_errors_are_fatal = true
+ assert_raise(Parser::SyntaxError) { parser.tokenize(buffer) }
+ end
+
def test_it_block_parameter_syntax
- it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/it.txt")
+ it_fixture_path = Pathname(__dir__).join("../../../test/prism/fixtures/3.4/it.txt")
buffer = Parser::Source::Buffer.new(it_fixture_path)
buffer.source = it_fixture_path.read
actual_ast = Prism::Translation::Parser34.new.tokenize(buffer)[0]
it_block_parameter_sexp = parse_sexp {
+ s(:begin,
s(:itblock,
s(:send, nil, :x), :it,
- s(:lvar, :it))
+ s(:lvar, :it)),
+ s(:itblock,
+ s(:lambda), :it,
+ s(:lvar, :it)))
}
assert_equal(it_block_parameter_sexp, actual_ast.to_sexp)
diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb
index d4b278c28e..2a0504c19f 100644
--- a/test/prism/ruby/ripper_test.rb
+++ b/test/prism/ruby/ripper_test.rb
@@ -1,36 +1,44 @@
# frozen_string_literal: true
-return if RUBY_VERSION < "3.3" || RUBY_ENGINE == "truffleruby"
+return if RUBY_VERSION < "3.3" || RUBY_ENGINE != "ruby"
require_relative "../test_helper"
+require "ripper"
module Prism
class RipperTest < TestCase
# Skip these tests that Ripper is reporting the wrong results for.
incorrect = [
# Ripper incorrectly attributes the block to the keyword.
- "seattlerb/block_break.txt",
- "seattlerb/block_next.txt",
"seattlerb/block_return.txt",
- "whitequark/break_block.txt",
- "whitequark/next_block.txt",
"whitequark/return_block.txt",
- # Ripper is not accounting for locals created by patterns using the **
- # operator within an `in` clause.
- "seattlerb/parse_pattern_058.txt",
-
# Ripper cannot handle named capture groups in regular expressions.
"regex.txt",
- "regex_char_width.txt",
- "whitequark/lvar_injecting_match.txt",
# Ripper fails to understand some structures that span across heredocs.
- "spanning_heredoc.txt"
+ "spanning_heredoc.txt",
+
+ # Ripper interprets circular keyword arguments as method calls.
+ "3.4/circular_parameters.txt",
+
+ # Ripper doesn't emit `args_add_block` when endless method is prefixed by modifier.
+ "4.0/endless_methods_command_call.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
]
+ if RUBY_VERSION.start_with?("3.3.")
+ incorrect += [
+ "whitequark/lvar_injecting_match.txt",
+ "seattlerb/parse_pattern_058.txt",
+ "regex_char_width.txt",
+ ]
+ end
+
# Skip these tests that we haven't implemented yet.
- omitted = [
+ omitted_sexp_raw = [
"dos_endings.txt",
"heredocs_with_fake_newlines.txt",
"heredocs_with_ignored_newlines.txt",
@@ -51,14 +59,82 @@ module Prism
"whitequark/slash_newline_in_heredocs.txt"
]
- Fixture.each(except: incorrect | omitted) do |fixture|
- define_method(fixture.test_name) { assert_ripper(fixture.read) }
+ omitted_lex = [
+ "comments.txt",
+ "heredoc_percent_q_newline_delimiter.txt",
+ "heredoc_with_escaped_newline_at_start.txt",
+ "heredocs_with_fake_newlines.txt",
+ "indented_file_end.txt",
+ "seattlerb/TestRubyParserShared.txt",
+ "seattlerb/class_comments.txt",
+ "seattlerb/module_comments.txt",
+ "seattlerb/parse_line_block_inline_comment_leading_newlines.txt",
+ "seattlerb/parse_line_block_inline_multiline_comment.txt",
+ "spanning_heredoc_newlines.txt",
+ "strings.txt",
+ "whitequark/dedenting_heredoc.txt",
+ "whitequark/procarg0.txt",
+ ]
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_sexp_raw) do |fixture|
+ define_method("#{fixture.test_name}_sexp_raw") { assert_ripper_sexp_raw(fixture.read) }
+ end
+
+ Fixture.each_for_current_ruby(except: incorrect | omitted_lex) do |fixture|
+ define_method("#{fixture.test_name}_lex") { assert_ripper_lex(fixture.read) }
+ end
+
+ def test_lexer
+ lexer = Translation::Ripper::Lexer.new("foo")
+ expected = [[1, 0], :on_ident, "foo", Translation::Ripper::EXPR_CMDARG]
+
+ assert_equal([expected], lexer.lex)
+ assert_equal(expected, lexer.parse[0].to_a)
+ assert_equal(lexer.parse[0].to_a, lexer.scan[0].to_a)
+
+ assert_equal(%i[on_int on_op], Translation::Ripper::Lexer.new("1 +").lex.map(&:event))
+ assert_raise(SyntaxError) { Translation::Ripper::Lexer.new("1 +").lex(raise_errors: true) }
+ end
+
+ def test_tokenize
+ source = "foo;1;BAZ"
+ assert_equal(Ripper.tokenize(source), Translation::Ripper.tokenize(source))
+ end
+
+ # Check that the hardcoded values don't change without us noticing.
+ def test_internals
+ actual = Translation::Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+ expected = Ripper.constants.select { |name| name.start_with?("EXPR_") }.sort
+
+ assert_equal(expected, actual)
+ expected.zip(actual).each do |ripper, prism|
+ assert_equal(Ripper.const_get(ripper), Translation::Ripper.const_get(prism))
+ end
end
private
- def assert_ripper(source)
+ def assert_ripper_sexp_raw(source)
assert_equal Ripper.sexp_raw(source), Prism::Translation::Ripper.sexp_raw(source)
end
+
+ def assert_ripper_lex(source)
+ prism = Translation::Ripper.lex(source)
+ ripper = Ripper.lex(source)
+ ripper.reject! { |elem| elem[1] == :on_sp } # Prism doesn't emit on_sp
+ ripper.sort_by! { |elem| elem[0] } # Prism emits tokens by their order in the code, not in parse order
+
+ [prism.size, ripper.size].max.times do |i|
+ expected = ripper[i]
+ actual = prism[i]
+ # Since tokens related to heredocs are not emitted in the same order,
+ # the state also doesn't line up.
+ if expected[1] == :on_heredoc_end && actual[1] == :on_heredoc_end
+ expected[3] = actual[3] = nil
+ end
+
+ assert_equal(expected, actual)
+ end
+ end
end
end
diff --git a/test/prism/ruby/ruby_parser_test.rb b/test/prism/ruby/ruby_parser_test.rb
index 03bcfafc42..4b7e9c93ed 100644
--- a/test/prism/ruby/ruby_parser_test.rb
+++ b/test/prism/ruby/ruby_parser_test.rb
@@ -13,23 +13,12 @@ rescue LoadError
return
end
-# We want to also compare lines and files to make sure we're setting them
-# correctly.
-Sexp.prepend(
- Module.new do
- def ==(other)
- super && line == other.line && file == other.file # && line_max == other.line_max
- end
- end
-)
-
module Prism
class RubyParserTest < TestCase
todos = [
+ "character_literal.txt",
"encoding_euc_jp.txt",
- "newline_terminated.txt",
"regex_char_width.txt",
- "seattlerb/bug169.txt",
"seattlerb/masgn_colon3.txt",
"seattlerb/messy_op_asgn_lineno.txt",
"seattlerb/op_asgn_primary_colon_const_command_call.txt",
@@ -37,15 +26,10 @@ module Prism
"seattlerb/str_lit_concat_bad_encodings.txt",
"strings.txt",
"unescaping.txt",
- "unparser/corpus/literal/kwbegin.txt",
- "unparser/corpus/literal/send.txt",
"whitequark/masgn_const.txt",
"whitequark/pattern_matching_constants.txt",
- "whitequark/pattern_matching_implicit_array_match.txt",
"whitequark/pattern_matching_single_match.txt",
"whitequark/ruby_bug_12402.txt",
- "whitequark/ruby_bug_14690.txt",
- "whitequark/space_args_block.txt"
]
# https://github.com/seattlerb/ruby_parser/issues/344
@@ -53,6 +37,7 @@ module Prism
"alias.txt",
"dsym_str.txt",
"dos_endings.txt",
+ "heredoc_percent_q_newline_delimiter.txt",
"heredocs_with_fake_newlines.txt",
"heredocs_with_ignored_newlines.txt",
"method_calls.txt",
@@ -73,6 +58,7 @@ module Prism
"spanning_heredoc.txt",
"symbols.txt",
"tilde_heredocs.txt",
+ "unary_method_calls.txt",
"unparser/corpus/literal/literal.txt",
"while.txt",
"whitequark/cond_eflipflop.txt",
@@ -90,7 +76,20 @@ module Prism
"whitequark/ruby_bug_11989.txt",
"whitequark/ruby_bug_18878.txt",
"whitequark/ruby_bug_19281.txt",
- "whitequark/slash_newline_in_heredocs.txt"
+ "whitequark/slash_newline_in_heredocs.txt",
+
+ "3.3-3.3/block_args_in_array_assignment.txt",
+ "3.3-3.3/it_with_ordinary_parameter.txt",
+ "3.3-3.3/keyword_args_in_array_assignment.txt",
+ "3.3-3.3/return_in_sclass.txt",
+
+ "3.4/circular_parameters.txt",
+
+ "4.0/endless_methods_command_call.txt",
+ "4.0/leading_logical.txt",
+
+ # https://bugs.ruby-lang.org/issues/21168#note-5
+ "command_method_call_2.txt",
]
Fixture.each(except: failures) do |fixture|
@@ -105,10 +104,16 @@ module Prism
source = fixture.read
expected = ignore_warnings { ::RubyParser.new.parse(source, fixture.path) }
actual = Prism::Translation::RubyParser.new.parse(source, fixture.path)
+ on_failure = -> { message(expected, actual) }
if !allowed_failure
- assert_equal(expected, actual, -> { message(expected, actual) })
- elsif expected == actual
+ assert_equal(expected, actual, on_failure)
+
+ unless actual.nil?
+ assert_equal(expected.line, actual.line, on_failure)
+ assert_equal(expected.file, actual.file, on_failure)
+ end
+ elsif expected == actual && expected.line && actual.line && expected.file == actual.file
puts "#{name} now passes"
end
end