1# -*- coding: utf-8 -*-
2# frozen_string_literal: true
3#
4# test/strscan/test_stringscanner.rb
5#
6
7require 'strscan'
8require 'test/unit'
9
10class TestStringScanner < Test::Unit::TestCase
11  def test_s_new
12    s = StringScanner.new('test string')
13    assert_instance_of StringScanner, s
14    assert_equal false, s.eos?
15    assert_equal false, s.tainted?
16
17    str = 'test string'.dup
18    str.taint
19    s = StringScanner.new(str, false)
20    assert_instance_of StringScanner, s
21    assert_equal false, s.eos?
22    assert_same str, s.string
23    assert_equal true, s.string.tainted?
24
25    str = 'test string'.dup
26    str.taint
27    s = StringScanner.new(str)
28    assert_equal true, s.string.tainted?
29  end
30
31  UNINIT_ERROR = ArgumentError
32
33  def test_s_allocate
34    s = StringScanner.allocate
35    assert_equal '#<StringScanner (uninitialized)>', s.inspect.sub(/StringScanner_C/, 'StringScanner')
36    assert_raise(UNINIT_ERROR) { s.eos? }
37    assert_raise(UNINIT_ERROR) { s.scan(/a/) }
38    s.string = 'test'
39    assert_equal '#<StringScanner 0/4 @ "test">', s.inspect.sub(/StringScanner_C/, 'StringScanner')
40    assert_nothing_raised(UNINIT_ERROR) { s.eos? }
41    assert_equal false, s.eos?
42  end
43
44  def test_s_mustc
45    assert_nothing_raised(NotImplementedError) {
46        StringScanner.must_C_version
47    }
48  end
49
50  def test_dup
51    s = StringScanner.new('test string')
52    d = s.dup
53    assert_equal s.inspect, d.inspect
54    assert_equal s.string, d.string
55    assert_equal s.pos, d.pos
56    assert_equal s.matched?, d.matched?
57    assert_equal s.eos?, d.eos?
58
59    s = StringScanner.new('test string')
60    s.scan(/test/)
61    d = s.dup
62    assert_equal s.inspect, d.inspect
63    assert_equal s.string, d.string
64    assert_equal s.pos, d.pos
65    assert_equal s.matched?, d.matched?
66    assert_equal s.eos?, d.eos?
67
68    s = StringScanner.new('test string')
69    s.scan(/test/)
70    s.scan(/NOT MATCH/)
71    d = s.dup
72    assert_equal s.inspect, d.inspect
73    assert_equal s.string, d.string
74    assert_equal s.pos, d.pos
75    assert_equal s.matched?, d.matched?
76    assert_equal s.eos?, d.eos?
77
78    s = StringScanner.new('test string')
79    s.terminate
80    d = s.dup
81    assert_equal s.inspect, d.inspect
82    assert_equal s.string, d.string
83    assert_equal s.pos, d.pos
84    assert_equal s.matched?, d.matched?
85    assert_equal s.eos?, d.eos?
86  end
87
88  def test_const_Version
89    assert_instance_of String, StringScanner::Version
90    assert_equal true, StringScanner::Version.frozen?
91  end
92
93  def test_const_Id
94    assert_instance_of String, StringScanner::Id
95    assert_equal true, StringScanner::Id.frozen?
96  end
97
98  def test_inspect
99    str = 'test string'.dup
100    str.taint
101    s = StringScanner.new(str, false)
102    assert_instance_of String, s.inspect
103    assert_equal s.inspect, s.inspect
104    assert_equal '#<StringScanner 0/11 @ "test ...">', s.inspect.sub(/StringScanner_C/, 'StringScanner')
105    s.get_byte
106    assert_equal '#<StringScanner 1/11 "t" @ "est s...">', s.inspect.sub(/StringScanner_C/, 'StringScanner')
107    assert_equal true, s.inspect.tainted?
108
109    s = StringScanner.new("\n")
110    assert_equal '#<StringScanner 0/1 @ "\n">', s.inspect
111  end
112
113  def test_eos?
114    s = StringScanner.new('test string')
115    assert_equal false, s.eos?
116    assert_equal false, s.eos?
117    s.scan(/\w+/)
118    assert_equal false, s.eos?
119    assert_equal false, s.eos?
120    s.scan(/\s+/)
121    s.scan(/\w+/)
122    assert_equal true, s.eos?
123    assert_equal true, s.eos?
124    s.scan(/\w+/)
125    assert_equal true, s.eos?
126
127    s = StringScanner.new('test'.dup)
128    s.scan(/te/)
129    s.string.replace ''
130    assert_equal true, s.eos?
131  end
132
133  def test_bol?
134    s = StringScanner.new("a\nbbb\n\ncccc\nddd\r\neee")
135    assert_equal true, s.bol?
136    assert_equal true, s.bol?
137    s.scan(/a/)
138    assert_equal false, s.bol?
139    assert_equal false, s.bol?
140    s.scan(/\n/)
141    assert_equal true, s.bol?
142    s.scan(/b/)
143    assert_equal false, s.bol?
144    s.scan(/b/)
145    assert_equal false, s.bol?
146    s.scan(/b/)
147    assert_equal false, s.bol?
148    s.scan(/\n/)
149    assert_equal true, s.bol?
150    s.unscan
151    assert_equal false, s.bol?
152    s.scan(/\n/)
153    s.scan(/\n/)
154    assert_equal true, s.bol?
155    s.scan(/c+\n/)
156    assert_equal true, s.bol?
157    s.scan(/d+\r\n/)
158    assert_equal true, s.bol?
159    s.scan(/e+/)
160    assert_equal false, s.bol?
161  end
162
163  def test_string
164    s = StringScanner.new('test')
165    assert_equal 'test', s.string
166    s.string = 'a'
167    assert_equal 'a', s.string
168    s.scan(/a/)
169    s.string = 'b'
170    assert_equal 0, s.pos
171  end
172
173  def test_string_set_is_equal
174    name = 'tenderlove'
175
176    s = StringScanner.new(name)
177    assert_equal name.object_id, s.string.object_id
178
179    s.string = name
180    assert_equal name.object_id, s.string.object_id
181  end
182
183  def test_string_append
184    s = StringScanner.new('tender'.dup)
185    s << 'love'
186    assert_equal 'tenderlove', s.string
187
188    s.string = 'tender'.dup
189    s << 'love'
190    assert_equal 'tenderlove', s.string
191  end
192
193  def test_pos
194    s = StringScanner.new('test string')
195    assert_equal 0, s.pos
196    s.get_byte
197    assert_equal 1, s.pos
198    s.get_byte
199    assert_equal 2, s.pos
200    s.terminate
201    assert_equal 11, s.pos
202  end
203
204  def test_pos_unicode
205    s = StringScanner.new("abcädeföghi")
206    assert_equal 0, s.charpos
207    assert_equal "abcä", s.scan_until(/ä/)
208    assert_equal 4, s.charpos
209    assert_equal "defö", s.scan_until(/ö/)
210    assert_equal 8, s.charpos
211    s.terminate
212    assert_equal 11, s.charpos
213  end
214
215  def test_concat
216    s = StringScanner.new('a'.dup)
217    s.scan(/a/)
218    s.concat 'b'
219    assert_equal false, s.eos?
220    assert_equal 'b', s.scan(/b/)
221    assert_equal true, s.eos?
222    s.concat 'c'
223    assert_equal false, s.eos?
224    assert_equal 'c', s.scan(/c/)
225    assert_equal true, s.eos?
226  end
227
228  def test_scan
229    s = StringScanner.new('stra strb strc', true)
230    tmp = s.scan(/\w+/)
231    assert_equal 'stra', tmp
232    assert_equal false, tmp.tainted?
233
234    tmp = s.scan(/\s+/)
235    assert_equal ' ', tmp
236    assert_equal false, tmp.tainted?
237
238    assert_equal 'strb', s.scan(/\w+/)
239    assert_equal ' ',    s.scan(/\s+/)
240
241    tmp = s.scan(/\w+/)
242    assert_equal 'strc', tmp
243    assert_equal false, tmp.tainted?
244
245    assert_nil           s.scan(/\w+/)
246    assert_nil           s.scan(/\w+/)
247
248
249    str = 'stra strb strc'.dup
250    str.taint
251    s = StringScanner.new(str, false)
252    tmp = s.scan(/\w+/)
253    assert_equal 'stra', tmp
254    assert_equal true, tmp.tainted?
255
256    tmp = s.scan(/\s+/)
257    assert_equal ' ', tmp
258    assert_equal true, tmp.tainted?
259
260    assert_equal 'strb', s.scan(/\w+/)
261    assert_equal ' ',    s.scan(/\s+/)
262
263    tmp = s.scan(/\w+/)
264    assert_equal 'strc', tmp
265    assert_equal true, tmp.tainted?
266
267    assert_nil           s.scan(/\w+/)
268    assert_nil           s.scan(/\w+/)
269
270    s = StringScanner.new('test'.dup)
271    s.scan(/te/)
272    # This assumes #string does not duplicate string,
273    # but it is implementation specific issue.
274    # DO NOT RELY ON THIS FEATURE.
275    s.string.replace ''
276    # unspecified: assert_equal 2, s.pos
277    assert_equal nil, s.scan(/test/)
278
279    # [ruby-bugs:4361]
280    s = StringScanner.new("")
281    assert_equal "", s.scan(//)
282    assert_equal "", s.scan(//)
283  end
284
285  def test_skip
286    s = StringScanner.new('stra strb strc', true)
287    assert_equal 4, s.skip(/\w+/)
288    assert_equal 1, s.skip(/\s+/)
289    assert_equal 4, s.skip(/\w+/)
290    assert_equal 1, s.skip(/\s+/)
291    assert_equal 4, s.skip(/\w+/)
292    assert_nil      s.skip(/\w+/)
293    assert_nil      s.skip(/\s+/)
294    assert_equal true, s.eos?
295
296    s = StringScanner.new('test'.dup)
297    s.scan(/te/)
298    s.string.replace ''
299    assert_equal nil, s.skip(/./)
300
301    # [ruby-bugs:4361]
302    s = StringScanner.new("")
303    assert_equal 0, s.skip(//)
304    assert_equal 0, s.skip(//)
305  end
306
307  def test_getch
308    s = StringScanner.new('abcde')
309    assert_equal 'a', s.getch
310    assert_equal 'b', s.getch
311    assert_equal 'c', s.getch
312    assert_equal 'd', s.getch
313    assert_equal 'e', s.getch
314    assert_nil        s.getch
315
316    str = 'abc'.dup
317    str.taint
318    s = StringScanner.new(str)
319    assert_equal true, s.getch.tainted?
320    assert_equal true, s.getch.tainted?
321    assert_equal true, s.getch.tainted?
322    assert_nil s.getch
323
324    s = StringScanner.new("\244\242".dup.force_encoding("euc-jp"))
325    assert_equal "\244\242".dup.force_encoding("euc-jp"), s.getch
326    assert_nil s.getch
327
328    s = StringScanner.new('test'.dup)
329    s.scan(/te/)
330    s.string.replace ''
331    assert_equal nil, s.getch
332  end
333
334  def test_get_byte
335    s = StringScanner.new('abcde')
336    assert_equal 'a', s.get_byte
337    assert_equal 'b', s.get_byte
338    assert_equal 'c', s.get_byte
339    assert_equal 'd', s.get_byte
340    assert_equal 'e', s.get_byte
341    assert_nil        s.get_byte
342    assert_nil        s.get_byte
343
344    str = 'abc'.dup
345    str.taint
346    s = StringScanner.new(str)
347    assert_equal true, s.get_byte.tainted?
348    assert_equal true, s.get_byte.tainted?
349    assert_equal true, s.get_byte.tainted?
350    assert_nil s.get_byte
351
352    s = StringScanner.new("\244\242".dup.force_encoding("euc-jp"))
353    assert_equal "\244".dup.force_encoding("euc-jp"), s.get_byte
354    assert_equal "\242".dup.force_encoding("euc-jp"), s.get_byte
355    assert_nil s.get_byte
356
357    s = StringScanner.new('test'.dup)
358    s.scan(/te/)
359    s.string.replace ''
360    assert_equal nil, s.get_byte
361  end
362
363  def test_matched
364    s = StringScanner.new('stra strb strc')
365    s.scan(/\w+/)
366    assert_equal 'stra', s.matched
367    assert_equal false, s.matched.tainted?
368    s.scan(/\s+/)
369    assert_equal ' ', s.matched
370    s.scan(/\w+/)
371    assert_equal 'strb', s.matched
372    s.scan(/\s+/)
373    assert_equal ' ', s.matched
374    s.scan(/\w+/)
375    assert_equal 'strc', s.matched
376    s.scan(/\w+/)
377    assert_nil s.matched
378    s.getch
379    assert_nil s.matched
380
381    s = StringScanner.new('stra strb strc')
382    s.getch
383    assert_equal 's', s.matched
384    assert_equal false, s.matched.tainted?
385    s.get_byte
386    assert_equal 't', s.matched
387    assert_equal 't', s.matched
388    assert_equal false, s.matched.tainted?
389
390    str = 'test'.dup
391    str.taint
392    s = StringScanner.new(str)
393    s.scan(/\w+/)
394    assert_equal true, s.matched.tainted?
395    assert_equal true, s.matched.tainted?
396  end
397
398  def test_AREF
399    s = StringScanner.new('stra strb strc')
400
401    s.scan(/\w+/)
402    assert_nil           s[-2]
403    assert_equal 'stra', s[-1]
404    assert_equal 'stra', s[0]
405    assert_nil           s[1]
406    assert_raise(IndexError) { s[:c] }
407    assert_raise(IndexError) { s['c'] }
408
409    assert_equal false,  s[-1].tainted?
410    assert_equal false,  s[0].tainted?
411
412    s.skip(/\s+/)
413    assert_nil           s[-2]
414    assert_equal ' ',    s[-1]
415    assert_equal ' ',    s[0]
416    assert_nil           s[1]
417
418    s.scan(/(s)t(r)b/)
419    assert_nil           s[-100]
420    assert_nil           s[-4]
421    assert_equal 'strb', s[-3]
422    assert_equal 's',    s[-2]
423    assert_equal 'r',    s[-1]
424    assert_equal 'strb', s[0]
425    assert_equal 's',    s[1]
426    assert_equal 'r',    s[2]
427    assert_nil           s[3]
428    assert_nil           s[100]
429
430    s.scan(/\s+/)
431
432    s.getch
433    assert_nil           s[-2]
434    assert_equal 's',    s[-1]
435    assert_equal 's',    s[0]
436    assert_nil           s[1]
437
438    s.get_byte
439    assert_nil           s[-2]
440    assert_equal 't',    s[-1]
441    assert_equal 't',    s[0]
442    assert_nil           s[1]
443
444    s.scan(/.*/)
445    s.scan(/./)
446    assert_nil           s[0]
447    assert_nil           s[0]
448
449
450    s = StringScanner.new("\244\242".dup.force_encoding("euc-jp"))
451    s.getch
452    assert_equal "\244\242".dup.force_encoding("euc-jp"), s[0]
453
454    str = 'test'.dup
455    str.taint
456    s = StringScanner.new(str)
457    s.scan(/(t)(e)(s)(t)/)
458    assert_equal true, s[0].tainted?
459    assert_equal true, s[1].tainted?
460    assert_equal true, s[2].tainted?
461    assert_equal true, s[3].tainted?
462    assert_equal true, s[4].tainted?
463
464    s = StringScanner.new("foo bar baz")
465    s.scan(/(?<a>\w+) (?<b>\w+) (\w+)/)
466    assert_equal 'foo', s[1]
467    assert_equal 'bar', s[2]
468    assert_nil s[3]
469    assert_equal 'foo', s[:a]
470    assert_equal 'bar', s[:b]
471    assert_raise(IndexError) { s[:c] }
472    assert_equal 'foo', s['a']
473    assert_equal 'bar', s['b']
474    assert_raise(IndexError) { s['c'] }
475    assert_raise_with_message(IndexError, /\u{30c6 30b9 30c8}/) { s["\u{30c6 30b9 30c8}"] }
476  end
477
478  def test_pre_match
479    s = StringScanner.new('a b c d e')
480    s.scan(/\w/)
481    assert_equal '', s.pre_match
482    assert_equal false, s.pre_match.tainted?
483    s.skip(/\s/)
484    assert_equal 'a', s.pre_match
485    assert_equal false, s.pre_match.tainted?
486    s.scan(/\w/)
487    assert_equal 'a ', s.pre_match
488    s.scan_until(/c/)
489    assert_equal 'a b ', s.pre_match
490    s.getch
491    assert_equal 'a b c', s.pre_match
492    s.get_byte
493    assert_equal 'a b c ', s.pre_match
494    s.get_byte
495    assert_equal 'a b c d', s.pre_match
496    s.scan(/never match/)
497    assert_nil s.pre_match
498
499    str = 'test string'.dup
500    str.taint
501    s = StringScanner.new(str)
502    s.scan(/\w+/)
503    assert_equal true, s.pre_match.tainted?
504    s.scan(/\s+/)
505    assert_equal true, s.pre_match.tainted?
506    s.scan(/\w+/)
507    assert_equal true, s.pre_match.tainted?
508  end
509
510  def test_post_match
511    s = StringScanner.new('a b c d e')
512    s.scan(/\w/)
513    assert_equal ' b c d e', s.post_match
514    s.skip(/\s/)
515    assert_equal 'b c d e', s.post_match
516    s.scan(/\w/)
517    assert_equal ' c d e', s.post_match
518    s.scan_until(/c/)
519    assert_equal ' d e', s.post_match
520    s.getch
521    assert_equal 'd e', s.post_match
522    s.get_byte
523    assert_equal ' e', s.post_match
524    s.get_byte
525    assert_equal 'e', s.post_match
526    s.scan(/never match/)
527    assert_nil s.post_match
528    s.scan(/./)
529    assert_equal '', s.post_match
530    s.scan(/./)
531    assert_nil s.post_match
532
533    str = 'test string'.dup
534    str.taint
535    s = StringScanner.new(str)
536    s.scan(/\w+/)
537    assert_equal true, s.post_match.tainted?
538    s.scan(/\s+/)
539    assert_equal true, s.post_match.tainted?
540    s.scan(/\w+/)
541    assert_equal true, s.post_match.tainted?
542  end
543
544  def test_terminate
545    s = StringScanner.new('ssss')
546    s.getch
547    s.terminate
548    assert_equal true, s.eos?
549    s.terminate
550    assert_equal true, s.eos?
551  end
552
553  def test_reset
554    s = StringScanner.new('ssss')
555    s.getch
556    s.reset
557    assert_equal 0, s.pos
558    s.scan(/\w+/)
559    s.reset
560    assert_equal 0, s.pos
561    s.reset
562    assert_equal 0, s.pos
563  end
564
565  def test_matched_size
566    s = StringScanner.new('test string')
567    assert_nil s.matched_size
568    s.scan(/test/)
569    assert_equal 4, s.matched_size
570    assert_equal 4, s.matched_size
571    s.scan(//)
572    assert_equal 0, s.matched_size
573    s.scan(/x/)
574    assert_nil s.matched_size
575    assert_nil s.matched_size
576    s.terminate
577    assert_nil s.matched_size
578
579    s = StringScanner.new('test string')
580    assert_nil s.matched_size
581    s.scan(/test/)
582    assert_equal 4, s.matched_size
583    s.terminate
584    assert_nil s.matched_size
585  end
586
587  def test_encoding
588    ss = StringScanner.new("\xA1\xA2".dup.force_encoding("euc-jp"))
589    assert_equal(Encoding::EUC_JP, ss.scan(/./e).encoding)
590  end
591
592  def test_generic_regexp
593    ss = StringScanner.new("\xA1\xA2".dup.force_encoding("euc-jp"))
594    t = ss.scan(/./)
595    assert_equal("\xa1\xa2".dup.force_encoding("euc-jp"), t)
596  end
597
598  def test_set_pos
599    s = StringScanner.new("test string")
600    s.pos = 7
601    assert_equal("ring", s.rest)
602  end
603
604  def test_match_p
605    s = StringScanner.new("test string")
606    assert_equal(4, s.match?(/\w+/))
607    assert_equal(4, s.match?(/\w+/))
608    assert_equal(nil, s.match?(/\s+/))
609  end
610
611  def test_check
612    s = StringScanner.new("Foo Bar Baz")
613    assert_equal("Foo", s.check(/Foo/))
614    assert_equal(0, s.pos)
615    assert_equal("Foo", s.matched)
616    assert_equal(nil, s.check(/Bar/))
617    assert_equal(nil, s.matched)
618  end
619
620  def test_scan_full
621    s = StringScanner.new("Foo Bar Baz")
622    assert_equal(4, s.scan_full(/Foo /, false, false))
623    assert_equal(0, s.pos)
624    assert_equal(nil, s.scan_full(/Baz/, false, false))
625    assert_equal("Foo ", s.scan_full(/Foo /, false, true))
626    assert_equal(0, s.pos)
627    assert_equal(nil, s.scan_full(/Baz/, false, false))
628    assert_equal(4, s.scan_full(/Foo /, true, false))
629    assert_equal(4, s.pos)
630    assert_equal(nil, s.scan_full(/Baz /, false, false))
631    assert_equal("Bar ", s.scan_full(/Bar /, true, true))
632    assert_equal(8, s.pos)
633    assert_equal(nil, s.scan_full(/az/, false, false))
634  end
635
636  def test_exist_p
637    s = StringScanner.new("test string")
638    assert_equal(3, s.exist?(/s/))
639    assert_equal(0, s.pos)
640    s.scan(/test/)
641    assert_equal(2, s.exist?(/s/))
642    assert_equal(4, s.pos)
643    assert_equal(nil, s.exist?(/e/))
644  end
645
646  def test_skip_until
647    s = StringScanner.new("Foo Bar Baz")
648    assert_equal(3, s.skip_until(/Foo/))
649    assert_equal(3, s.pos)
650    assert_equal(4, s.skip_until(/Bar/))
651    assert_equal(7, s.pos)
652    assert_equal(nil, s.skip_until(/Qux/))
653  end
654
655  def test_check_until
656    s = StringScanner.new("Foo Bar Baz")
657    assert_equal("Foo", s.check_until(/Foo/))
658    assert_equal(0, s.pos)
659    assert_equal("Foo Bar", s.check_until(/Bar/))
660    assert_equal(0, s.pos)
661    assert_equal(nil, s.check_until(/Qux/))
662  end
663
664  def test_search_full
665    s = StringScanner.new("Foo Bar Baz")
666    assert_equal(8, s.search_full(/Bar /, false, false))
667    assert_equal(0, s.pos)
668    assert_equal("Foo Bar ", s.search_full(/Bar /, false, true))
669    assert_equal(0, s.pos)
670    assert_equal(8, s.search_full(/Bar /, true, false))
671    assert_equal(8, s.pos)
672    assert_equal("Baz", s.search_full(/az/, true, true))
673    assert_equal(11, s.pos)
674  end
675
676  def test_peek
677    s = StringScanner.new("test string")
678    assert_equal("test st", s.peek(7))
679    assert_equal("test st", s.peek(7))
680    s.scan(/test/)
681    assert_equal(" stri", s.peek(5))
682    assert_equal(" string", s.peek(10))
683    s.scan(/ string/)
684    assert_equal("", s.peek(10))
685  end
686
687  def test_unscan
688    s = StringScanner.new('test string')
689    assert_equal("test", s.scan(/\w+/))
690    s.unscan
691    assert_equal("te", s.scan(/../))
692    assert_equal(nil, s.scan(/\d/))
693    assert_raise(ScanError) { s.unscan }
694  end
695
696  def test_rest
697    s = StringScanner.new('test string')
698    assert_equal("test string", s.rest)
699    s.scan(/test/)
700    assert_equal(" string", s.rest)
701    s.scan(/ string/)
702    assert_equal("", s.rest)
703    s.scan(/ string/)
704  end
705
706  def test_rest_size
707    s = StringScanner.new('test string')
708    assert_equal(11, s.rest_size)
709    s.scan(/test/)
710    assert_equal(7, s.rest_size)
711    s.scan(/ string/)
712    assert_equal(0, s.rest_size)
713    s.scan(/ string/)
714  end
715
716  def test_inspect2
717    s = StringScanner.new('test string test')
718    s.scan(/test strin/)
719    assert_equal('#<StringScanner 10/16 "...strin" @ "g tes...">', s.inspect)
720  end
721
722  def test_aref_without_regex
723    s = StringScanner.new('abc')
724    s.get_byte
725    assert_nil(s[:c])
726    assert_nil(s["c"])
727    s.getch
728    assert_nil(s[:c])
729    assert_nil(s["c"])
730  end
731
732  def test_size
733    s = StringScanner.new("Fri Dec 12 1975 14:39")
734    s.scan(/(\w+) (\w+) (\d+) /)
735    assert_equal(4, s.size)
736  end
737
738  def test_captures
739    s = StringScanner.new("Fri Dec 12 1975 14:39")
740    s.scan(/(\w+) (\w+) (\d+) /)
741    assert_equal(["Fri", "Dec", "12"], s.captures)
742    s.scan(/(\w+) (\w+) (\d+) /)
743    assert_nil(s.captures)
744  end
745
746  def test_values_at
747    s = StringScanner.new("Fri Dec 12 1975 14:39")
748    s.scan(/(\w+) (\w+) (\d+) /)
749    assert_equal(["Fri Dec 12 ", "12", nil, "Dec"], s.values_at(0, -1, 5, 2))
750    s.scan(/(\w+) (\w+) (\d+) /)
751    assert_nil(s.values_at(0, -1, 5, 2))
752  end
753end
754