2 # Copyright (C) 2001-2008, The Perl Foundation.
8 t/compilers/pge/p5regex/p5rx.t - Perl 5 Regular Expression tests
12 These tests are ripped from the Perl 5.9.2 distribution. The test harness
13 has been modified to feed them to PGE's P5Regex compiler. The tests are
14 in a separate file in the same directory, named 're_tests'.
16 This test harness honors a special environment variable called C<TEST_P5RX>.
17 If set to a number, that test will be run alone and unconditionally--even
18 if it's designated as SKIP or TODO by the harness. This is quite helpful
19 in debugging tests that cause parrot to spiral out of control. {{ XXX }}
21 B<NOTE:> Don't add new tests to C<re_tests>. That file is strictly for
24 The Perl 5 equivalent file provides the following description of the test
25 format. There are 5-6 columns, separated by tabs.
27 Column 1 contains the pattern, optionally enclosed in C<''>.
28 Modifiers can be put after the closing C<'>.
30 Column 2 contains the string to be matched.
32 Column 3 contains the expected result:
36 B test exposes a known bug in Perl, should be skipped
37 b test exposes a known bug in Perl, should be skipped if noamp
39 Columns 4 and 5 are used only if column 3 contains C<y> or C<c>.
41 Column 4 contains a string, usually C<$&>.
43 Column 5 contains the expected result of double-quote
44 interpolating that string after the match, or start of error message.
46 Column 6, if present, contains a description of what is being tested.
48 \n in the tests are interpolated, as are variables of the form ${\w+}.
52 % prove t/compilers/pge/p5regex/p5rx.t
56 .const int TESTS = 960
59 load_bytecode 'Test/Builder.pir'
60 load_bytecode 'PGE.pbc'
61 load_bytecode 'PGE/Dumper.pbc'
62 .include 'iglobals.pasm'
64 # Variable declarations, initializations
65 .local pmc test # the test harness object.
66 test = new [ 'Test'; 'Builder' ]
68 .local pmc todo_tests # keys indicate test file; values test number.
69 todo_tests = new 'Hash'
71 .local pmc skip_tests # keys indicate tests ID; values reasons.
72 skip_tests = new 'Hash'
74 .local string test_dir # the directory containing tests
75 test_dir = 't/compilers/pge/p5regex/'
77 .local pmc test_files # values are test file names to run.
78 test_files = new 'ResizablePMCArray'
80 # populate the list of test files
81 push test_files, 're_tests'
83 .local pmc file_iterator # iterate over list of files..
84 file_iterator = new 'Iterator', test_files
86 .local int test_number # the number of the test we're running
89 # these vars are in the loops below
90 .local pmc file_handle # currently open file.
91 .local string test_file # name of the current test file
92 .local string test_line # one line of one test file, a single test
93 .local int ok # is this a passing test?
96 .local pmc regex # the regex
97 .local pmc match # the match
98 .local string pattern # the regex
99 .local string target # this string to match against the regex
100 .local string result # expected result of this test. (y/n/...)
101 .local string testvar # the value to test against expected results
102 .local string expected # the expected result of the match, or the error
103 .local string description # user-facing description of the test.
105 todo_tests = 'set_todo_info'()
106 skip_tests = 'set_skip_info'()
108 # how many tests to run?
109 # XXX: this should be summed automatically from test_files data
110 # until then, we use the constant above
114 unless file_iterator goto end_outer_loop
115 .local string test_name
116 test_name = shift file_iterator
117 # local test number in test file
118 .local int local_test_number
119 local_test_number = 0
121 # append the test directory and filename
122 test_file = test_dir . test_name
125 file_handle = open test_file, '<'
126 $S0 = typeof file_handle
127 if $S0 == 'Undef' goto bad_file
129 # loop over the file, one at a time.
132 # read in the file one line at a time...
133 $I0 = file_handle.'eof'()
136 test_line = readline file_handle
138 # skip lines without tabs
139 $I0 = index test_line, "\t"
140 if $I0 == -1 goto loop
142 inc local_test_number
146 ( pattern, target, result, testvar, expected, description ) = 'parse_data'( test_line )
149 # build the test description
150 # start with the pattern
151 $S0 = concat '/', pattern
153 # add the test description, if it exists
154 $I0 = length description
155 unless $I0 goto no_desc
156 description = concat '-- ', description
158 description = concat $S0, description
159 # prepend test filename and line number to description
160 description = 'build_test_desc'( description, test_name, local_test_number )
162 if target != "''" goto got_target
166 target = 'backslash_escape'( target )
167 result = 'backslash_escape'( result )
169 # Should this test be skipped?
170 $I0 = exists skip_tests[test_name]
171 unless $I0 goto not_skip
172 $P0 = skip_tests[test_name]
173 $I0 = exists $P0[local_test_number]
174 unless $I0 goto not_skip
175 # extract reason from skip data
176 $S0 = $P0[local_test_number]
177 if $S0 == '1' goto set_skip
178 description = 'build_test_desc'( $S0, test_name, local_test_number )
180 test.'skip'(1, description)
185 match = 'match_p5regex'( pattern, target )
188 if match goto matched
190 if result == 'n' goto is_ok
191 if result == 'y' goto is_nok
195 if result == 'y' goto is_ok
196 if result == 'n' goto is_nok
199 $S1 = match.'dump_str'('mob', ' ', '')
201 $I0 = index $S1, result
202 if $I0 == -1 goto is_nok
211 $I0 = exists todo_tests[test_name]
212 unless $I0 goto not_todo
213 $P0 = todo_tests[test_name]
214 $I0 = exists $P0[local_test_number]
215 unless $I0 goto not_todo
216 # extract reason from todo data
217 $S0 = $P0[local_test_number]
218 if $S0 == '1' goto set_todo
219 description = 'build_test_desc'( $S0, test_name, local_test_number )
221 test.'todo'(ok,description)
224 test.'ok'(ok,description)
226 $S0 = concat 'pattern: /', pattern
227 $S1 = concat '/, target: "', target
229 $S1 = concat '", result: "', result
231 $S1 = concat '", testvar: "', testvar
233 $S1 = concat '", expected: "', expected
236 $S1 = concat '", got: "', $S2
251 print "Unable to open '"
257 .local string message
258 get_results '0,0', exception, message
260 # $S0 = substr result, 0, 1
261 # if $S0 != '/' goto bad_error
262 # substr result, 0, 1, ''
263 # substr result, -1, 1, ''
264 $I0 = index message, expected
265 if $I0 == -1 goto bad_error
272 $S0 = 'Test not formatted properly!'
276 $S0 = 'Test not formatted properly!'
282 # set todo information
284 .local pmc todo_tests # keys indicate test file; values are just defined
285 todo_tests = new 'Hash'
288 todo_info = new 'Hash'
290 .local string test_file
292 test_file = 're_tests'
295 $S0 = 'character class in enumeration'
303 $S0 = 'unknown reason'
304 # todo_info[172] = $S0
305 # todo_info[184] = $S0
306 # todo_info[223] = $S0
307 # todo_info[232] = $S0
308 # todo_info[233] = $S0
312 # todo_info[241] = $S0
313 # todo_info[243] = $S0
314 # todo_info[244] = $S0
317 # todo_info[253] = $S0
321 # todo_info[260] = $S0
322 # todo_info[261] = $S0
330 # todo_info[428] = $S0
336 # todo_info[440] = $S0
337 # todo_info[444] = $S0
338 # todo_info[445] = $S0
380 # todo_info[602] = $S0
383 # todo_info[605] = $S0
403 # todo_info[840] = $S0
406 # todo_info[860] = $S0
407 # todo_info[861] = $S0
409 # todo_info[863] = $S0
412 # todo_info[874] = $S0
413 # todo_info[875] = $S0
414 # todo_info[876] = $S0
416 # todo_info[882] = $S0
422 # todo_info[894] = $S0
423 # todo_info[895] = $S0
428 # todo_info[900] = $S0
430 $S0 = 'reuse captured group'
447 $S0 = 'non-greedy/lookbehind'
451 # todo_info[919] = $S0
452 # todo_info[920] = $S0
456 $S0 = 'greediness/lookbehind'
458 # todo_info[902] = $S0
459 # todo_info[903] = $S0
463 $S0 = 'non-greedy/zero-width assertion'
466 # todo_info[909] = $S0
468 # todo_info[912] = $S0
473 $S0 = '\d in character class'
474 # todo_info[825] = $S0
475 # todo_info[826] = $S0
478 $S0 = '[ID 20010803.016]'
479 # todo_info[884] = $S0
481 $S0 = '[perl #34195]'
484 $S0 = 'undef [perl #16773]'
485 # todo_info[925] = $S0
487 $S0 = 'unmatched bracket'
490 $S0 = '16 tests for [perl #23171]'
493 todo_tests[test_file] = todo_info
498 todo_info = new 'Hash'
501 set_todo_loop: # for developer testing. not used normally
502 if $I0 > $I1 goto end_loop
511 # set skip information
513 .local pmc skip_tests # keys indicate test file; values are just defined
514 skip_tests = new 'Hash'
517 skip_info = new 'Hash'
519 .local string test_file
521 test_file = 're_tests'
524 $S0 = 'trailing modifiers'
618 $S0 = 'broken col 4?'
621 $S0 = 'kills a parrot'
636 $S0 = 'hangs a parrot'
642 $S0 = 'unknown reason'
648 $S0 = '[ID 20010811.006]'
651 $S0 = '[perl #18019]'
657 skip_tests[test_file] = skip_info
662 skip_info = new 'Hash'
665 set_range: # for setting a range of tests
666 if $I0 > $I1 goto end_loop # put range min in $I0, max in $I1
667 if $S0 != '' goto set_skip_info # put skip reason in $S0
668 $S0 = 'unknown reason'
680 .param string test_line # the data record
682 .local pmc regex # the regex matching object
683 .local pmc match # the match
684 .local string pattern # the regex
685 .local string target # this string to match against the regex
686 .local string result # expected result of this test. (y/n/...)
687 .local string testvar # the value to test against expected results
688 .local string expected # the expected result of the match, or the error
689 .local string description # user-facing description of the test.
691 # NOTE: there can be multiple tabs between entries, so skip until
693 # remove the trailing newline from record
696 $P1 = split "\t", test_line
699 unless $P1 goto bad_line
701 if pattern == '' goto get_pattern
703 unless $P1 goto bad_line
706 unless $P1 goto bad_line
708 if result == '' goto get_result
710 unless $P1 goto bad_line
712 if testvar == '' goto get_testvar
714 unless $P1 goto bad_line
720 .return ( pattern, target, result, testvar, expected, description )
723 $P1 = new 'Exception'
724 $P1[0] = 'invalid data format'
729 .sub 'build_test_desc'
731 .param string test_name
732 .param string local_test_number
737 $S0 .= local_test_number
746 .param string pattern
751 .local pmc p5regex # the perl5 regex compiler
752 p5regex = compreg 'PGE::P5Regex'
755 regex = p5regex(pattern)
757 unless_null regex, match_it
758 $P1 = new 'Exception'
759 $P1[0] = 'regex error'
762 match = regex(target)
768 # given a 2 digit string, convert to appropriate chr() value.
772 $S0 = substr hex, 0, 1
773 $S1 = substr hex, 1, 1
787 # given a single digit hex value, return it's int value.
792 if $I0 < 48 goto bad_digit
793 if $I0 > 57 goto non_numeric
797 if $I0 < 65 goto bad_digit
798 if $I0 > 70 goto not_capital
799 $I0 -= 55 # A is ascii 65, so reset to zero, add 10 for hex..
802 if $I0 < 97 goto bad_digit
803 if $I0 > 102 goto bad_digit
804 $I0 -= 87 # a is ascii 97, so reset to zero, add 10 for hex..
808 $P1 = new 'Exception'
809 $P1[0] = 'invalid hex digit'
814 .sub backslash_escape
817 .local int x_pos # position in string of last \x escape..
821 $I0 = index target, '\n'
822 if $I0 == -1 goto target2
823 substr target, $I0, 2, "\n"
826 $I0 = index target, '\r'
827 if $I0 == -1 goto target3
828 substr target, $I0, 2, "\r"
831 $I0 = index target, '\e'
832 if $I0 == -1 goto target4
833 substr target, $I0, 2, "\e"
836 $I0 = index target, '\t'
837 if $I0 == -1 goto target5
838 substr target, $I0, 2, "\t"
841 $I0 = index target, '\f'
842 if $I0 == -1 goto target6
843 substr target, $I0, 2, "\f"
846 # handle \xHH, hex escape.
848 $I0 = index target, '\x', x_pos
849 if $I0 == -1 goto target7
854 if $I2 > $I1 goto target7
855 $S0 = substr target, $I2, 2
857 substr target, $I0, 4, $S1
865 =head1 BUGS AND LIMITATIONS
867 Note that while our job would be easier if we could use regular expressions
868 in here, but we want to avoid any dependency on the thing we're testing.
870 Need to add in test IDs, to avoid the precarious line numbering.
878 # vim: expandtab shiftwidth=4 ft=pir: