Skip to content

Commit b7b46ee

Browse files
committed
Add nesting parser tests, fix some existing tests
1 parent befc180 commit b7b46ee

File tree

2 files changed

+334
-51
lines changed

2 files changed

+334
-51
lines changed

test/irb/test_nesting_parser.rb

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2+
require 'irb'
3+
require 'rubygems'
4+
5+
require_relative "helper"
6+
7+
module TestIRB
8+
class TestNestingParser < TestCase
9+
def setup
10+
save_encodings
11+
end
12+
13+
def teardown
14+
restore_encodings
15+
end
16+
17+
def parse_by_line(code)
18+
IRB::NestingParser.parse_by_line(RubyLex.ripper_lex_without_warning(code))
19+
end
20+
21+
def test_scan
22+
code = <<~'EOS'
23+
class A
24+
def f
25+
if true
26+
tap do
27+
{
28+
x: "
29+
#{p(1, 2, 3
30+
EOS
31+
opens = IRB::NestingParser.scan(RubyLex.ripper_lex_without_warning(code))
32+
assert_equal(%w[class def if do { " #{ (], opens.map(&:tok))
33+
end
34+
35+
def test_parse_by_line
36+
code = <<~EOS
37+
(((((1+2
38+
).to_s())).tap do (((
39+
EOS
40+
_tokens, prev_opens, next_opens, min_depth = parse_by_line(code).last
41+
assert_equal(%w[( ( ( ( (], prev_opens.map(&:tok))
42+
assert_equal(%w[( ( do ( ( (], next_opens.map(&:tok))
43+
assert_equal(2, min_depth)
44+
end
45+
46+
def test_ruby_syntax
47+
code = <<~'EOS'
48+
class A
49+
1 if 2
50+
1 while 2
51+
1 until 2
52+
1 unless 2
53+
1 rescue 2
54+
begin; rescue; ensure; end
55+
tap do; rescue; ensure; end
56+
class B; end
57+
module C; end
58+
def f; end
59+
def `; end
60+
def f() = 1
61+
%(); %w[]; %q(); %r{}; %i[]
62+
"#{1}"; ''; /#{1}/; `#{1}`
63+
:sym; :"sym"; :+; :`; :if
64+
[1, 2, 3]
65+
{ x: 1, y: 2 }
66+
(a, (*b, c), d), e = 1, 2, 3
67+
->(a){}; ->(a) do end
68+
-> a = -> b = :do do end do end
69+
if 1; elsif 2; else; end
70+
unless 1; end
71+
while 1; end
72+
until 1; end
73+
for i in j; end
74+
case 1; when 2; end
75+
puts(1, 2, 3)
76+
loop{|i|}
77+
loop do |i| end
78+
end
79+
EOS
80+
line_results = parse_by_line(code)
81+
line_results[1...-1].each {|result| assert_equal(['class'], result[2].map(&:tok)) }
82+
end
83+
84+
def test_multiline_string
85+
code = <<~EOS
86+
"
87+
aaa
88+
bbb
89+
"
90+
<<A
91+
aaa
92+
bbb
93+
A
94+
EOS
95+
line_results = parse_by_line(code)
96+
string_content_line, string_opens = line_results[1]
97+
assert_equal("\naaa\nbbb\n", string_content_line.map(&:first).map(&:tok).join)
98+
assert_equal("aaa\n", string_content_line.map(&:last).join)
99+
assert_equal(['"'], string_opens.map(&:tok))
100+
heredoc_content_line, heredoc_opens = line_results[6]
101+
assert_equal("aaa\nbbb\n", heredoc_content_line.map(&:first).map(&:tok).join)
102+
assert_equal("bbb\n", heredoc_content_line.map(&:last).join)
103+
assert_equal(['<<A'], heredoc_opens.map(&:tok))
104+
_line, _prev_opens, next_opens, _min_depth = line_results.last
105+
assert_equal([], next_opens)
106+
end
107+
108+
def test_backslash_continued_nested_symbol
109+
code = <<~'EOS'
110+
x = <<A, :\
111+
heredoc #{
112+
here
113+
}
114+
A
115+
=begin
116+
embdoc
117+
=end
118+
# comment
119+
120+
if # this is symbol :if
121+
while
122+
EOS
123+
line_results = parse_by_line(code)
124+
assert_equal(%w[: <<A #{], line_results[2][2].map(&:tok))
125+
assert_equal(%w[while], line_results.last[2].map(&:tok))
126+
end
127+
128+
def test_oneliner_def
129+
code = <<~EOC
130+
if true
131+
# normal oneliner def
132+
def f = 1
133+
def f() = 1
134+
def f(*) = 1
135+
# keyword, backtick, op
136+
def * = 1
137+
def ` = 1
138+
def if = 1
139+
def *() = 1
140+
def `() = 1
141+
def if() = 1
142+
# oneliner def with receiver
143+
def a.* = 1
144+
def $a.* = 1
145+
def @a.` = 1
146+
def A.` = 1
147+
def ((a;b;c)).*() = 1
148+
def ((a;b;c)).if() = 1
149+
def ((a;b;c)).end() = 1
150+
# multiline oneliner def
151+
def f =
152+
1
153+
def f()
154+
=
155+
1
156+
# oneliner def with comment and embdoc
157+
def # comment
158+
=begin
159+
embdoc
160+
=end
161+
((a;b;c))
162+
. # comment
163+
=begin
164+
embdoc
165+
=end
166+
f (*) # comment
167+
=begin
168+
embdoc
169+
=end
170+
=
171+
1
172+
# nested oneliner def
173+
def f(x = def f() = 1) = def f() = 1
174+
EOC
175+
_tokens, _prev_opens, next_opens, min_depth = parse_by_line(code).last
176+
assert_equal(['if'], next_opens.map(&:tok))
177+
assert_equal(1, min_depth)
178+
end
179+
180+
def test_heredoc_embexpr
181+
code = <<~'EOS'
182+
<<A+<<B+<<C+(<<D+(<<E)
183+
#{
184+
<<~F+"#{<<~G}
185+
#{
186+
here
187+
}
188+
F
189+
G
190+
"
191+
}
192+
A
193+
B
194+
C
195+
D
196+
E
197+
)
198+
EOS
199+
line_results = parse_by_line(code)
200+
last_opens = line_results.last[-2]
201+
assert_equal([], last_opens)
202+
_tokens, _prev_opens, next_opens, _min_depth = line_results[4]
203+
assert_equal(%w[( <<E <<D <<C <<B <<A #{ " <<~G <<~F #{], next_opens.map(&:tok))
204+
end
205+
206+
def test_for_in
207+
code = <<~EOS
208+
for i in j
209+
here
210+
end
211+
for i in j do
212+
here
213+
end
214+
for i in
215+
j do
216+
here
217+
end
218+
for
219+
# comment
220+
i in j do
221+
here
222+
end
223+
for (a;b;c).d in (a;b;c) do
224+
here
225+
end
226+
for i in :in + :do do
227+
here
228+
end
229+
for i in -> do end do
230+
here
231+
end
232+
EOS
233+
line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include? 'here' }
234+
assert_equal(7, line_results.size)
235+
line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
236+
assert_equal(['for'], next_opens.map(&:tok))
237+
end
238+
end
239+
240+
def test_while_until
241+
base_code = <<~'EOS'
242+
while_or_until true
243+
here
244+
end
245+
while_or_until a < c
246+
here
247+
end
248+
while_or_until true do
249+
here
250+
end
251+
while_or_until
252+
# comment
253+
(a + b) <
254+
# comment
255+
c do
256+
here
257+
end
258+
while_or_until :\
259+
do do
260+
here
261+
end
262+
while_or_until def do; end == :do do
263+
here
264+
end
265+
while_or_until -> do end do
266+
here
267+
end
268+
EOS
269+
%w[while until].each do |keyword|
270+
code = base_code.gsub('while_or_until', keyword)
271+
line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include? 'here' }
272+
assert_equal(7, line_results.size)
273+
line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
274+
assert_equal([keyword], next_opens.map(&:tok) )
275+
end
276+
end
277+
end
278+
279+
def test_case_in
280+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0')
281+
pend 'This test requires ruby version that supports case-in syntax'
282+
end
283+
code = <<~EOS
284+
case 1
285+
in 1
286+
here
287+
in
288+
2
289+
here
290+
end
291+
EOS
292+
line_results = parse_by_line(code).select { |tokens,| tokens.map(&:last).include?('here') }
293+
assert_equal(2, line_results.size)
294+
line_results.each do |_tokens, _prev_opens, next_opens, _min_depth|
295+
assert_equal(['in'], next_opens.map(&:tok))
296+
end
297+
end
298+
end
299+
end

0 commit comments

Comments
 (0)