Skip to content

Commit a6282a3

Browse files
committed
[GR-28693] Add tests for compatibility errors in the TRegex Ruby flavor.
PullRequest: truffleruby/2437
2 parents 5f33393 + 4ca7311 commit a6282a3

File tree

5 files changed

+190
-2
lines changed

5 files changed

+190
-2
lines changed

mx.truffleruby/suite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"name": "regex",
99
"subdir": True,
10-
"version": "8c1abd10ad2992580462d7629db316177a256f82",
10+
"version": "5389f3cc7077f24bcf62f1315530e445ec5646c7",
1111
"urls": [
1212
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
1313
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},
@@ -16,7 +16,7 @@
1616
{
1717
"name": "sulong",
1818
"subdir": True,
19-
"version": "8c1abd10ad2992580462d7629db316177a256f82",
19+
"version": "5389f3cc7077f24bcf62f1315530e445ec5646c7",
2020
"urls": [
2121
{"url": "https://github.com/oracle/graal.git", "kind": "git"},
2222
{"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"},

spec/ruby/language/regexp/back-references_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
(/\10()()()()()()()()()()/ =~ "\x08").should == 0
6464
end
6565

66+
it "fails when trying to match a backreference to an unmatched capture group" do
67+
/\1()/.match("").should == nil
68+
/(?:(a)|b)\1/.match("b").should == nil
69+
end
70+
6671
it "ignores backreferences > 1000" do
6772
/\99999/.match("99999")[0].should == "99999"
6873
end
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
require_relative '../../spec_helper'
2+
require_relative '../fixtures/classes'
3+
4+
describe "empty checks in Regexps" do
5+
6+
it "allow extra empty iterations" do
7+
/()?/.match("").to_a.should == ["", ""]
8+
/(a*)?/.match("").to_a.should == ["", ""]
9+
/(a*)*/.match("").to_a.should == ["", ""]
10+
# The bounds are high to avoid DFA-based matchers in implementations
11+
# and to check backtracking behavior.
12+
/(?:a|()){500,1000}/.match("a" * 500).to_a.should == ["a" * 500, ""]
13+
14+
# Variations with non-greedy loops.
15+
/()??/.match("").to_a.should == ["", nil]
16+
/(a*?)?/.match("").to_a.should == ["", ""]
17+
/(a*)??/.match("").to_a.should == ["", nil]
18+
/(a*?)??/.match("").to_a.should == ["", nil]
19+
/(a*?)*/.match("").to_a.should == ["", ""]
20+
/(a*)*?/.match("").to_a.should == ["", nil]
21+
/(a*?)*?/.match("").to_a.should == ["", nil]
22+
end
23+
24+
it "allow empty iterations in the middle of a loop" do
25+
# One empty iteration between a's and b's.
26+
/(a|\2b|())*/.match("aaabbb").to_a.should == ["aaabbb", "", ""]
27+
/(a|\2b|()){2,4}/.match("aaabbb").to_a.should == ["aaa", "", ""]
28+
29+
# Two empty iterations between a's and b's.
30+
/(a|\2b|\3()|())*/.match("aaabbb").to_a.should == ["aaabbb", "", "", ""]
31+
/(a|\2b|\3()|()){2,4}/.match("aaabbb").to_a.should == ["aaa", "", nil, ""]
32+
33+
# Check that the empty iteration correctly updates the loop counter.
34+
/(a|\2b|()){20,24}/.match("a" * 20 + "b" * 5).to_a.should == ["a" * 20 + "b" * 3, "b", ""]
35+
36+
# Variations with non-greedy loops.
37+
/(a|\2b|())*?/.match("aaabbb").to_a.should == ["", nil, nil]
38+
/(a|\2b|()){2,4}/.match("aaabbb").to_a.should == ["aaa", "", ""]
39+
/(a|\2b|\3()|())*?/.match("aaabbb").to_a.should == ["", nil, nil, nil]
40+
/(a|\2b|\3()|()){2,4}/.match("aaabbb").to_a.should == ["aaa", "", nil, ""]
41+
/(a|\2b|()){20,24}/.match("a" * 20 + "b" * 5).to_a.should == ["a" * 20 + "b" * 3, "b", ""]
42+
end
43+
44+
it "make the Regexp proceed past the quantified expression on failure" do
45+
# If the contents of the ()* quantified group are empty (i.e., they fail
46+
# the empty check), the loop will abort. It will not try to backtrack
47+
# and try other alternatives (e.g. matching the "a") like in other Regexp
48+
# dialects such as ECMAScript.
49+
/(?:|a)*/.match("aaa").to_a.should == [""]
50+
/(?:()|a)*/.match("aaa").to_a.should == ["", ""]
51+
/(|a)*/.match("aaa").to_a.should == ["", ""]
52+
/(()|a)*/.match("aaa").to_a.should == ["", "", ""]
53+
54+
# Same expressions, but with backreferences, to force the use of non-DFA-based
55+
# engines.
56+
/()\1(?:|a)*/.match("aaa").to_a.should == ["", ""]
57+
/()\1(?:()|a)*/.match("aaa").to_a.should == ["", "", ""]
58+
/()\1(|a)*/.match("aaa").to_a.should == ["", "", ""]
59+
/()\1(()|a)*/.match("aaa").to_a.should == ["", "", "", ""]
60+
61+
# Variations with other zero-width contents of the quantified
62+
# group: backreferences, capture groups, lookarounds
63+
/()(?:\1|a)*/.match("aaa").to_a.should == ["", ""]
64+
/()(?:()\1|a)*/.match("aaa").to_a.should == ["", "", ""]
65+
/()(?:(\1)|a)*/.match("aaa").to_a.should == ["", "", ""]
66+
/()(?:\1()|a)*/.match("aaa").to_a.should == ["", "", ""]
67+
/()(\1|a)*/.match("aaa").to_a.should == ["", "", ""]
68+
/()(()\1|a)*/.match("aaa").to_a.should == ["", "", "", ""]
69+
/()((\1)|a)*/.match("aaa").to_a.should == ["", "", "", ""]
70+
/()(\1()|a)*/.match("aaa").to_a.should == ["", "", "", ""]
71+
72+
/(?:(?=a)|a)*/.match("aaa").to_a.should == [""]
73+
/(?:(?=a)()|a)*/.match("aaa").to_a.should == ["", ""]
74+
/(?:()(?=a)|a)*/.match("aaa").to_a.should == ["", ""]
75+
/(?:((?=a))|a)*/.match("aaa").to_a.should == ["", ""]
76+
/()\1(?:(?=a)|a)*/.match("aaa").to_a.should == ["", ""]
77+
/()\1(?:(?=a)()|a)*/.match("aaa").to_a.should == ["", "", ""]
78+
/()\1(?:()(?=a)|a)*/.match("aaa").to_a.should == ["", "", ""]
79+
/()\1(?:((?=a))|a)*/.match("aaa").to_a.should == ["", "", ""]
80+
81+
# Variations with non-greedy loops.
82+
/(?:|a)*?/.match("aaa").to_a.should == [""]
83+
/(?:()|a)*?/.match("aaa").to_a.should == ["", nil]
84+
/(|a)*?/.match("aaa").to_a.should == ["", nil]
85+
/(()|a)*?/.match("aaa").to_a.should == ["", nil, nil]
86+
87+
/()\1(?:|a)*?/.match("aaa").to_a.should == ["", ""]
88+
/()\1(?:()|a)*?/.match("aaa").to_a.should == ["", "", nil]
89+
/()\1(|a)*?/.match("aaa").to_a.should == ["", "", nil]
90+
/()\1(()|a)*?/.match("aaa").to_a.should == ["", "", nil, nil]
91+
92+
/()(?:\1|a)*?/.match("aaa").to_a.should == ["", ""]
93+
/()(?:()\1|a)*?/.match("aaa").to_a.should == ["", "", nil]
94+
/()(?:(\1)|a)*?/.match("aaa").to_a.should == ["", "", nil]
95+
/()(?:\1()|a)*?/.match("aaa").to_a.should == ["", "", nil]
96+
/()(\1|a)*?/.match("aaa").to_a.should == ["", "", nil]
97+
/()(()\1|a)*?/.match("aaa").to_a.should == ["", "", nil, nil]
98+
/()((\1)|a)*?/.match("aaa").to_a.should == ["", "", nil, nil]
99+
/()(\1()|a)*?/.match("aaa").to_a.should == ["", "", nil, nil]
100+
101+
/(?:(?=a)|a)*?/.match("aaa").to_a.should == [""]
102+
/(?:(?=a)()|a)*?/.match("aaa").to_a.should == ["", nil]
103+
/(?:()(?=a)|a)*?/.match("aaa").to_a.should == ["", nil]
104+
/(?:((?=a))|a)*?/.match("aaa").to_a.should == ["", nil]
105+
/()\1(?:(?=a)|a)*?/.match("aaa").to_a.should == ["", ""]
106+
/()\1(?:(?=a)()|a)*?/.match("aaa").to_a.should == ["", "", nil]
107+
/()\1(?:()(?=a)|a)*?/.match("aaa").to_a.should == ["", "", nil]
108+
/()\1(?:((?=a))|a)*?/.match("aaa").to_a.should == ["", "", nil]
109+
end
110+
111+
it "shouldn't cause the Regexp parser to get stuck in a loop" do
112+
/(|a|\2b|())*/.match("aaabbb").to_a.should == ["", "", nil]
113+
/(a||\2b|())*/.match("aaabbb").to_a.should == ["aaa", "", nil]
114+
/(a|\2b||())*/.match("aaabbb").to_a.should == ["aaa", "", nil]
115+
/(a|\2b|()|)*/.match("aaabbb").to_a.should == ["aaabbb", "", ""]
116+
/(()|a|\3b|())*/.match("aaabbb").to_a.should == ["", "", "", nil]
117+
/(a|()|\3b|())*/.match("aaabbb").to_a.should == ["aaa", "", "", nil]
118+
/(a|\2b|()|())*/.match("aaabbb").to_a.should == ["aaabbb", "", "", nil]
119+
/(a|\3b|()|())*/.match("aaabbb").to_a.should == ["aaa", "", "", nil]
120+
/(a|()|())*/.match("aaa").to_a.should == ["aaa", "", "", nil]
121+
/^(()|a|())*$/.match("aaa").to_a.should == ["aaa", "", "", nil]
122+
123+
# Variations with non-greedy loops.
124+
/(|a|\2b|())*?/.match("aaabbb").to_a.should == ["", nil, nil]
125+
/(a||\2b|())*?/.match("aaabbb").to_a.should == ["", nil, nil]
126+
/(a|\2b||())*?/.match("aaabbb").to_a.should == ["", nil, nil]
127+
/(a|\2b|()|)*?/.match("aaabbb").to_a.should == ["", nil, nil]
128+
/(()|a|\3b|())*?/.match("aaabbb").to_a.should == ["", nil, nil, nil]
129+
/(a|()|\3b|())*?/.match("aaabbb").to_a.should == ["", nil, nil, nil]
130+
/(a|\2b|()|())*?/.match("aaabbb").to_a.should == ["", nil, nil, nil]
131+
/(a|\3b|()|())*?/.match("aaabbb").to_a.should == ["", nil, nil, nil]
132+
/(a|()|())*?/.match("aaa").to_a.should == ["", nil, nil, nil]
133+
/^(()|a|())*?$/.match("aaa").to_a.should == ["aaa", "a", "", nil]
134+
end
135+
end

spec/ruby/language/regexp/repetition_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,15 @@
128128
RUBY
129129
end
130130
end
131+
132+
it "treats ? after {n} quantifier as another quantifier, not as non-greedy marker" do
133+
/a{2}?/.match("").to_a.should == [""]
134+
end
135+
136+
it "matches zero-width capture groups in optional iterations of loops" do
137+
/()?/.match("").to_a.should == ["", ""]
138+
/(a*)?/.match("").to_a.should == ["", ""]
139+
/(a*)*/.match("").to_a.should == ["", ""]
140+
/(?:a|()){500,1000}/.match("a" * 500).to_a.should == ["a" * 500, ""]
141+
end
131142
end

spec/truffle/regressions_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2021, 2021 Oracle and/or its affiliates. All rights reserved. This
2+
# code is released under a tri EPL/GPL/LGPL license. You can use it,
3+
# redistribute it and/or modify it under the terms of the:
4+
#
5+
# Eclipse Public License version 2.0, or
6+
# GNU General Public License version 2, or
7+
# GNU Lesser General Public License version 2.1.
8+
9+
require_relative '../ruby/spec_helper'
10+
11+
describe "Regression test suite" do
12+
it "fixes GitHub issue 2204" do
13+
/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/.match("20190116152522_enable_postgis_extension.rb").to_a.should ==
14+
["20190116152522_enable_postgis_extension.rb", "20190116152522", "enable_postgis_extension", ""]
15+
16+
/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/.match("20190116152523_create_schools.rb").to_a.should ==
17+
["20190116152523_create_schools.rb", "20190116152523", "create_schools", ""]
18+
19+
/^0{2}?(00)?(44)?(0)?([1-357-9]\d{9}|[18]\d{8}|8\d{6})$/.match("07123456789").to_a.should ==
20+
["07123456789", nil, nil, "0", "7123456789"]
21+
22+
/^0{2}?(00)?44/.match("447123456789").to_a.should ==
23+
["44", nil]
24+
25+
/^0{2}?(00)?(44)(0)?([1-357-9]\d{9}|[18]\d{8}|8\d{6})$/.match("447123456789").to_a.should ==
26+
["447123456789", nil, "44", nil, "7123456789"]
27+
28+
/^0{2}?(00)?(44)?(0)?([1-357-9]\d{9}|[18]\d{8}|8\d{6})$/.match("07123456789").to_a.should ==
29+
["07123456789", nil, nil, "0", "7123456789"]
30+
31+
/^0{2}?(00)?44/.match("447123456789").to_a.should ==
32+
["44", nil]
33+
34+
/^0{2}?(00)?(44)(0)?([1-357-9]\d{9}|[18]\d{8}|8\d{6})$/.match("447123456789").to_a.should ==
35+
["447123456789", nil, "44", nil, "7123456789"]
36+
end
37+
end

0 commit comments

Comments
 (0)