re2 2.15.0.rc1-x86_64-linux-gnu

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RE2::Scanner do
4
+ describe "#regexp" do
5
+ it "returns the original pattern for the scanner" do
6
+ re = RE2::Regexp.new('(\w+)')
7
+ scanner = re.scan("It is a truth")
8
+
9
+ expect(scanner.regexp).to equal(re)
10
+ end
11
+ end
12
+
13
+ describe "#string" do
14
+ it "returns the original text for the scanner" do
15
+ re = RE2::Regexp.new('(\w+)')
16
+ text = "It is a truth"
17
+ scanner = re.scan(text)
18
+
19
+ expect(scanner.string).to equal(text)
20
+ end
21
+ end
22
+
23
+ describe "#scan" do
24
+ it "returns the next array of matches", :aggregate_failures do
25
+ r = RE2::Regexp.new('(\w+)')
26
+ scanner = r.scan("It is a truth universally acknowledged")
27
+
28
+ expect(scanner.scan).to eq(["It"])
29
+ expect(scanner.scan).to eq(["is"])
30
+ expect(scanner.scan).to eq(["a"])
31
+ expect(scanner.scan).to eq(["truth"])
32
+ expect(scanner.scan).to eq(["universally"])
33
+ expect(scanner.scan).to eq(["acknowledged"])
34
+ expect(scanner.scan).to be_nil
35
+ end
36
+
37
+ it "supports scanning inputs with null bytes", :aggregate_failures do
38
+ r = RE2::Regexp.new("(\\w\0\\w)")
39
+ scanner = r.scan("a\0b c\0d e\0f")
40
+
41
+ expect(scanner.scan).to eq(["a\0b"])
42
+ expect(scanner.scan).to eq(["c\0d"])
43
+ expect(scanner.scan).to eq(["e\0f"])
44
+ expect(scanner.scan).to be_nil
45
+ end
46
+
47
+ it "returns UTF-8 matches if the pattern is UTF-8" do
48
+ r = RE2::Regexp.new('(\w+)')
49
+ scanner = r.scan("It")
50
+ matches = scanner.scan
51
+
52
+ expect(matches.first.encoding).to eq(Encoding::UTF_8)
53
+ end
54
+
55
+ it "returns ISO-8859-1 matches if the pattern is not UTF-8" do
56
+ r = RE2::Regexp.new('(\w+)', utf8: false)
57
+ scanner = r.scan("It")
58
+ matches = scanner.scan
59
+
60
+ expect(matches.first.encoding).to eq(Encoding::ISO_8859_1)
61
+ end
62
+
63
+ it "returns multiple capturing groups at a time", :aggregate_failures do
64
+ r = RE2::Regexp.new('(\w+) (\w+)')
65
+ scanner = r.scan("It is a truth universally acknowledged")
66
+
67
+ expect(scanner.scan).to eq(["It", "is"])
68
+ expect(scanner.scan).to eq(["a", "truth"])
69
+ expect(scanner.scan).to eq(["universally", "acknowledged"])
70
+ expect(scanner.scan).to be_nil
71
+ end
72
+
73
+ it "returns an empty array if there are no capturing groups" do
74
+ r = RE2::Regexp.new('\w+')
75
+ scanner = r.scan("Foo bar")
76
+
77
+ expect(scanner.scan).to eq([])
78
+ end
79
+
80
+ it "returns nil if there is no match" do
81
+ r = RE2::Regexp.new('\d+')
82
+ scanner = r.scan("Foo bar")
83
+
84
+ expect(scanner.scan).to be_nil
85
+ end
86
+
87
+ it "returns nil if the regexp is invalid" do
88
+ r = RE2::Regexp.new('???', log_errors: false)
89
+ scanner = r.scan("Foo bar")
90
+
91
+ expect(scanner.scan).to be_nil
92
+ end
93
+
94
+ it "returns an empty array if the input is empty", :aggregate_failures do
95
+ r = RE2::Regexp.new("")
96
+ scanner = r.scan("")
97
+
98
+ expect(scanner.scan).to eq([])
99
+ expect(scanner.scan).to be_nil
100
+ end
101
+
102
+ it "returns an array of nil with an empty input and capture", :aggregate_failures do
103
+ r = RE2::Regexp.new("()")
104
+ scanner = r.scan("")
105
+
106
+ expect(scanner.scan).to eq([nil])
107
+ expect(scanner.scan).to be_nil
108
+ end
109
+
110
+ it "returns an empty array for every match if the pattern is empty", :aggregate_failures do
111
+ r = RE2::Regexp.new("")
112
+ scanner = r.scan("Foo")
113
+
114
+ expect(scanner.scan).to eq([])
115
+ expect(scanner.scan).to eq([])
116
+ expect(scanner.scan).to eq([])
117
+ expect(scanner.scan).to eq([])
118
+ expect(scanner.scan).to be_nil
119
+ end
120
+
121
+ it "returns an array of nil if the pattern is an empty capturing group", :aggregate_failures do
122
+ r = RE2::Regexp.new("()")
123
+ scanner = r.scan("Foo")
124
+
125
+ expect(scanner.scan).to eq([nil])
126
+ expect(scanner.scan).to eq([nil])
127
+ expect(scanner.scan).to eq([nil])
128
+ expect(scanner.scan).to eq([nil])
129
+ expect(scanner.scan).to be_nil
130
+ end
131
+
132
+ it "returns array of nils with multiple empty capturing groups", :aggregate_failures do
133
+ r = RE2::Regexp.new("()()()")
134
+ scanner = r.scan("Foo")
135
+
136
+ expect(scanner.scan).to eq([nil, nil, nil])
137
+ expect(scanner.scan).to eq([nil, nil, nil])
138
+ expect(scanner.scan).to eq([nil, nil, nil])
139
+ expect(scanner.scan).to eq([nil, nil, nil])
140
+ expect(scanner.scan).to be_nil
141
+ end
142
+
143
+ it "supports empty groups with multibyte characters", :aggregate_failures do
144
+ r = RE2::Regexp.new("()€")
145
+ scanner = r.scan("€")
146
+
147
+ expect(scanner.scan).to eq([nil])
148
+ expect(scanner.scan).to be_nil
149
+ end
150
+
151
+ it "raises a Type Error if given input that can't be coerced to a String" do
152
+ r = RE2::Regexp.new('(\w+)')
153
+
154
+ expect { r.scan(0) }.to raise_error(TypeError)
155
+ end
156
+
157
+ it "accepts input that can be coerced to a String", :aggregate_failures do
158
+ r = RE2::Regexp.new('(\w+)')
159
+ scanner = r.scan(StringLike.new("Hello world"))
160
+
161
+ expect(scanner.scan).to eq(["Hello"])
162
+ expect(scanner.scan).to eq(["world"])
163
+ expect(scanner.scan).to be_nil
164
+ end
165
+ end
166
+
167
+ it "is enumerable" do
168
+ r = RE2::Regexp.new('(\d)')
169
+ scanner = r.scan("There are 1 some 2 numbers 3")
170
+
171
+ expect(scanner).to be_a(Enumerable)
172
+ end
173
+
174
+ describe "#each" do
175
+ it "yields each match" do
176
+ r = RE2::Regexp.new('(\d)')
177
+ scanner = r.scan("There are 1 some 2 numbers 3")
178
+
179
+ expect { |b| scanner.each(&b) }.to yield_successive_args(["1"], ["2"], ["3"])
180
+ end
181
+
182
+ it "returns an enumerator when not given a block" do
183
+ r = RE2::Regexp.new('(\d)')
184
+ scanner = r.scan("There are 1 some 2 numbers 3")
185
+
186
+ expect(scanner.each).to be_a(Enumerator)
187
+ end
188
+ end
189
+
190
+ describe "#rewind" do
191
+ it "resets any consumption", :aggregate_failures do
192
+ r = RE2::Regexp.new('(\d)')
193
+ scanner = r.scan("There are 1 some 2 numbers 3")
194
+
195
+ expect(scanner.to_enum.first).to eq(["1"])
196
+ expect(scanner.to_enum.first).to eq(["2"])
197
+
198
+ scanner.rewind
199
+
200
+ expect(scanner.to_enum.first).to eq(["1"])
201
+ end
202
+
203
+ it "supports inputs with null bytes", :aggregate_failures do
204
+ r = RE2::Regexp.new("(\\w\0\\w)")
205
+ scanner = r.scan("a\0b c\0d")
206
+
207
+ expect(scanner.to_enum.first).to eq(["a\0b"])
208
+ expect(scanner.to_enum.first).to eq(["c\0d"])
209
+
210
+ scanner.rewind
211
+
212
+ expect(scanner.to_enum.first).to eq(["a\0b"])
213
+ end
214
+
215
+ it "resets the eof? check", :aggregate_failures do
216
+ r = RE2::Regexp.new('(\d)')
217
+ scanner = r.scan("1")
218
+ scanner.scan
219
+
220
+ expect(scanner).to be_eof
221
+
222
+ scanner.rewind
223
+
224
+ expect(scanner).not_to be_eof
225
+ end
226
+ end
227
+
228
+ describe "#eof?" do
229
+ it "returns false if the input has not been consumed" do
230
+ r = RE2::Regexp.new('(\d)')
231
+ scanner = r.scan("1 2 3")
232
+
233
+ expect(scanner).not_to be_eof
234
+ end
235
+
236
+ it "returns true if the input has been consumed" do
237
+ r = RE2::Regexp.new('(\d)')
238
+ scanner = r.scan("1")
239
+ scanner.scan
240
+
241
+ expect(scanner).to be_eof
242
+ end
243
+
244
+ it "returns false if no match is made" do
245
+ r = RE2::Regexp.new('(\d)')
246
+ scanner = r.scan("a")
247
+ scanner.scan
248
+
249
+ expect(scanner).not_to be_eof
250
+ end
251
+
252
+ it "returns false with an empty input that has not been scanned" do
253
+ r = RE2::Regexp.new("")
254
+ scanner = r.scan("")
255
+
256
+ expect(scanner).not_to be_eof
257
+ end
258
+
259
+ it "returns false with an empty input that has not been matched" do
260
+ r = RE2::Regexp.new('(\d)')
261
+ scanner = r.scan("")
262
+ scanner.scan
263
+
264
+ expect(scanner).not_to be_eof
265
+ end
266
+
267
+ it "returns true with an empty input that has been matched" do
268
+ r = RE2::Regexp.new("")
269
+ scanner = r.scan("")
270
+ scanner.scan
271
+
272
+ expect(scanner).to be_eof
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RE2::Set do
4
+ describe "#initialize" do
5
+ it "returns an instance given no args" do
6
+ set = RE2::Set.new
7
+
8
+ expect(set).to be_a(RE2::Set)
9
+ end
10
+
11
+ it "returns an instance given only an anchor of :unanchored" do
12
+ set = RE2::Set.new(:unanchored)
13
+
14
+ expect(set).to be_a(RE2::Set)
15
+ end
16
+
17
+ it "returns an instance given only an anchor of :anchor_start" do
18
+ set = RE2::Set.new(:anchor_start)
19
+
20
+ expect(set).to be_a(RE2::Set)
21
+ end
22
+
23
+ it "returns an instance given only an anchor of :anchor_both" do
24
+ set = RE2::Set.new(:anchor_both)
25
+
26
+ expect(set).to be_a(RE2::Set)
27
+ end
28
+
29
+ it "returns an instance given an anchor and options" do
30
+ set = RE2::Set.new(:unanchored, case_sensitive: false)
31
+
32
+ expect(set).to be_a(RE2::Set)
33
+ end
34
+
35
+ it "raises an error if given an inappropriate type" do
36
+ expect { RE2::Set.new(0) }.to raise_error(TypeError)
37
+ end
38
+
39
+ it "raises an error if given an invalid anchor" do
40
+ expect { RE2::Set.new(:not_a_valid_anchor) }.to raise_error(
41
+ ArgumentError,
42
+ "anchor should be one of: :unanchored, :anchor_start, :anchor_both"
43
+ )
44
+ end
45
+
46
+ it "raises an error if given an invalid anchor and options" do
47
+ expect { RE2::Set.new(:not_a_valid_anchor, case_sensitive: false) }.to raise_error(
48
+ ArgumentError,
49
+ "anchor should be one of: :unanchored, :anchor_start, :anchor_both"
50
+ )
51
+ end
52
+ end
53
+
54
+ describe "#add" do
55
+ it "allows multiple patterns to be added", :aggregate_failures do
56
+ set = RE2::Set.new
57
+
58
+ expect(set.add("abc")).to eq(0)
59
+ expect(set.add("def")).to eq(1)
60
+ expect(set.add("ghi")).to eq(2)
61
+ end
62
+
63
+ it "rejects invalid patterns when added" do
64
+ set = RE2::Set.new(:unanchored, log_errors: false)
65
+
66
+ expect { set.add("???") }.to raise_error(ArgumentError, /str rejected by RE2::Set->Add\(\)/)
67
+ end
68
+
69
+ it "truncates error messages to 100 characters" do
70
+ set = RE2::Set.new(:unanchored, log_errors: false)
71
+
72
+ expect { set.add("(?P<#{'o' * 200}") }.to raise_error(ArgumentError, "str rejected by RE2::Set->Add(): invalid named capture group: (?P<oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")
73
+ end
74
+
75
+ it "raises an error if called after #compile" do
76
+ set = RE2::Set.new(:unanchored, log_errors: false)
77
+ set.add("abc")
78
+ set.compile
79
+
80
+ silence_stderr do
81
+ expect { set.add("def") }.to raise_error(ArgumentError)
82
+ end
83
+ end
84
+
85
+ it "raises an error if given a pattern that can't be coerced to a String" do
86
+ set = RE2::Set.new(:unanchored, log_errors: false)
87
+
88
+ expect { set.add(0) }.to raise_error(TypeError)
89
+ end
90
+
91
+ it "accepts a pattern that can be coerced to a String" do
92
+ set = RE2::Set.new
93
+
94
+ expect(set.add(StringLike.new("abc"))).to eq(0)
95
+ end
96
+ end
97
+
98
+ describe "#compile" do
99
+ it "compiles the set without error" do
100
+ set = RE2::Set.new
101
+ set.add("abc")
102
+ set.add("def")
103
+ set.add("ghi")
104
+
105
+ expect(set.compile).to be_truthy
106
+ end
107
+ end
108
+
109
+ describe "#match" do
110
+ it "matches against multiple patterns" do
111
+ set = RE2::Set.new
112
+ set.add("abc")
113
+ set.add("def")
114
+ set.add("ghi")
115
+ set.compile
116
+
117
+ expect(set.match("abcdefghi", exception: false)).to eq([0, 1, 2])
118
+ end
119
+
120
+ it "returns an empty array if there is no match" do
121
+ set = RE2::Set.new
122
+ set.add("abc")
123
+ set.compile
124
+
125
+ expect(set.match("def", exception: false)).to be_empty
126
+ end
127
+
128
+ it "supports matching null bytes", :aggregate_failures do
129
+ set = RE2::Set.new
130
+ set.add("a\0b")
131
+ set.compile
132
+
133
+ expect(set.match("a\0b", exception: false)).to eq([0])
134
+ end
135
+
136
+ it "returns an empty array if there is no match when :exception is true" do
137
+ skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
138
+
139
+ set = RE2::Set.new
140
+ set.add("abc")
141
+ set.compile
142
+
143
+ expect(set.match("def")).to be_empty
144
+ end
145
+
146
+ it "raises an error if called before #compile by default" do
147
+ skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
148
+
149
+ set = RE2::Set.new(:unanchored, log_errors: false)
150
+
151
+ silence_stderr do
152
+ expect { set.match("") }.to raise_error(RE2::Set::MatchError)
153
+ end
154
+ end
155
+
156
+ it "raises an error if called before #compile when :exception is true" do
157
+ skip "Underlying RE2::Set::Match does not output error information" unless RE2::Set.match_raises_errors?
158
+
159
+ set = RE2::Set.new(:unanchored, log_errors: false)
160
+
161
+ silence_stderr do
162
+ expect { set.match("", exception: true) }.to raise_error(RE2::Set::MatchError)
163
+ end
164
+ end
165
+
166
+ it "returns an empty array if called before #compile when :exception is false" do
167
+ set = RE2::Set.new(:unanchored, log_errors: false)
168
+
169
+ silence_stderr do
170
+ expect(set.match("", exception: false)).to be_empty
171
+ end
172
+ end
173
+
174
+ it "raises an error if :exception is true and RE2 does not support it" do
175
+ skip "Underlying RE2::Set::Match outputs error information" if RE2::Set.match_raises_errors?
176
+
177
+ set = RE2::Set.new(:unanchored, log_errors: false)
178
+
179
+ silence_stderr do
180
+ expect { set.match("", exception: true) }.to raise_error(RE2::Set::UnsupportedError)
181
+ end
182
+ end
183
+
184
+ it "raises an error if given non-hash options" do
185
+ set = RE2::Set.new
186
+
187
+ expect { set.match("", 0) }.to raise_error(TypeError)
188
+ end
189
+
190
+ it "raises a Type Error if given input that can't be coerced to a String" do
191
+ set = RE2::Set.new
192
+ set.add("abc")
193
+ set.compile
194
+
195
+ expect { set.match(0, exception: false) }.to raise_error(TypeError)
196
+ end
197
+
198
+ it "accepts input if it can be coerced to a String" do
199
+ set = RE2::Set.new
200
+ set.add("abc")
201
+ set.compile
202
+
203
+ expect(set.match(StringLike.new("abcdef"), exception: false)).to contain_exactly(0)
204
+ end
205
+ end
206
+
207
+ def silence_stderr
208
+ original_stream = STDERR
209
+
210
+ if File.const_defined?(:NULL)
211
+ STDERR.reopen(File::NULL)
212
+ else
213
+ platform = RUBY_PLATFORM == 'java' ? RbConfig::CONFIG['host_os'] : RUBY_PLATFORM
214
+
215
+ case platform
216
+ when /mswin|mingw/i
217
+ STDERR.reopen('NUL')
218
+ when /amiga/i
219
+ STDERR.reopen('NIL')
220
+ when /openvms/i
221
+ STDERR.reopen('NL:')
222
+ else
223
+ STDERR.reopen('/dev/null')
224
+ end
225
+ end
226
+
227
+ yield
228
+ ensure
229
+ STDERR.reopen(original_stream)
230
+ end
231
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "re2/string"
4
+
5
+ class String
6
+ include RE2::String
7
+ end
8
+
9
+ RSpec.describe RE2::String do
10
+ describe "#re2_sub" do
11
+ it "delegates to RE2.Replace to perform replacement" do
12
+ expect("My name is Robert Paulson".re2_sub('Robert', 'Crobert')).to eq("My name is Crobert Paulson")
13
+ end
14
+
15
+ it "doesn't perform an in-place replacement" do
16
+ string = "My name is Robert Paulson"
17
+
18
+ expect(string.re2_sub('Robert', 'Crobert')).not_to equal(string)
19
+ end
20
+ end
21
+
22
+ describe "#re2_gsub" do
23
+ it "delegates to RE2.GlobalReplace to perform replacement" do
24
+ expect("My name is Robert Paulson".re2_gsub('a', 'e')).to eq("My neme is Robert Peulson")
25
+ end
26
+
27
+ it "doesn't perform an in-place replacement" do
28
+ string = "My name is Robert Paulson"
29
+
30
+ expect(string.re2_gsub('a', 'e')).not_to equal(string)
31
+ end
32
+ end
33
+
34
+ describe "#re2_match" do
35
+ it "delegates to RE2::Regexp#match to perform matches", :aggregate_failures do
36
+ md = "My name is Robert Paulson".re2_match('My name is (\S+) (\S+)')
37
+
38
+ expect(md).to be_a(RE2::MatchData)
39
+ expect(md[0]).to eq("My name is Robert Paulson")
40
+ expect(md[1]).to eq("Robert")
41
+ expect(md[2]).to eq("Paulson")
42
+ end
43
+
44
+ it "supports limiting the number of matches" do
45
+ md = "My name is Robert Paulson".re2_match('My name is (\S+) (\S+)', 0)
46
+
47
+ expect(md).to eq(true)
48
+ end
49
+ end
50
+
51
+ describe "#re2_escape" do
52
+ it "escapes the string for use in regular expressions" do
53
+ expect("1.5-2.0?".re2_escape).to eq('1\.5\-2\.0\?')
54
+ end
55
+ end
56
+
57
+ describe "#re2_quote" do
58
+ it "escapes the string for use in regular expressions" do
59
+ expect("1.5-2.0?".re2_quote).to eq('1\.5\-2\.0\?')
60
+ end
61
+ end
62
+ end