summaryrefslogtreecommitdiff
path: root/test/ripper
diff options
context:
space:
mode:
Diffstat (limited to 'test/ripper')
-rw-r--r--test/ripper/assert_parse_files.rb25
-rw-r--r--test/ripper/dummyparser.rb53
-rw-r--r--test/ripper/test_lexer.rb108
-rw-r--r--test/ripper/test_parser_events.rb94
-rw-r--r--test/ripper/test_ripper.rb39
-rw-r--r--test/ripper/test_scanner_events.rb37
-rw-r--r--test/ripper/test_sexp.rb54
7 files changed, 357 insertions, 53 deletions
diff --git a/test/ripper/assert_parse_files.rb b/test/ripper/assert_parse_files.rb
index 85d20cf69e..0d583a99e3 100644
--- a/test/ripper/assert_parse_files.rb
+++ b/test/ripper/assert_parse_files.rb
@@ -5,26 +5,39 @@ module TestRipper; end
class TestRipper::Generic < Test::Unit::TestCase
SRCDIR = File.expand_path("../../..", __FILE__)
- def assert_parse_files(dir, pattern = "**/*.rb")
- assert_separately(%W[--disable-gem -rripper - #{SRCDIR}/#{dir} #{pattern}],
+ def assert_parse_files(dir, pattern = "**/*.rb", exclude: nil, gc_stress: GC.stress, test_ratio: nil)
+ test_ratio ||= ENV["TEST_RIPPER_RATIO"]&.tap {|s|break s.to_f} || 0.05 # testing all files needs too long time...
+ assert_separately(%W[-rripper - #{SRCDIR}/#{dir} #{pattern}],
__FILE__, __LINE__, "#{<<-"begin;"}\n#{<<-'end;'}", timeout: Float::INFINITY)
+ GC.stress = false
pattern = "#{pattern}"
+ exclude = (
+ #{exclude if exclude}
+ )
+ test_ratio = (
+ #{test_ratio}
+ )
+ gc_stress = (
+ #{gc_stress}
+ )
begin;
- TEST_RATIO = ENV["TEST_RIPPER_RATIO"]&.tap {|s|break s.to_f} || 0.05 # testing all files needs too long time...
class Parser < Ripper
PARSER_EVENTS.each {|n| eval "def on_#{n}(*args) r = [:#{n}, *args]; r.inspect; Object.new end" }
SCANNER_EVENTS.each {|n| eval "def on_#{n}(*args) r = [:#{n}, *args]; r.inspect; Object.new end" }
end
dir = ARGV.shift
- scripts = Dir.chdir(dir) {Dir[pattern]}
- if (1...scripts.size).include?(num = scripts.size * TEST_RATIO)
+ scripts = Dir.glob(pattern, base: dir)
+ scripts.reject! {|script| File.fnmatch?(exclude, script, File::FNM_PATHNAME)} if exclude
+ if (1...scripts.size).include?(num = scripts.size * test_ratio)
scripts = scripts.sample(num)
end
scripts.sort!
for script in scripts
assert_nothing_raised {
parser = Parser.new(File.read("#{dir}/#{script}"), script)
- parser.instance_eval "parse", "<#{script}>"
+ EnvUtil.under_gc_stress(gc_stress) do
+ parser.instance_eval "parse", "<#{script}>"
+ end
}
end
end;
diff --git a/test/ripper/dummyparser.rb b/test/ripper/dummyparser.rb
index fa834bd0f7..ef5ea49b1f 100644
--- a/test/ripper/dummyparser.rb
+++ b/test/ripper/dummyparser.rb
@@ -4,8 +4,9 @@
#
require 'ripper'
+module TestRipper; end
-class Node
+class TestRipper::Node
def initialize(name, *nodes)
@name = name
@children = nodes
@@ -14,7 +15,7 @@ class Node
attr_reader :name, :children
def to_s
- "#{@name}(#{Node.trim_nil(@children).map {|n| n.to_s }.join(',')})"
+ "#{@name}(#{TestRipper::Node.trim_nil(@children).map {|n| n.to_s }.join(',')})"
end
def self.trim_nil(list)
@@ -36,7 +37,7 @@ class Node
end
end
-class NodeList
+class TestRipper::NodeList
def initialize(list = [])
@list = list
end
@@ -62,7 +63,7 @@ class NodeList
end
end
-class DummyParser < Ripper
+class TestRipper::DummyParser < Ripper
def hook(*names)
class << self; self; end.class_eval do
names.each do |name|
@@ -81,7 +82,7 @@ class DummyParser < Ripper
end
def on_stmts_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_stmts_add(stmts, st)
@@ -90,23 +91,23 @@ class DummyParser < Ripper
end
def on_void_stmt
- Node.new('void')
+ TestRipper::Node.new('void')
end
def on_var_ref(name)
- Node.new('ref', name)
+ TestRipper::Node.new('ref', name)
end
def on_var_alias(a, b)
- Node.new('valias', a, b)
+ TestRipper::Node.new('valias', a, b)
end
def on_assign_error(mesg = nil, a)
- Node.new('assign_error', a)
+ TestRipper::Node.new('assign_error', a)
end
def on_alias_error(mesg = nil, a)
- Node.new('aliaserr', a)
+ TestRipper::Node.new('aliaserr', a)
end
def on_arg_paren(args)
@@ -114,7 +115,7 @@ class DummyParser < Ripper
end
def on_args_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_args_add(list, arg)
@@ -156,7 +157,7 @@ class DummyParser < Ripper
end
def on_brace_block(params, code)
- Node.new('block', params, code)
+ TestRipper::Node.new('block', params, code)
end
def on_block_var(params, shadow)
@@ -176,7 +177,7 @@ class DummyParser < Ripper
end
def on_params(required, optional, rest, more, keyword, keyword_rest, block)
- args = NodeList.new
+ args = TestRipper::NodeList.new
required.each do |req|
args.push(req)
@@ -197,15 +198,15 @@ class DummyParser < Ripper
end
def on_assoc_new(a, b)
- Node.new('assoc', a, b)
+ TestRipper::Node.new('assoc', a, b)
end
def on_bare_assoc_hash(assoc_list)
- Node.new('assocs', *assoc_list)
+ TestRipper::Node.new('assocs', *assoc_list)
end
def on_assoclist_from_args(a)
- Node.new('assocs', *a)
+ TestRipper::Node.new('assocs', *a)
end
def on_word_new
@@ -217,7 +218,7 @@ class DummyParser < Ripper
end
def on_words_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_words_add(words, word)
@@ -225,7 +226,7 @@ class DummyParser < Ripper
end
def on_qwords_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_qwords_add(words, word)
@@ -233,27 +234,27 @@ class DummyParser < Ripper
end
def on_symbols_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_symbols_add(symbols, symbol)
- symbols.push Node::Sym.new(symbol)
+ symbols.push TestRipper::Node::Sym.new(symbol)
end
def on_qsymbols_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_qsymbols_add(symbols, symbol)
- symbols.push Node::Sym.new(symbol)
+ symbols.push TestRipper::Node::Sym.new(symbol)
end
def on_mlhs_new
- NodeList.new
+ TestRipper::NodeList.new
end
def on_mlhs_paren(list)
- Node.new(:mlhs, list)
+ TestRipper::Node.new(:mlhs, list)
end
def on_mlhs_add(list, node)
@@ -277,12 +278,12 @@ class DummyParser < Ripper
end
def on_rescue(exc, *rest)
- Node.new('rescue', (exc && NodeList.new(exc)), *rest)
+ TestRipper::Node.new('rescue', (exc && TestRipper::NodeList.new(exc)), *rest)
end
(Ripper::PARSER_EVENTS.map(&:to_s) - instance_methods(false).map {|n|n.to_s.sub(/^on_/, '')}).each do |event|
define_method(:"on_#{event}") do |*args|
- Node.new(event, *args)
+ TestRipper::Node.new(event, *args)
end
end
end
diff --git a/test/ripper/test_lexer.rb b/test/ripper/test_lexer.rb
index 83130668be..7d62a7ee28 100644
--- a/test/ripper/test_lexer.rb
+++ b/test/ripper/test_lexer.rb
@@ -100,6 +100,20 @@ class TestRipper::Lexer < Test::Unit::TestCase
assert_equal expect, Ripper.lex(src).map {|e| e[1]}
end
+ def test_end_of_script_char
+ all_assertions do |all|
+ ["a", %w"[a ]", %w"{, }", "if"].each do |src, append|
+ expected = Ripper.lex(src).map {|e| e[1]}
+ ["\0b", "\4b", "\32b"].each do |eof|
+ c = "#{src}#{eof}#{append}"
+ all.for(c) do
+ assert_equal expected, Ripper.lex(c).map {|e| e[1]}
+ end
+ end
+ end
+ end
+ end
+
def test_slice
assert_equal "string\#{nil}\n",
Ripper.slice(%(<<HERE\nstring\#{nil}\nHERE), "heredoc_beg .*? nl $(.*?) heredoc_end", 1)
@@ -157,7 +171,7 @@ class TestRipper::Lexer < Test::Unit::TestCase
end
BAD_CODE = [
- [:parse_error, 'def req(true) end', %r[unexpected `true'], 'true'],
+ [:parse_error, 'def req(true) end', %r[unexpected 'true'], 'true'],
[:parse_error, 'def req(a, a) end', %r[duplicated argument name], 'a'],
[:assign_error, 'begin; nil = 1; end', %r[assign to nil], 'nil'],
[:alias_error, 'begin; alias $x $1; end', %r[number variables], '$1'],
@@ -228,4 +242,96 @@ class TestRipper::Lexer < Test::Unit::TestCase
EOF
assert_equal([[5, 0], :on_heredoc_end, "EOS\n", state(:EXPR_BEG)], Ripper.lex(s).last, bug)
end
+
+ def test_tokenize_with_here_document
+ bug = '[Bug #18963]'
+ code = %[
+<<A + "hello
+A
+world"
+]
+ assert_equal(code, Ripper.tokenize(code).join(""), bug)
+ end
+
+ def test_heredoc_inside_block_param
+ bug = '[Bug #19399]'
+ code = <<~CODE
+ a do |b
+ <<-C
+ C
+ |
+ end
+ CODE
+ assert_equal(code, Ripper.tokenize(code).join(""), bug)
+ end
+
+ def test_heredoc_unterminated_interpolation
+ code = <<~'HEREDOC'
+ <<A+1
+ #{
+ HEREDOC
+
+ assert_include(Ripper.tokenize(code).join(""), "+1")
+ end
+
+ def test_nested_heredoc
+ code = <<~'HEREDOC'
+ <<~H1
+ 1
+ #{<<~H2}
+ 2
+ H2
+ 3
+ H1
+ HEREDOC
+
+ expected = [
+ [[1, 0], :on_heredoc_beg, "<<~H1", state(:EXPR_BEG)],
+ [[1, 5], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_ignored_sp, " ", state(:EXPR_BEG)],
+ [[2, 2], :on_tstring_content, "1\n", state(:EXPR_BEG)],
+ [[3, 0], :on_ignored_sp, " ", state(:EXPR_BEG)],
+ [[3, 2], :on_embexpr_beg, "\#{", state(:EXPR_BEG)],
+ [[3, 4], :on_heredoc_beg, "<<~H2", state(:EXPR_BEG)],
+ [[3, 9], :on_embexpr_end, "}", state(:EXPR_END)],
+ [[3, 10], :on_tstring_content, "\n", state(:EXPR_BEG)],
+ [[4, 0], :on_ignored_sp, " ", state(:EXPR_BEG)],
+ [[4, 4], :on_tstring_content, "2\n", state(:EXPR_BEG)],
+ [[5, 0], :on_heredoc_end, " H2\n", state(:EXPR_BEG)],
+ [[6, 0], :on_ignored_sp, " ", state(:EXPR_BEG)],
+ [[6, 2], :on_tstring_content, "3\n", state(:EXPR_BEG)],
+ [[7, 0], :on_heredoc_end, "H1\n", state(:EXPR_BEG)],
+ ]
+ assert_equal(code, Ripper.tokenize(code).join(""))
+ assert_equal(expected, result = Ripper.lex(code),
+ proc {expected.zip(result) {|e, r| break diff(e, r) unless e == r}})
+
+ code = <<~'HEREDOC'
+ <<-H1
+ 1
+ #{<<~H2}
+ 2
+ H2
+ 3
+ H1
+ HEREDOC
+
+ expected = [
+ [[1, 0], :on_heredoc_beg, "<<-H1", state(:EXPR_BEG)],
+ [[1, 5], :on_nl, "\n", state(:EXPR_BEG)],
+ [[2, 0], :on_tstring_content, " 1\n ", state(:EXPR_BEG)],
+ [[3, 2], :on_embexpr_beg, "\#{", state(:EXPR_BEG)],
+ [[3, 4], :on_heredoc_beg, "<<~H2", state(:EXPR_BEG)],
+ [[3, 9], :on_embexpr_end, "}", state(:EXPR_END)],
+ [[3, 10], :on_tstring_content, "\n", state(:EXPR_BEG)],
+ [[4, 0], :on_ignored_sp, " ", state(:EXPR_BEG)],
+ [[4, 4], :on_tstring_content, "2\n", state(:EXPR_BEG)],
+ [[5, 0], :on_heredoc_end, " H2\n", state(:EXPR_BEG)],
+ [[6, 0], :on_tstring_content, " 3\n", state(:EXPR_BEG)],
+ [[7, 0], :on_heredoc_end, "H1\n", state(:EXPR_BEG)],
+ ]
+ assert_equal(code, Ripper.tokenize(code).join(""))
+ assert_equal(expected, result = Ripper.lex(code),
+ proc {expected.zip(result) {|e, r| break diff(e, r) unless e == r}})
+ end
end
diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb
index 5bb8f120f2..cbae6e7ed5 100644
--- a/test/ripper/test_parser_events.rb
+++ b/test/ripper/test_parser_events.rb
@@ -16,7 +16,7 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
end
def parse(str, nm = nil, &bl)
- dp = DummyParser.new(str)
+ dp = TestRipper::DummyParser.new(str)
dp.hook(*nm, &bl) if nm
dp.parse.to_s
end
@@ -152,6 +152,45 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
thru_args_forward = false
parse(code, :on_args_forward) {thru_args_forward = true}
assert_equal true, thru_args_forward, "no args_forward for: #{code}"
+ parse(code, :on_params) {|*, block| assert_nil(block)}
+ end
+ end
+
+ def test_anonymous_block_forwarding
+ thru_args_add_block = false
+ parse('def b(&); c(&); end', :on_args_add_block) {thru_args_add_block = true}
+ assert_equal true, thru_args_add_block
+ assert_match "no anonymous block parameter", compile_error('def b; c(&); end')
+ end
+
+ def test_anonymous_rest_forwarding
+ [
+ 'c(*)',
+ 'c(*, *)',
+ ].each do |code|
+ thru_args_add_star = false
+ src = "def b(*); #{code} end"
+ parse(src, :on_args_add_star) {thru_args_add_star = true}
+ assert_equal true, thru_args_add_star, src
+
+ src = "def b; #{code} end"
+ assert_match "no anonymous rest parameter", compile_error(src), src
+ end
+ end
+
+ def test_anonymous_keyword_rest_forwarding
+ [
+ 'c(**)',
+ 'c(k: 1, **)',
+ 'c(**, k: 1)',
+ ].each do |code|
+ thru_assoc_splat = false
+ src = "def b(**); #{code} end"
+ parse(src, :on_assoc_splat) {thru_assoc_splat = true}
+ assert_equal true, thru_assoc_splat, src
+
+ src = "def b; #{code} end"
+ assert_match "no anonymous keyword rest parameter", compile_error(src), src
end
end
@@ -461,6 +500,23 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
assert_equal "[call(ref(self),&.,foo,[])]", tree
end
+ def test_call_colon2
+ hook = Module.new do
+ def on_op(op)
+ super("(op: #{op.inspect})")
+ end
+ def on_call(recv, name, *args)
+ super(recv, "(method: #{name})", *args)
+ end
+ def on_ident(name)
+ super("(ident: #{name.inspect})")
+ end
+ end
+
+ parser = TestRipper::DummyParser.new("a::b").extend(hook)
+ assert_equal '[call(vcall((ident: "a")),(method: (op: "::")),(ident: "b"))]', parser.parse.to_s
+ end
+
def test_excessed_comma
thru_excessed_comma = false
parse("proc{|x,|}", :on_excessed_comma) {thru_excessed_comma = true}
@@ -1588,20 +1644,20 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
end
def test_invalid_instance_variable_name
- assert_equal("`@1' is not allowed as an instance variable name", compile_error('proc{@1}'))
- assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@%'))
- assert_equal("`@' without identifiers is not allowed as an instance variable name", compile_error('@'))
+ assert_equal("'@1' is not allowed as an instance variable name", compile_error('proc{@1}'))
+ assert_equal("'@' without identifiers is not allowed as an instance variable name", compile_error('@%'))
+ assert_equal("'@' without identifiers is not allowed as an instance variable name", compile_error('@'))
end
def test_invalid_class_variable_name
- assert_equal("`@@1' is not allowed as a class variable name", compile_error('@@1'))
- assert_equal("`@@' without identifiers is not allowed as a class variable name", compile_error('@@%'))
- assert_equal("`@@' without identifiers is not allowed as a class variable name", compile_error('@@'))
+ assert_equal("'@@1' is not allowed as a class variable name", compile_error('@@1'))
+ assert_equal("'@@' without identifiers is not allowed as a class variable name", compile_error('@@%'))
+ assert_equal("'@@' without identifiers is not allowed as a class variable name", compile_error('@@'))
end
def test_invalid_global_variable_name
- assert_equal("`$%' is not allowed as a global variable name", compile_error('$%'))
- assert_equal("`$' without identifiers is not allowed as a global variable name", compile_error('$'))
+ assert_equal("'$%' is not allowed as a global variable name", compile_error('$%'))
+ assert_equal("'$' without identifiers is not allowed as a global variable name", compile_error('$'))
end
def test_warning_ignored_magic_comment
@@ -1616,6 +1672,26 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
assert_equal(%w"frozen_string_literal nottrue", args)
end
+ def test_warning_duplicated_when_clause
+ fmt, *args = warning(<<~STR)
+ a = 1
+ case a
+ when 1
+ when 1
+ when 2
+ else
+ end
+ STR
+ assert_match(/duplicated 'when' clause/, fmt)
+ assert_equal([3], args)
+ end
+
+ def test_warn_duplicated_hash_keys
+ fmt, *args = warn("{ a: 1, a: 2 }")
+ assert_match(/is duplicated and overwritten on line/, fmt)
+ assert_equal([:a, 1], args)
+ end
+
def test_warn_cr_in_middle
fmt = nil
assert_warn("") {fmt, = warn("\r;")}
diff --git a/test/ripper/test_ripper.rb b/test/ripper/test_ripper.rb
index 76276c54ef..f129a41be9 100644
--- a/test/ripper/test_ripper.rb
+++ b/test/ripper/test_ripper.rb
@@ -14,6 +14,13 @@ class TestRipper::Ripper < Test::Unit::TestCase
@ripper = Ripper.new '1 + 1'
end
+ def test_new
+ assert_separately(%w[-rripper], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ assert_nil EnvUtil.under_gc_stress {Ripper.new("")}.state
+ end;
+ end
+
def test_column
assert_nil @ripper.column
end
@@ -81,7 +88,7 @@ class TestRipper::Ripper < Test::Unit::TestCase
ripper.yydebug = true
ripper.debug_output = out
ripper.parse
- assert_include out.string[/.*"literal content".*/], 'woot'
+ assert_include out.string[/.*"literal content".*/], '1.1-1.5'
end
def test_regexp_with_option
@@ -141,6 +148,36 @@ end
assert_nothing_raised { Ripper.lex src }
end
+ def test_no_memory_leak
+ assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true)
+ 2_000_000.times do
+ Ripper.parse("")
+ end
+ end;
+
+ # [Bug #19835]
+ assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true)
+ 1_000_000.times do
+ Ripper.parse("class Foo")
+ end
+ end;
+
+ # [Bug #19836]
+ assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true)
+ 1_000_000.times do
+ Ripper.parse("-> {")
+ end
+ end;
+ end
+
+ def test_sexp_no_memory_leak
+ assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true)
+ 1_000_000.times do
+ Ripper.sexp("")
+ end
+ end;
+ end
+
class TestInput < self
Input = Struct.new(:lines) do
def gets
diff --git a/test/ripper/test_scanner_events.rb b/test/ripper/test_scanner_events.rb
index 13bd44e83d..792f19ef1a 100644
--- a/test/ripper/test_scanner_events.rb
+++ b/test/ripper/test_scanner_events.rb
@@ -113,11 +113,11 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
[[5, 0], :on_imaginary, "5.6ri", Ripper::EXPR_END],
],
Ripper.lex("1r\n2i\n3ri\n4.2r\n5.6ri")
- assert_lex [[[1, 0], :on_heredoc_beg, "<<~EOS", Ripper::EXPR_BEG],
- [[1, 6], :on_nl, "\n", Ripper::EXPR_BEG],
- [[2, 0], :on_ignored_sp, " ", Ripper::EXPR_BEG],
- [[2, 2], :on_tstring_content, "heredoc\n", Ripper::EXPR_BEG],
- [[3, 0], :on_heredoc_end, "EOS", Ripper::EXPR_BEG]
+ assert_lex [[[1, 0], :on_heredoc_beg, "<<~EOS", Ripper::EXPR_BEG],
+ [[1, 6], :on_nl, "\n", Ripper::EXPR_BEG],
+ [[2, 0], :on_ignored_sp, " ", Ripper::EXPR_BEG],
+ [[2, 2], :on_tstring_content, "heredoc\n", Ripper::EXPR_BEG],
+ [[3, 0], :on_heredoc_end, "EOS", Ripper::EXPR_BEG]
],
Ripper.lex("<<~EOS\n heredoc\nEOS")
assert_lex [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG],
@@ -179,6 +179,11 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('backtick', %q[p `make all`])
end
+ def test_colon2_call
+ assert_equal ["::"],
+ scan('op', %q[ a::b ])
+ end
+
def test_comma
assert_equal [','] * 6,
scan('comma', %q[ m(0,1,2,3,4,5,6) ])
@@ -712,7 +717,7 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('words_sep', '%w( w w w )')
assert_equal [' ', "\n", ' ', ' '],
scan('words_sep', "%w( w\nw w )")
- assert_equal ["\n\n", "\n ", ' ', ' '],
+ assert_equal ["\n", "\n", "\n", ' ', ' ', ' '],
scan('words_sep', "%w(\n\nw\n w w )")
end
@@ -986,13 +991,27 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
assert_equal("\e", err[2])
end
- def test_invalid_hex_escape
+ def test_invalid_escape
+ err = nil
+ assert_equal ["\\C-\u{3042}"], scan('tstring_content', %["\\C-\u{3042}"]) {|*e| err = e}
+ assert_equal [:on_parse_error, "Invalid escape character syntax", "\\C-\u{3042}"], err
+ end
+
+ def test_invalid_hex_escape_string
err = nil
- assert_equal ['U'], scan('tstring_content', '"\\xU"') {|*e| err = e}
+ assert_equal ['\\x', 'U'], scan('tstring_content', '"\\xU"') {|*e| err = e}
assert_equal [:on_parse_error, "invalid hex escape", "\\x"], err
+ end
+ def test_invalid_hex_escape_regexp
err = nil
- assert_equal ['U'], scan('tstring_content', '/\\xU/') {|*e| err = e}
+ assert_equal ['\\x', 'U'], scan('tstring_content', '/\\xU/') {|*e| err = e}
assert_equal [:on_parse_error, "invalid hex escape", "\\x"], err
end
+
+ def test_error_token
+ src = "{a:,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n""hello}"
+ err = scan('parse_error', src) {|*e| break e}
+ assert_equal "", err[2]
+ end
end if ripper_test
diff --git a/test/ripper/test_sexp.rb b/test/ripper/test_sexp.rb
index 9faeaba782..3ebcf3062e 100644
--- a/test/ripper/test_sexp.rb
+++ b/test/ripper/test_sexp.rb
@@ -18,6 +18,11 @@ class TestRipper::Sexp < Test::Unit::TestCase
assert_nil Ripper.sexp("/*")
assert_nil Ripper.sexp("/*/")
assert_nil Ripper.sexp("/+/")
+ assert_nil Ripper.sexp("m(&nil) {}"), '[Bug #10436]'
+ assert_nil Ripper.sexp("/(?<a>)/ =~ ''; x = a **a, **a if false"), '[Bug #18988]'
+ assert_nil Ripper.sexp("return + return"), '[Bug #20055]'
+ assert_nil Ripper.sexp("1 in [a, a]"), '[Bug #20055]'
+ assert_nil Ripper.sexp("1 + (1 => [a, a])"), '[Bug #20055]'
end
def test_regexp_content
@@ -34,6 +39,14 @@ class TestRipper::Sexp < Test::Unit::TestCase
assert_equal '(?<n>a(b|\g<n>))', search_sexp(:@tstring_content, search_sexp(:regexp_literal, sexp))[1]
end
+ def test_regexp_named_capture
+ sexp = Ripper.sexp("/(?<a>)/ =~ ''; x = a **a, a if false")
+ assert_not_nil sexp, '[Bug #18988]'
+
+ sexp = Ripper.sexp("/(?<a>)/ =~ ''; a %(exit)")
+ assert_equal 'exit', search_sexp(:@ident, search_sexp(:paren, sexp))[1], '[Bug #18988]'
+ end
+
def test_heredoc_content
sexp = Ripper.sexp("<<E\nfoo\nE")
assert_equal "foo\n", search_sexp(:@tstring_content, sexp)[1]
@@ -110,6 +123,21 @@ eot
assert_equal(exp, named)
end
+ def test_command
+ sexp = Ripper.sexp("a::C {}")
+ assert_equal(
+ [:program,
+ [
+ [:method_add_block,
+ [:command_call,
+ [:vcall, [:@ident, "a", [1, 0]]],
+ [:@op, "::", [1, 1]],
+ [:@const, "C", [1, 3]],
+ nil],
+ [:brace_block, nil, [[:void_stmt]]]]]],
+ sexp)
+ end
+
def search_sexp(sym, sexp)
return sexp if !sexp or sexp[0] == sym
sexp.find do |e|
@@ -175,7 +203,7 @@ eot
[:aryptn,
nil,
[[:var_field, [:@ident, "a", [1, 11]]]],
- [:var_field, nil],
+ nil,
nil],
[[:void_stmt]],
nil]],
@@ -407,6 +435,14 @@ eot
[[:void_stmt]],
nil]],
+ [__LINE__, %q{ case 0; in [a,]; end }] =>
+ [:case,
+ [:@int, "0", [1, 5]],
+ [:in,
+ [:aryptn, nil, [[:var_field, [:@ident, "a", [1, 12]]]], nil, nil],
+ [[:void_stmt]],
+ nil]],
+
[__LINE__, %q{ case 0; in []; end }] =>
[:case,
[:@int, "0", [1, 5]],
@@ -486,6 +522,22 @@ eot
[:begin, [:binary, [:@int, "0", [1, 13]], :+, [:@int, "0", [1, 15]]]],
[[:void_stmt]],
nil]],
+
+ [__LINE__, %q{ case 0; in [*a]; a; end } ] =>
+ [:case,
+ [:@int, "0", [1, 5]],
+ [:in,
+ [:aryptn, nil, nil, [:var_field, [:@ident, "a", [1, 13]]], nil],
+ [[:var_ref, [:@ident, "a", [1, 17]]]],
+ nil]],
+
+ [__LINE__, %q{ case 0; in {a:}; a; end } ] =>
+ [:case,
+ [:@int, "0", [1, 5]],
+ [:in,
+ [:hshptn, nil, [[[:@label, "a:", [1, 12]], nil]], nil],
+ [[:var_ref, [:@ident, "a", [1, 17]]]],
+ nil]],
}
pattern_matching_data.each do |(i, src), expected|
define_method(:"test_pattern_matching_#{i}") do