re2 2.23.0 → 2.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,56 @@ RSpec.describe RE2::Scanner do
8
8
 
9
9
  expect(scanner.regexp).to equal(re)
10
10
  end
11
+
12
+ it "raises an error when called on an uninitialized object" do
13
+ expect { described_class.allocate.regexp }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
14
+ end
15
+ end
16
+
17
+ describe "#dup" do
18
+ it "returns a usable copy of the scanner at the same position" do
19
+ scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
20
+ scanner.scan
21
+
22
+ copy = scanner.dup
23
+
24
+ expect(copy.scan).to eq(["bar"])
25
+ end
26
+
27
+ it "creates an independent copy" do
28
+ scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
29
+ scanner.scan
30
+
31
+ copy = scanner.dup
32
+ copy.scan
33
+
34
+ expect(scanner.scan).to eq(["bar"])
35
+ end
36
+
37
+ it "copies the EOF state of the scanner" do
38
+ scanner = RE2::Regexp.new('(\w+)').scan("foo")
39
+ scanner.scan
40
+ scanner.scan
41
+
42
+ copy = scanner.dup
43
+
44
+ expect(copy).to be_eof
45
+ end
46
+
47
+ it "raises an error when called on an uninitialized object" do
48
+ expect { described_class.allocate.dup }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
49
+ end
50
+ end
51
+
52
+ describe "#clone" do
53
+ it "returns a usable copy of the scanner at the same position" do
54
+ scanner = RE2::Regexp.new('(\w+)').scan("foo bar baz")
55
+ scanner.scan
56
+
57
+ copy = scanner.clone
58
+
59
+ expect(copy.scan).to eq(["bar"])
60
+ end
11
61
  end
12
62
 
13
63
  describe "#string" do
@@ -50,6 +100,10 @@ RSpec.describe RE2::Scanner do
50
100
 
51
101
  expect(scanner.string).to equal(text)
52
102
  end
103
+
104
+ it "raises an error when called on an uninitialized object" do
105
+ expect { described_class.allocate.string }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
106
+ end
53
107
  end
54
108
 
55
109
  describe "#scan" do
@@ -131,11 +185,11 @@ RSpec.describe RE2::Scanner do
131
185
  expect(scanner.scan).to be_nil
132
186
  end
133
187
 
134
- it "returns an array of nil with an empty input and capture", :aggregate_failures do
188
+ it "returns an array of empty strings with an empty input and capture", :aggregate_failures do
135
189
  r = RE2::Regexp.new("()")
136
190
  scanner = r.scan("")
137
191
 
138
- expect(scanner.scan).to eq([nil])
192
+ expect(scanner.scan).to eq([""])
139
193
  expect(scanner.scan).to be_nil
140
194
  end
141
195
 
@@ -150,25 +204,34 @@ RSpec.describe RE2::Scanner do
150
204
  expect(scanner.scan).to be_nil
151
205
  end
152
206
 
153
- it "returns an array of nil if the pattern is an empty capturing group", :aggregate_failures do
207
+ it "returns an array of empty strings if the pattern is an empty capturing group", :aggregate_failures do
154
208
  r = RE2::Regexp.new("()")
155
209
  scanner = r.scan("Foo")
156
210
 
157
- expect(scanner.scan).to eq([nil])
158
- expect(scanner.scan).to eq([nil])
159
- expect(scanner.scan).to eq([nil])
160
- expect(scanner.scan).to eq([nil])
211
+ expect(scanner.scan).to eq([""])
212
+ expect(scanner.scan).to eq([""])
213
+ expect(scanner.scan).to eq([""])
214
+ expect(scanner.scan).to eq([""])
161
215
  expect(scanner.scan).to be_nil
162
216
  end
163
217
 
164
- it "returns array of nils with multiple empty capturing groups", :aggregate_failures do
218
+ it "returns array of empty strings with multiple empty capturing groups", :aggregate_failures do
165
219
  r = RE2::Regexp.new("()()()")
166
220
  scanner = r.scan("Foo")
167
221
 
168
- expect(scanner.scan).to eq([nil, nil, nil])
169
- expect(scanner.scan).to eq([nil, nil, nil])
170
- expect(scanner.scan).to eq([nil, nil, nil])
171
- expect(scanner.scan).to eq([nil, nil, nil])
222
+ expect(scanner.scan).to eq(["", "", ""])
223
+ expect(scanner.scan).to eq(["", "", ""])
224
+ expect(scanner.scan).to eq(["", "", ""])
225
+ expect(scanner.scan).to eq(["", "", ""])
226
+ expect(scanner.scan).to be_nil
227
+ end
228
+
229
+ it "distinguishes zero-length matches from unmatched groups", :aggregate_failures do
230
+ r = RE2::Regexp.new("()(a)?")
231
+ scanner = r.scan("b")
232
+
233
+ expect(scanner.scan).to eq(["", nil])
234
+ expect(scanner.scan).to eq(["", nil])
172
235
  expect(scanner.scan).to be_nil
