summaryrefslogtreecommitdiff
path: root/test/ripper/test_parser_events.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ripper/test_parser_events.rb')
-rw-r--r--test/ripper/test_parser_events.rb149
1 files changed, 132 insertions, 17 deletions
diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb
index 1ea8d23378..aa7434c083 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,7 @@ 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
@@ -266,17 +267,29 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
end
def test_assign_error_backref
- thru_assign_error = false
+ errors = []
result =
- parse('$` = 1', :on_assign_error) {thru_assign_error = true}
- assert_equal true, thru_assign_error
- assert_equal '[assign(assign_error(var_field($`)),1)]', result
+ parse('$& = 1', %i[on_assign_error compile_error]) {|e, *| errors << e}
+ assert_equal %i[on_assign_error], errors
+ assert_equal '[assign(assign_error(var_field($&)),1)]', result
- thru_assign_error = false
+ errors = []
result =
- parse('$`, _ = 1', :on_assign_error) {thru_assign_error = true}
- assert_equal true, thru_assign_error
- assert_equal '[massign([assign_error(var_field($`)),var_field(_)],1)]', result
+ parse('$&, _ = 1', %i[on_assign_error compile_error]) {|e, *| errors << e}
+ assert_equal %i[on_assign_error], errors
+ assert_equal '[massign([assign_error(var_field($&)),var_field(_)],1)]', result
+
+ errors = []
+ result =
+ parse('$& += 1', %i[on_assign_error compile_error]) {|e, *| errors << e}
+ assert_equal %i[on_assign_error], errors
+ assert_equal '[assign_error(opassign(var_field($&),+=,1))]', result
+
+ errors = []
+ result =
+ parse('$& += cmd 1, 2', %i[on_assign_error compile_error]) {|e, *| errors << e}
+ assert_equal %i[on_assign_error], errors
+ assert_equal '[assign_error(opassign(var_field($&),+=,command(cmd,[1,2])))]', result
end
def test_assign_error_const_qualified
@@ -499,6 +512,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}
@@ -1626,20 +1656,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
@@ -1654,6 +1684,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(/duplicates 'when' clause/, fmt)
+ assert_equal([4, 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;")}
@@ -1693,4 +1743,69 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
parse('case 0; in {a:}; end', :on_hshptn) {thru_hshptn = true}
assert_equal true, thru_hshptn
end
+
+ def test_return_out_of_compile_error_no_memory_leak
+ assert_no_memory_leak(%w(-rripper), "#{<<~'begin;'}", "#{<<~'end;'}", rss: true)
+ class MyRipper < Ripper
+ def initialize(src, &blk)
+ super(src)
+ @blk = blk
+ end
+
+ def compile_error(msg) = @blk.call(msg)
+ end
+
+ def call_parse = MyRipper.new("/") { |msg| return msg }.parse
+
+ # Check that call_parse does return a syntax error
+ raise "call_parse should return a syntax error" unless call_parse
+ begin;
+ 100_000.times do
+ call_parse
+ end
+ end;
+ end
+
+ def test_return_out_of_warn_no_memory_leak
+ assert_no_memory_leak(%w(-rripper), "#{<<~'begin;'}", "#{<<~'end;'}", rss: true)
+ class MyRipper < Ripper
+ def initialize(src, &blk)
+ super(src)
+ @blk = blk
+ end
+
+ def warn(msg, *args) = @blk.call(msg)
+ end
+
+ def call_parse = MyRipper.new("{ a: 1, a: 2 }") { |msg| return msg }.parse
+
+ # Check that call_parse does warn
+ raise "call_parse should warn" unless call_parse
+ begin;
+ 500_000.times do
+ call_parse
+ end
+ end;
+
+ assert_no_memory_leak(%w(-rripper), "#{<<~'begin;'}", "#{<<~'end;'}", rss: true)
+ class MyRipper < Ripper
+ def initialize(src, &blk)
+ super(src)
+ @blk = blk
+ end
+
+ def warn(msg, *args) = @blk.call(msg)
+ end
+
+ $VERBOSE = true
+ def call_parse = MyRipper.new("if true\n end\n") { |msg| return msg }.parse
+
+ # Check that call_parse does warn
+ raise "call_parse should warn" unless call_parse
+ begin;
+ 1_000_000.times do
+ call_parse
+ end
+ end;
+ end
end if ripper_test