173
236
  end
174
237
 
@@ -176,7 +239,53 @@ RSpec.describe RE2::Scanner do
176
239
  r = RE2::Regexp.new("()€")
177
240
  scanner = r.scan("€")
178
241
 
179
- expect(scanner.scan).to eq([nil])
242
+ expect(scanner.scan).to eq([""])
243
+ expect(scanner.scan).to be_nil
244
+ end
245
+
246
+ it "advances by whole characters with zero-width matches on 2-byte UTF-8 input", :aggregate_failures do
247
+ r = RE2::Regexp.new("")
248
+ scanner = r.scan("à")
249
+
250
+ expect(scanner.scan).to eq([])
251
+ expect(scanner.scan).to eq([])
252
+ expect(scanner.scan).to be_nil
253
+ end
254
+
255
+ it "advances by whole characters with zero-width matches on 3-byte UTF-8 input", :aggregate_failures do
256
+ r = RE2::Regexp.new("")
257
+ scanner = r.scan("\u20AC")
258
+
259
+ expect(scanner.scan).to eq([])
260
+ expect(scanner.scan).to eq([])
261
+ expect(scanner.scan).to be_nil
262
+ end
263
+
264
+ it "advances by whole characters with zero-width matches on 4-byte UTF-8 input", :aggregate_failures do
265
+ r = RE2::Regexp.new("")
266
+ scanner = r.scan("\u{1F600}")
267
+
268
+ expect(scanner.scan).to eq([])
269
+ expect(scanner.scan).to eq([])
270
+ expect(scanner.scan).to be_nil
271
+ end
272
+
273
+ it "advances by single bytes with zero-width matches on Latin-1 input", :aggregate_failures do
274
+ r = RE2::Regexp.new("", utf8: false)
275
+ scanner = r.scan("\xC3\xA0")
276
+
277
+ expect(scanner.scan).to eq([])
278
+ expect(scanner.scan).to eq([])
279
+ expect(scanner.scan).to eq([])
280
+ expect(scanner.scan).to be_nil
281
+ end
282
+
283
+ it "handles truncated multi-byte sequences at the end of input", :aggregate_failures do
284
+ r = RE2::Regexp.new("")
285
+ scanner = r.scan("\xC3")
286
+
287
+ expect(scanner.scan).to eq([])
288
+ expect(scanner.scan).to eq([])
180
289
  expect(scanner.scan).to be_nil
181
290
  end
182
291
 
@@ -211,6 +320,10 @@ RSpec.describe RE2::Scanner do
211
320
 
212
321
  expect(scanner.scan).to eq(["It"])
213
322
  end
323
+
324
+ it "raises an error when called on an uninitialized object" do
325
+ expect { described_class.allocate.scan }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
326
+ end
214
327
  end
215
328
 
216
329
  it "is enumerable" do
@@ -272,6 +385,10 @@ RSpec.describe RE2::Scanner do
272
385
 
273
386
  expect(scanner).not_to be_eof
274
387
  end
388
+
389
+ it "raises an error when called on an uninitialized object" do
390
+ expect { described_class.allocate.rewind }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
391
+ end
275
392
  end
276
393
 
277
394
  describe "#eof?" do
@@ -320,5 +437,9 @@ RSpec.describe RE2::Scanner do
320
437
 
321
438
  expect(scanner).to be_eof
322
439
  end
440
+
441
+ it "raises an error when called on an uninitialized object" do
442
+ expect { described_class.allocate.eof? }.to raise_error(TypeError, /uninitialized RE2::Scanner/)
443
+ end
323
444
  end
324
445
  end
data/spec/re2/set_spec.rb CHANGED
@@ -51,6 +51,18 @@ RSpec.describe RE2::Set do
51
51
  end
52
52
  end
53
53
 
54
+ describe "#dup" do
55
+ it "raises a TypeError" do
56
+ expect { described_class.new.dup }.to raise_error(TypeError, /cannot copy RE2::Set/)
57
+ end
58
+ end
59
+
60
+ describe "#clone" do
61
+ it "raises a TypeError" do
62
+ expect { described_class.new.clone }.to raise_error(TypeError, /cannot copy RE2::Set/)
63
+ end
64
+ end
65
+
54
66
  describe "#add" do
55
67
  it "allows multiple patterns to be added", :aggregate_failures do
56
68
  set = RE2::Set.new
@@ -72,14 +84,12 @@ RSpec.describe RE2::Set do
72
84
  expect { set.add("(?P<#{'o' * 200}") }.to raise_error(ArgumentError, "str rejected by RE2::Set->Add(): invalid named capture group: (?P<oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo")
73
85
  end
74
86
 
75
- it "raises an error if called after #compile" do
87
+ it "raises a FrozenError if called after #compile" do
76
88
  set = RE2::Set.new(:unanchored, log_errors: false)
77
89
  set.add("abc")
78
90
  set.compile
79
91
 
80
- silence_stderr do
81
- expect { set.add("def") }.to raise_error(ArgumentError)
82
- end
92
+ expect { set.add("def") }.to raise_error(FrozenError)
83
93
  end
84
94
 
85
95
  it "raises an error if given a pattern that can't be coerced to a String" do
@@ -93,6 +103,10 @@ RSpec.describe RE2::Set do
93
103
 
94
104
  expect(set.add(StringLike.new("abc"))).to eq(0)
95
105
  end
106
+
107
+ it "raises an error when called on an uninitialized object" do
108
+ expect { described_class.allocate.add("foo") }.to raise_error(TypeError, /uninitialized RE2::Set/)
109
+ end
96
110
  end
97
111
 
98
112
  describe "#compile" do
@@ -104,6 +118,33 @@ RSpec.describe RE2::Set do
104
118
 
105
119
  expect(set.compile).to be_truthy
106
120
  end
121
+
122
+ it "freezes the set on successful compilation" do
123
+ set = RE2::Set.new
124
+ set.add("abc")
125
+ set.compile
126
+
127
+ expect(set).to be_frozen
128
+ end
129
+
130
+ it "is not frozen before compilation" do
131
+ set = RE2::Set.new
132
+ set.add("abc")
133
+
134
+ expect(set).to_not be_frozen
135
+ end
136
+
137
+ it "cannot be re-initialized after compilation" do
138
+ set = RE2::Set.new
139
+ set.add("abc")
140
+ set.compile
141
+
142
+ expect { set.send(:initialize) }.to raise_error(FrozenError)
143
+ end
144
+
145
+ it "raises an error when called on an uninitialized object" do
146
+ expect { described_class.allocate.compile }.to raise_error(TypeError, /uninitialized RE2::Set/)
147
+ end
107
148
  end
108
149
 
109
150
  describe "#match" do
@@ -202,6 +243,24 @@ RSpec.describe RE2::Set do
202
243
 
203
244
  expect(set.match(StringLike.new("abcdef"), exception: false)).to contain_exactly(0)
204
245
  end
246
+
247
+ it "raises an error when called on an uninitialized object" do
248
+ expect { described_class.allocate.match("foo") }.to raise_error(TypeError, /uninitialized RE2::Set/)
249
+ end
250
+
251
+ it "can be run concurrently" do
252
+ set = RE2::Set.new
253
+ set.add("abc")
254
+ set.add("def")
255
+ set.add("ghi")
256
+ set.compile
257
+
258
+ threads = 10.times.map do
259
+ Thread.new { set.match("abcdefghi", exception: false) }
260
+ end
261
+
262
+ expect(threads.map(&:value)).to all(eq([0, 1, 2]))
263
+ end
205
264
  end
206
265
 
207
266
  describe "#size" do
@@ -228,6 +287,12 @@ RSpec.describe RE2::Set do
228
287
 
229
288
  expect { set.size }.to raise_error(RE2::Set::UnsupportedError)
230
289
  end
290
+
291
+ it "raises an error when called on an uninitialized object" do
292
+ skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
293
+
294
+ expect { described_class.allocate.size }.to raise_error(TypeError, /uninitialized RE2::Set/)
295
+ end
231
296
  end
232
297
 
233
298
  describe "#length" do
@@ -246,6 +311,12 @@ RSpec.describe RE2::Set do
246
311
 
247
312
  expect(set.length).to eq(2)
248
313
  end
314
+
315
+ it "raises an error when called on an uninitialized object" do
316
+ skip "Underlying RE2::Set has no Size method" unless RE2::Set.size?
317
+
318
+ expect { described_class.allocate.length }.to raise_error(TypeError, /uninitialized RE2::Set/)
319
+ end
249
320
  end
250
321
 
251
322
  def silence_stderr