| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Test::Regexp; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 18 |  |  | 18 |  | 209938 | use 5.010; | 
|  | 18 |  |  |  |  | 55 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | BEGIN { | 
| 6 | 18 |  |  | 18 |  | 270 | binmode STDOUT, ":utf8"; | 
| 7 |  |  |  |  |  |  | } | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 18 |  |  | 18 |  | 60 | use strict; | 
|  | 18 |  |  |  |  | 17 |  | 
|  | 18 |  |  |  |  | 267 |  | 
| 10 | 18 |  |  | 18 |  | 56 | use warnings; | 
|  | 18 |  |  |  |  | 18 |  | 
|  | 18 |  |  |  |  | 386 |  | 
| 11 | 18 |  |  | 18 |  | 7750 | use charnames ":full"; | 
|  | 18 |  |  |  |  | 395772 |  | 
|  | 18 |  |  |  |  | 105 |  | 
| 12 | 18 |  |  | 18 |  | 2651 | no  warnings 'syntax'; | 
|  | 18 |  |  |  |  | 24 |  | 
|  | 18 |  |  |  |  | 549 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 18 |  |  | 18 |  | 59 | use Exporter (); | 
|  | 18 |  |  |  |  | 18 |  | 
|  | 18 |  |  |  |  | 212 |  | 
| 15 | 18 |  |  | 18 |  | 567 | use Test::Builder; | 
|  | 18 |  |  |  |  | 6186 |  | 
|  | 18 |  |  |  |  | 12401 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | our @EXPORT  = qw [match no_match]; | 
| 18 |  |  |  |  |  |  | our @ISA     = qw [Exporter Test::More]; | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | our $VERSION = '2016060501'; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | my $Test = Test::Builder -> new; | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | my $ESCAPE_NONE           = 0; | 
| 26 |  |  |  |  |  |  | my $ESCAPE_WHITE_SPACE    = 1; | 
| 27 |  |  |  |  |  |  | my $ESCAPE_NAMES          = 2; | 
| 28 |  |  |  |  |  |  | my $ESCAPE_CODES          = 3; | 
| 29 |  |  |  |  |  |  | my $ESCAPE_NON_PRINTABLE  = 4; | 
| 30 |  |  |  |  |  |  | my $ESCAPE_DEFAULT        = ${^UNICODE} ? $ESCAPE_NON_PRINTABLE | 
| 31 |  |  |  |  |  |  | : $ESCAPE_CODES; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | sub import { | 
| 34 | 18 |  |  | 18 |  | 103 | my $self = shift; | 
| 35 | 18 |  |  |  |  | 21 | my $pkg  = caller; | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 18 |  |  |  |  | 33 | my %arg  = @_; | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 18 |  |  |  |  | 134 | $Test -> exported_to ($pkg); | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 18 |  | 100 |  |  | 447 | $arg {import} //= [qw [match no_match]]; | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 18 |  |  |  |  | 69 | while (my ($key, $value) = each %arg) { | 
| 44 | 19 | 100 |  |  |  | 61 | if ($key eq "tests") { | 
|  |  | 50 |  |  |  |  |  | 
| 45 | 1 |  |  |  |  | 3 | $Test -> plan ($value); | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  | elsif ($key eq "import") { | 
| 48 | 18 | 50 |  |  |  | 19 | $self -> export_to_level (1, $self, $_) for @{$value || []}; | 
|  | 18 |  |  |  |  | 3012 |  | 
| 49 |  |  |  |  |  |  | } | 
| 50 |  |  |  |  |  |  | else { | 
| 51 | 0 |  |  |  |  | 0 | die "Unknown option '$key'\n"; | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | my $__ = "    "; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub escape { | 
| 60 | 619 |  |  | 619 | 1 | 570 | my ($str, $escape) = @_; | 
| 61 | 619 |  | 66 |  |  | 1259 | $escape //= $ESCAPE_DEFAULT; | 
| 62 | 619 | 50 |  |  |  | 922 | return $str if $escape == $ESCAPE_NONE; | 
| 63 | 619 |  |  |  |  | 701 | $str =~ s/\n/\\n/g; | 
| 64 | 619 |  |  |  |  | 450 | $str =~ s/\t/\\t/g; | 
| 65 | 619 |  |  |  |  | 413 | $str =~ s/\r/\\r/g; | 
| 66 | 619 | 100 |  |  |  | 1055 | if ($escape == $ESCAPE_NAMES) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 67 | 58 |  |  |  |  | 180 | $str =~ s{([^\x20-\x7E])} | 
| 68 | 38 |  |  |  |  | 113 | {my $name = charnames::viacode (ord $1); | 
| 69 | 38 | 50 |  |  |  | 57347 | $name ? sprintf "\\N{%s}"   => $name | 
| 70 |  |  |  |  |  |  | : sprintf "\\x{%02X}" => ord $1}eg; | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  | elsif ($escape == $ESCAPE_CODES) { | 
| 73 | 445 |  |  |  |  | 690 | $str =~ s{([^\x20-\x7E])} | 
| 74 | 38 |  |  |  |  | 168 | {sprintf "\\x{%02X}" => ord $1}eg; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  | elsif ($escape == $ESCAPE_NON_PRINTABLE) { | 
| 77 | 58 |  |  |  |  | 94 | $str =~ s{([\x00-\x1F\xFF])} | 
| 78 | 0 |  |  |  |  | 0 | {sprintf "\\x{%02X}" => ord $1}eg; | 
| 79 |  |  |  |  |  |  | } | 
| 80 | 619 |  |  |  |  | 792 | $str; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | sub pretty { | 
| 84 | 421 |  |  | 421 | 0 | 355 | my $str = shift; | 
| 85 | 421 |  |  |  |  | 512 | my %arg = @_; | 
| 86 | 421 | 100 | 100 |  |  | 871 | substr ($str, 50, -5, "...") if length $str > 55 && !$arg {full_text}; | 
| 87 | 421 |  |  |  |  | 571 | $str = escape $str, $arg {escape}; | 
| 88 | 421 |  |  |  |  | 559 | $str; | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | sub mess { | 
| 93 | 223 |  |  | 223 | 0 | 207 | my $val = shift; | 
| 94 | 223 | 50 |  |  |  | 313 | unless (defined $val) {return 'undefined'} | 
|  | 0 |  |  |  |  | 0 |  | 
| 95 | 223 |  |  |  |  | 344 | my %arg = @_; | 
| 96 |  |  |  |  |  |  | my $pretty = pretty $val, full_text => $arg {full_text}, | 
| 97 | 223 |  |  |  |  | 335 | escape    => $arg {escape}; | 
| 98 | 223 | 100 | 66 |  |  | 759 | if ($pretty eq $val && $val !~ /'/) { | 
|  |  | 50 |  |  |  |  |  | 
| 99 | 183 |  |  |  |  | 944 | return "eq '$val'"; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  | elsif ($pretty !~ /"/) { | 
| 102 | 40 |  |  |  |  | 215 | return 'eq "' . $pretty . '"'; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  | else { | 
| 105 | 0 |  |  |  |  | 0 | return "eq qq {$pretty}"; | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | sub todo { | 
| 111 | 198 |  |  | 198 | 1 | 644 | my %arg       =  @_; | 
| 112 | 198 |  |  |  |  | 208 | my $subject   =  $arg {subject}; | 
| 113 | 198 |  |  |  |  | 175 | my $comment   =  $arg {comment}; | 
| 114 | 198 |  |  |  |  | 159 | my $upgrade   =  $arg {upgrade}; | 
| 115 | 198 |  |  |  |  | 157 | my $downgrade =  $arg {downgrade}; | 
| 116 | 198 | 100 |  |  |  | 288 | my $neg       =  $arg {match} ? "" : "not "; | 
| 117 | 198 |  |  |  |  | 185 | my $full_text =  $arg {full_text}; | 
| 118 | 198 |  |  |  |  | 158 | my $escape    =  $arg {escape}; | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 198 |  |  |  |  | 138 | my $line      = ""; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 198 | 100 |  |  |  | 294 | if ($arg {show_line}) { | 
| 123 | 18 |  |  | 18 |  | 77 | no warnings 'once'; | 
|  | 18 |  |  |  |  | 18 |  | 
|  | 18 |  |  |  |  | 11752 |  | 
| 124 | 24 |  | 50 |  |  | 132 | my ($file, $l_nr)  = (caller ($Test::Builder::deepness // 1)) [1, 2]; | 
| 125 | 24 |  |  |  |  | 55 | $line = " [$file:$l_nr]"; | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 198 |  |  |  |  | 279 | my $subject_pretty = pretty $subject, full_text => $full_text, | 
| 129 |  |  |  |  |  |  | escape    => $escape; | 
| 130 | 198 |  |  |  |  | 295 | my $Comment        = qq {qq {$subject_pretty}}; | 
| 131 | 198 |  |  |  |  | 336 | $Comment       .= qq { ${neg}matched by "$comment"}; | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 198 |  |  |  |  | 359 | my @todo = [$subject, $Comment, $line]; | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | # | 
| 136 |  |  |  |  |  |  | # If the subject isn't already UTF-8, and there are characters in | 
| 137 |  |  |  |  |  |  | # the range "\x{80}" .. "\x{FF}", we do the test a second time, | 
| 138 |  |  |  |  |  |  | # with the subject upgraded to UTF-8. | 
| 139 |  |  |  |  |  |  | # | 
| 140 |  |  |  |  |  |  | # Otherwise, if the subject is in UTF-8 format, and there are *no* | 
| 141 |  |  |  |  |  |  | # characters with code point > 0xFF, but with characters in the | 
| 142 |  |  |  |  |  |  | # range 0x80 .. 0xFF, we downgrade and test again. | 
| 143 |  |  |  |  |  |  | # | 
| 144 | 198 | 100 | 33 |  |  | 1886 | if ($upgrade && ($upgrade == 2 ||    !utf8::is_utf8 ($subject) | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 145 |  |  |  |  |  |  | && $subject =~ /[\x80-\xFF]/)) { | 
| 146 | 24 |  |  |  |  | 26 | my $subject_utf8 = $subject; | 
| 147 | 24 | 50 |  |  |  | 55 | if (utf8::upgrade ($subject_utf8)) { | 
| 148 | 24 |  |  |  |  | 33 | my $Comment_utf8   = qq {qq {$subject_pretty}}; | 
| 149 | 24 |  |  |  |  | 28 | $Comment_utf8  .= qq { [UTF-8]}; | 
| 150 | 24 |  |  |  |  | 32 | $Comment_utf8  .= qq { ${neg}matched by "$comment"}; | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 24 |  |  |  |  | 46 | push @todo => [$subject_utf8, $Comment_utf8, $line]; | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | elsif ($downgrade && ($downgrade == 2 ||     utf8::is_utf8 ($subject) | 
| 156 |  |  |  |  |  |  | && $subject =~ /[\x80-\xFF]/ | 
| 157 |  |  |  |  |  |  | && $subject !~ /[^\x00-\xFF]/)) { | 
| 158 | 24 |  |  |  |  | 23 | my $subject_non_utf8 = $subject; | 
| 159 | 24 | 50 |  |  |  | 53 | if (utf8::downgrade ($subject_non_utf8)) { | 
| 160 | 24 |  |  |  |  | 34 | my $Comment_non_utf8  = qq {qq {$subject_pretty}}; | 
| 161 | 24 |  |  |  |  | 33 | $Comment_non_utf8 .= qq { [non-UTF-8]}; | 
| 162 | 24 |  |  |  |  | 36 | $Comment_non_utf8 .= qq { ${neg}matched by "$comment"}; | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 24 |  |  |  |  | 44 | push @todo => [$subject_non_utf8, $Comment_non_utf8, $line]; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 198 |  |  |  |  | 500 | @todo; | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | # | 
| 174 |  |  |  |  |  |  | # Arguments: | 
| 175 |  |  |  |  |  |  | #   name:         'Name' of the pattern. | 
| 176 |  |  |  |  |  |  | #   pattern:       Pattern to be tested, without captures. | 
| 177 |  |  |  |  |  |  | #   keep_pattern:  Pattern to be tested, with captures. | 
| 178 |  |  |  |  |  |  | #   subject:       String to match. | 
| 179 |  |  |  |  |  |  | #   captures:      Array of captures; elements are either strings | 
| 180 |  |  |  |  |  |  | #                  (match for the corresponding numbered capture), | 
| 181 |  |  |  |  |  |  | #                  or an array, where the first element is the name | 
| 182 |  |  |  |  |  |  | #                  of the capture and the second its value. | 
| 183 |  |  |  |  |  |  | #   comment:       Comment to use, defaults to name or "". | 
| 184 |  |  |  |  |  |  | #   utf8_upgrade:  If set, upgrade the string if applicable. Defaults to 1. | 
| 185 |  |  |  |  |  |  | #   utf8_downgrade If set, downgrade the string if applicable. Defaults to 1. | 
| 186 |  |  |  |  |  |  | #   match          If true, pattern(s) should match, otherwise, should fail | 
| 187 |  |  |  |  |  |  | #                  to match. Defaults to 1. | 
| 188 |  |  |  |  |  |  | #   reason         The reason a match should fail. | 
| 189 |  |  |  |  |  |  | #   test           What is tested. | 
| 190 |  |  |  |  |  |  | #   todo           This test is a todo test; argument is the reason. | 
| 191 |  |  |  |  |  |  | #   show_line      Show file name/line number of call to 'match'. | 
| 192 |  |  |  |  |  |  | #   full_text      Don't shorten long messages. | 
| 193 |  |  |  |  |  |  | # | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | sub match { | 
| 196 | 198 |  |  | 198 | 1 | 557266 | my %arg            = @_; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 198 |  |  |  |  | 255 | my $name           = $arg {name}; | 
| 199 | 198 |  |  |  |  | 172 | my $pattern        = $arg {pattern}; | 
| 200 | 198 |  |  |  |  | 163 | my $keep_pattern   = $arg {keep_pattern}; | 
| 201 | 198 |  |  |  |  | 178 | my $subject        = $arg {subject}; | 
| 202 | 198 |  | 100 |  |  | 560 | my $captures       = $arg {captures}       // []; | 
| 203 | 198 |  | 100 |  |  | 976 | my $comment        = escape $arg {comment} // $name // ""; | 
|  |  |  | 100 |  |  |  |  | 
| 204 | 198 |  | 100 |  |  | 510 | my $upgrade        = $arg {utf8_upgrade}   // 1; | 
| 205 | 198 |  | 100 |  |  | 446 | my $downgrade      = $arg {utf8_downgrade} // 1; | 
| 206 | 198 |  | 100 |  |  | 347 | my $match          = $arg {match}          // 1; | 
| 207 |  |  |  |  |  |  | my $reason         = defined $arg {reason} | 
| 208 | 198 | 100 |  |  |  | 307 | ? " [Reason: " . $arg {reason} . "]" | 
| 209 |  |  |  |  |  |  | : ""; | 
| 210 |  |  |  |  |  |  | my $test           = defined $arg {test} | 
| 211 | 198 | 100 |  |  |  | 268 | ? " [Test: "   . $arg {test}   . "]" | 
| 212 |  |  |  |  |  |  | : ""; | 
| 213 | 198 |  |  |  |  | 171 | my $show_line      = $arg {show_line}; | 
| 214 | 198 |  |  |  |  | 144 | my $full_text      = $arg {full_text}; | 
| 215 | 198 |  |  |  |  | 147 | my $escape         = $arg {escape}; | 
| 216 | 198 |  |  |  |  | 161 | my $todo           = $arg {todo}; | 
| 217 | 198 | 100 |  |  |  | 242 | my $keep_message   = $arg {no_keep_message} ? "" : " (with -Keep)"; | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 198 |  |  |  |  | 136 | my $numbered_captures; | 
| 220 |  |  |  |  |  |  | my $named_captures; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 198 |  |  |  |  | 140 | my $pass           = 1; | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | # | 
| 225 |  |  |  |  |  |  | # First split the captures into a hash (for named captures) and | 
| 226 |  |  |  |  |  |  | # an array (for numbered captures) so we can check $1 and friends, and %-. | 
| 227 |  |  |  |  |  |  | # | 
| 228 | 198 |  |  |  |  | 304 | foreach my $capture (@$captures) { | 
| 229 | 117 | 100 |  |  |  | 161 | if (ref $capture eq 'ARRAY') { | 
| 230 | 70 |  |  |  |  | 81 | my ($name, $match) = @$capture; | 
| 231 | 70 |  |  |  |  | 78 | push   @$numbered_captures => $match; | 
| 232 | 70 |  |  |  |  | 44 | push @{$$named_captures {$name}} => $match; | 
|  | 70 |  |  |  |  | 145 |  | 
| 233 |  |  |  |  |  |  | } | 
| 234 |  |  |  |  |  |  | else { | 
| 235 | 47 |  |  |  |  | 350 | push @$numbered_captures => $capture; | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 | 198 |  | 100 |  |  | 515 | $numbered_captures ||= []; | 
| 240 | 198 |  | 100 |  |  | 438 | $named_captures    ||= {}; | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 198 |  |  |  |  | 336 | my @todo = todo subject   => $subject, | 
| 243 |  |  |  |  |  |  | comment   => $comment, | 
| 244 |  |  |  |  |  |  | upgrade   => $upgrade, | 
| 245 |  |  |  |  |  |  | downgrade => $downgrade, | 
| 246 |  |  |  |  |  |  | match     => $match, | 
| 247 |  |  |  |  |  |  | show_line => $show_line, | 
| 248 |  |  |  |  |  |  | full_text => $full_text, | 
| 249 |  |  |  |  |  |  | escape    => $escape; | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 198 | 100 |  |  |  | 324 | $Test -> todo_start ($todo) if defined $todo; | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | # | 
| 254 |  |  |  |  |  |  | # Now we will do the tests. | 
| 255 |  |  |  |  |  |  | # | 
| 256 | 198 |  |  |  |  | 404 | foreach my $todo (@todo) { | 
| 257 | 246 |  |  |  |  | 278 | my $subject = $$todo [0]; | 
| 258 | 246 |  |  |  |  | 183 | my $comment = $$todo [1]; | 
| 259 | 246 |  |  |  |  | 180 | my $line    = $$todo [2]; | 
| 260 |  |  |  |  |  |  |  | 
| 261 | 246 | 100 | 100 |  |  | 669 | if ($match && defined $pattern) { | 
| 262 | 134 |  |  |  |  | 98 | my $comment = $comment; | 
| 263 | 134 | 100 |  |  |  | 346 | my $pat     =  ref $pattern ?     $pattern | 
| 264 |  |  |  |  |  |  | : qr /$pattern/; | 
| 265 | 134 |  |  |  |  | 549 | $comment =~ s{""$}{/$pat/}; | 
| 266 | 134 |  |  |  |  | 166 | $comment .= "$line$test"; | 
| 267 |  |  |  |  |  |  | # | 
| 268 |  |  |  |  |  |  | # Test match; match should also be complete, and not | 
| 269 |  |  |  |  |  |  | # have any captures. | 
| 270 |  |  |  |  |  |  | # | 
| 271 |  |  |  |  |  |  | SKIP: { | 
| 272 | 134 |  |  |  |  | 105 | my $result = $subject =~ /^$pattern/; | 
|  | 134 |  |  |  |  | 704 |  | 
| 273 | 134 | 100 |  |  |  | 596 | unless ($Test -> ok ($result, $comment)) { | 
| 274 | 3 |  |  |  |  | 231 | $Test -> skip ("Match failed") for 1 .. 3; | 
| 275 | 3 |  |  |  |  | 310 | $pass = 0; | 
| 276 | 3 |  |  |  |  | 8 | last SKIP; | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | # | 
| 280 |  |  |  |  |  |  | # %- contains an entry for *each* named group, regardless | 
| 281 |  |  |  |  |  |  | # whether it's a capture or not. | 
| 282 |  |  |  |  |  |  | # | 
| 283 | 131 |  |  |  |  | 9693 | my $named_matches  = 0; | 
| 284 | 18 |  |  | 18 |  | 6762 | $named_matches += @$_ for values %-; | 
|  | 18 |  |  |  |  | 5443 |  | 
|  | 18 |  |  |  |  | 5629 |  | 
|  | 131 |  |  |  |  | 585 |  | 
| 285 |  |  |  |  |  |  |  | 
| 286 | 131 | 100 |  |  |  | 597 | unless ($Test -> is_eq ($&, $subject, | 
| 287 |  |  |  |  |  |  | "${__}match is complete")) { | 
| 288 | 22 |  |  |  |  | 4942 | $Test -> skip ("Match failed") for 2 .. 3; | 
| 289 | 22 |  |  |  |  | 1683 | $pass = 0; | 
| 290 | 22 |  |  |  |  | 53 | last SKIP; | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 109 | 100 |  |  |  | 16019 | $pass = 0 unless | 
| 294 |  |  |  |  |  |  | $Test -> is_eq (scalar @+, 1, | 
| 295 |  |  |  |  |  |  | "${__}no numbered captures"); | 
| 296 | 109 | 100 |  |  |  | 15249 | $pass = 0 unless | 
| 297 |  |  |  |  |  |  | $Test -> is_eq ($named_matches, 0, | 
| 298 |  |  |  |  |  |  | "${__}no named captures"); | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 246 | 100 | 100 |  |  | 15529 | if ($match && defined $keep_pattern) { | 
| 304 | 82 |  |  |  |  | 61 | my $comment = $comment; | 
| 305 | 82 | 100 |  |  |  | 250 | my $pat     =  ref $keep_pattern ?     $keep_pattern | 
| 306 |  |  |  |  |  |  | : qr /$keep_pattern/; | 
| 307 | 82 |  |  |  |  | 403 | $comment =~ s{""$}{/$pat/}; | 
| 308 | 82 |  |  |  |  | 105 | $comment .= $keep_message; | 
| 309 | 82 |  |  |  |  | 80 | $comment .= "$line$test"; | 
| 310 |  |  |  |  |  |  | # | 
| 311 |  |  |  |  |  |  | # Test keep. Should match, and the parts as well. | 
| 312 |  |  |  |  |  |  | # | 
| 313 |  |  |  |  |  |  | # Total number of tests: | 
| 314 |  |  |  |  |  |  | #   - 1 for match. | 
| 315 |  |  |  |  |  |  | #   - 1 for match complete. | 
| 316 |  |  |  |  |  |  | #   - 1 for each named capture. | 
| 317 |  |  |  |  |  |  | #   - 1 for each capture name. | 
| 318 |  |  |  |  |  |  | #   - 1 for number of different capture names. | 
| 319 |  |  |  |  |  |  | #   - 1 for each capture. | 
| 320 |  |  |  |  |  |  | #   - 1 for number of captures. | 
| 321 |  |  |  |  |  |  | # So, if you only have named captures, and all the names | 
| 322 |  |  |  |  |  |  | # are different, you have 4 + 3 * N tests. | 
| 323 |  |  |  |  |  |  | # If you only have numbered captures, you have 4 + N tests. | 
| 324 |  |  |  |  |  |  | # | 
| 325 |  |  |  |  |  |  | SKIP: { | 
| 326 | 82 |  |  |  |  | 62 | my $nr_of_tests  = 0; | 
|  | 82 |  |  |  |  | 66 |  | 
| 327 | 82 |  |  |  |  | 63 | $nr_of_tests += 1;  # For match. | 
| 328 | 82 |  |  |  |  | 55 | $nr_of_tests += 1;  # For match complete. | 
| 329 | 82 |  |  |  |  | 185 | $nr_of_tests += @{$_} for values %$named_captures; | 
|  | 98 |  |  |  |  | 112 |  | 
| 330 |  |  |  |  |  |  | # Number of named captures. | 
| 331 | 82 |  |  |  |  | 73 | $nr_of_tests += scalar keys %$named_captures; | 
| 332 |  |  |  |  |  |  | # Number of different named captures. | 
| 333 | 82 |  |  |  |  | 55 | $nr_of_tests += 1;  # Right number of named captures. | 
| 334 | 82 |  |  |  |  | 58 | $nr_of_tests += @$numbered_captures; | 
| 335 |  |  |  |  |  |  | # Number of numbered captures. | 
| 336 | 82 |  |  |  |  | 65 | $nr_of_tests += 1;  # Right number of numbered captures. | 
| 337 |  |  |  |  |  |  |  | 
| 338 | 82 |  |  |  |  | 76 | my ($amp, @numbered_matches, %minus); | 
| 339 |  |  |  |  |  |  |  | 
| 340 | 82 |  |  |  |  | 990 | my $result = $subject =~ /^$keep_pattern/; | 
| 341 | 82 | 100 |  |  |  | 390 | unless ($Test -> ok ($result, $comment)) { | 
| 342 | 2 |  |  |  |  | 170 | $Test -> skip ("Match failed") for 2 .. $nr_of_tests; | 
| 343 | 2 |  |  |  |  | 343 | $pass = 0; | 
| 344 | 2 |  |  |  |  | 7 | last SKIP; | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | # | 
| 349 |  |  |  |  |  |  | # Copy $&, $N and %- before doing anything that | 
| 350 |  |  |  |  |  |  | # migh override them. | 
| 351 |  |  |  |  |  |  | # | 
| 352 |  |  |  |  |  |  |  | 
| 353 | 80 |  |  |  |  | 6313 | $amp = $&; | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | # | 
| 356 |  |  |  |  |  |  | # Grab numbered captures. | 
| 357 |  |  |  |  |  |  | # | 
| 358 | 80 |  |  |  |  | 198 | for (my $i = 1; $i < @+; $i ++) { | 
| 359 | 18 |  |  | 18 |  | 81 | no strict 'refs'; | 
|  | 18 |  |  |  |  | 18 |  | 
|  | 18 |  |  |  |  | 12321 |  | 
| 360 | 139 |  |  |  |  | 448 | push @numbered_matches => $$i; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | # | 
| 364 |  |  |  |  |  |  | # Copy %-; | 
| 365 |  |  |  |  |  |  | # | 
| 366 | 80 |  |  |  |  | 507 | while (my ($key, $value) = each %-) { | 
| 367 | 98 |  |  |  |  | 487 | $minus {$key} = [@$value]; | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | # | 
| 371 |  |  |  |  |  |  | # Test to see if match is complete. | 
| 372 |  |  |  |  |  |  | # | 
| 373 | 80 | 100 |  |  |  | 344 | unless ($Test -> is_eq ($amp, $subject, | 
| 374 |  |  |  |  |  |  | "${__}match is complete")) { | 
| 375 | 6 |  |  |  |  | 1216 | $Test -> skip ("Match incomplete") for 3 .. $nr_of_tests; | 
| 376 | 6 |  |  |  |  | 1465 | $pass = 0; | 
| 377 | 6 |  |  |  |  | 22 | last SKIP; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | # | 
| 381 |  |  |  |  |  |  | # Test named captures. | 
| 382 |  |  |  |  |  |  | # | 
| 383 | 74 |  |  |  |  | 10490 | while (my ($key, $value) = each %$named_captures) { | 
| 384 | 93 |  |  |  |  | 6466 | for (my $i = 0; $i < @$value; $i ++) { | 
| 385 |  |  |  |  |  |  | $pass = 0 unless | 
| 386 |  |  |  |  |  |  | $Test -> is_eq ( | 
| 387 | 97 | 100 |  |  |  | 998 | $minus {$key} ? $minus {$key} [$i] : undef, | 
|  |  | 100 |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | $$value [$i], | 
| 389 |  |  |  |  |  |  | "${__}\$- {$key} [$i] " . | 
| 390 |  |  |  |  |  |  | mess ($$value [$i], full_text => $full_text, | 
| 391 |  |  |  |  |  |  | escape    => $escape)); | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | $pass = 0 unless | 
| 394 | 93 | 100 |  |  |  | 13100 | $Test -> is_num (scalar @{$minus {$key} || []}, | 
|  | 93 | 100 |  |  |  | 614 |  | 
|  |  | 100 |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | scalar @$value, "$__${__}capture '$key' has " . | 
| 396 |  |  |  |  |  |  | (@$value == 1 ? "1 match" : | 
| 397 |  |  |  |  |  |  | @$value . " matches")); | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  | # | 
| 400 |  |  |  |  |  |  | # Test for the right number of captures. | 
| 401 |  |  |  |  |  |  | # | 
| 402 | 74 | 100 |  |  |  | 7386 | $pass = 0 unless | 
| 403 |  |  |  |  |  |  | $Test -> is_num (scalar keys %minus, | 
| 404 |  |  |  |  |  |  | scalar keys %$named_captures, | 
| 405 |  |  |  |  |  |  | $__ . scalar (keys %$named_captures) | 
| 406 |  |  |  |  |  |  | . " named capture groups" | 
| 407 |  |  |  |  |  |  | ); | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | # | 
| 411 |  |  |  |  |  |  | # Test numbered captures. | 
| 412 |  |  |  |  |  |  | # | 
| 413 | 74 |  |  |  |  | 10019 | for (my $i = 0; $i < @$numbered_captures; $i ++) { | 
| 414 | 126 | 100 |  |  |  | 8491 | $pass = 0 unless | 
| 415 |  |  |  |  |  |  | $Test -> is_eq ($numbered_matches [$i], | 
| 416 |  |  |  |  |  |  | $$numbered_captures [$i], | 
| 417 |  |  |  |  |  |  | "${__}\$" . ($i + 1) . " " . | 
| 418 |  |  |  |  |  |  | mess ($$numbered_captures [$i], | 
| 419 |  |  |  |  |  |  | full_text => $full_text, | 
| 420 |  |  |  |  |  |  | escape    => $escape)); | 
| 421 |  |  |  |  |  |  | } | 
| 422 | 74 | 100 |  |  |  | 8719 | $pass = 0 unless | 
|  |  | 100 |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | $Test -> is_num (scalar @numbered_matches, | 
| 424 |  |  |  |  |  |  | scalar @$numbered_captures, | 
| 425 |  |  |  |  |  |  | $__ . | 
| 426 |  |  |  |  |  |  | (@$numbered_captures == 1     ? | 
| 427 |  |  |  |  |  |  | "1 numbered capture group" : | 
| 428 |  |  |  |  |  |  | @$numbered_captures . | 
| 429 |  |  |  |  |  |  | " numbered capture groups")); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  |  | 
| 433 | 246 | 100 | 100 |  |  | 10829 | if (!$match && defined $pattern) { | 
| 434 | 33 |  |  |  |  | 25 | my $comment = $comment; | 
| 435 | 33 | 100 |  |  |  | 107 | my $pat     =  ref $pattern ?     $pattern | 
| 436 |  |  |  |  |  |  | : qr /$pattern/; | 
| 437 | 33 |  |  |  |  | 94 | $comment =~ s{""$}{/$pat/}; | 
| 438 | 33 |  |  |  |  | 60 | $comment .= "$line$reason"; | 
| 439 | 33 |  |  |  |  | 186 | my $r = $subject =~ /^$pattern/; | 
| 440 | 33 | 100 | 100 |  |  | 205 | $pass = 0 unless | 
| 441 |  |  |  |  |  |  | $Test -> ok (!$r || $subject ne $&, $comment); | 
| 442 |  |  |  |  |  |  | } | 
| 443 | 246 | 100 | 100 |  |  | 3334 | if (!$match && defined $keep_pattern) { | 
| 444 | 1 |  |  |  |  | 1 | my $comment = $comment; | 
| 445 | 1 | 50 |  |  |  | 3 | my $pat     =  ref $keep_pattern ?     $keep_pattern | 
| 446 |  |  |  |  |  |  | : qr /$keep_pattern/; | 
| 447 | 1 |  |  |  |  | 1 | $comment =~ s{""$}{/$pat/}; | 
| 448 | 1 |  |  |  |  | 2 | $comment .= $keep_message; | 
| 449 | 1 |  |  |  |  | 2 | $comment .= "$line$reason"; | 
| 450 | 1 |  |  |  |  | 23 | my $r = $subject =~ /^$keep_pattern/; | 
| 451 | 1 | 50 | 33 |  |  | 6 | $pass = 0 unless | 
| 452 |  |  |  |  |  |  | $Test -> ok (!$r || $subject ne $&, $comment); | 
| 453 |  |  |  |  |  |  | } | 
| 454 |  |  |  |  |  |  | } | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 198 | 100 |  |  |  | 603 | $Test -> todo_end if defined $todo; | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 198 |  |  |  |  | 949 | $pass; | 
| 459 |  |  |  |  |  |  | } | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | sub no_match { | 
| 462 | 6 |  |  | 6 | 1 | 15 | push @_ => match => 0; | 
| 463 | 6 |  |  |  |  | 13 | goto &match; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | sub new { | 
| 467 | 19 |  |  | 19 | 0 | 20588 | "Test::Regexp::Object" -> new | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | package Test::Regexp::Object; | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | sub new { | 
| 473 | 21 |  |  | 21 |  | 25 | bless \do {my $var} => shift; | 
|  | 21 |  |  |  |  | 96 |  | 
| 474 |  |  |  |  |  |  | } | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 18 |  |  | 18 |  | 9731 | use Hash::Util::FieldHash qw [fieldhash]; | 
|  | 18 |  |  |  |  | 13961 |  | 
|  | 18 |  |  |  |  | 8436 |  | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | fieldhash my %pattern; | 
| 479 |  |  |  |  |  |  | fieldhash my %keep_pattern; | 
| 480 |  |  |  |  |  |  | fieldhash my %name; | 
| 481 |  |  |  |  |  |  | fieldhash my %comment; | 
| 482 |  |  |  |  |  |  | fieldhash my %utf8_upgrade; | 
| 483 |  |  |  |  |  |  | fieldhash my %utf8_downgrade; | 
| 484 |  |  |  |  |  |  | fieldhash my %match; | 
| 485 |  |  |  |  |  |  | fieldhash my %reason; | 
| 486 |  |  |  |  |  |  | fieldhash my %test; | 
| 487 |  |  |  |  |  |  | fieldhash my %show_line; | 
| 488 |  |  |  |  |  |  | fieldhash my %full_text; | 
| 489 |  |  |  |  |  |  | fieldhash my %escape; | 
| 490 |  |  |  |  |  |  | fieldhash my %todo; | 
| 491 |  |  |  |  |  |  | fieldhash my %tags; | 
| 492 |  |  |  |  |  |  | fieldhash my %no_keep_message; | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | sub init { | 
| 495 | 19 |  |  | 19 |  | 21 | my $self = shift; | 
| 496 | 19 |  |  |  |  | 47 | my %arg  = @_; | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 19 |  |  |  |  | 104 | $pattern             {$self} = $arg {pattern}; | 
| 499 | 19 |  |  |  |  | 41 | $keep_pattern        {$self} = $arg {keep_pattern}; | 
| 500 | 19 |  |  |  |  | 31 | $name                {$self} = $arg {name}; | 
| 501 | 19 |  |  |  |  | 35 | $comment             {$self} = $arg {comment}; | 
| 502 | 19 |  |  |  |  | 32 | $utf8_upgrade        {$self} = $arg {utf8_upgrade}; | 
| 503 | 19 |  |  |  |  | 29 | $utf8_downgrade      {$self} = $arg {utf8_downgrade}; | 
| 504 | 19 |  |  |  |  | 30 | $match               {$self} = $arg {match}; | 
| 505 | 19 |  |  |  |  | 44 | $reason              {$self} = $arg {reason}; | 
| 506 | 19 |  |  |  |  | 32 | $test                {$self} = $arg {test}; | 
| 507 | 19 |  |  |  |  | 30 | $show_line           {$self} = $arg {show_line}; | 
| 508 | 19 |  |  |  |  | 30 | $full_text           {$self} = $arg {full_text}; | 
| 509 | 19 |  |  |  |  | 33 | $escape              {$self} = $arg {escape}; | 
| 510 | 19 |  |  |  |  | 26 | $todo                {$self} = $arg {todo}; | 
| 511 | 19 | 100 |  |  |  | 44 | $tags                {$self} = $arg {tags} if exists $arg {tags}; | 
| 512 | 19 |  |  |  |  | 27 | $no_keep_message     {$self} = $arg {no_keep_message}; | 
| 513 |  |  |  |  |  |  |  | 
| 514 | 19 |  |  |  |  | 39 | $self; | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | sub args { | 
| 518 | 28 |  |  | 28 |  | 27 | my  $self = shift; | 
| 519 |  |  |  |  |  |  | ( | 
| 520 |  |  |  |  |  |  | pattern             => $pattern             {$self}, | 
| 521 |  |  |  |  |  |  | keep_pattern        => $keep_pattern        {$self}, | 
| 522 |  |  |  |  |  |  | name                => $name                {$self}, | 
| 523 |  |  |  |  |  |  | comment             => $comment             {$self}, | 
| 524 |  |  |  |  |  |  | utf8_upgrade        => $utf8_upgrade        {$self}, | 
| 525 |  |  |  |  |  |  | utf8_downgrade      => $utf8_downgrade      {$self}, | 
| 526 |  |  |  |  |  |  | match               => $match               {$self}, | 
| 527 |  |  |  |  |  |  | reason              => $reason              {$self}, | 
| 528 |  |  |  |  |  |  | test                => $test                {$self}, | 
| 529 |  |  |  |  |  |  | show_line           => $show_line           {$self}, | 
| 530 |  |  |  |  |  |  | full_text           => $full_text           {$self}, | 
| 531 |  |  |  |  |  |  | escape              => $escape              {$self}, | 
| 532 |  |  |  |  |  |  | todo                => $todo                {$self}, | 
| 533 | 28 |  |  |  |  | 232 | no_keep_message     => $no_keep_message     {$self}, | 
| 534 |  |  |  |  |  |  | ) | 
| 535 |  |  |  |  |  |  | } | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | sub match { | 
| 538 | 22 |  |  | 22 |  | 44809 | my  $self     = shift; | 
| 539 | 22 |  |  |  |  | 29 | my  $subject  = shift; | 
| 540 | 22 | 100 |  |  |  | 51 | my  $captures = @_ % 2 ? shift : undef; | 
| 541 |  |  |  |  |  |  |  | 
| 542 | 22 |  |  |  |  | 49 | Test::Regexp::match subject  => $subject, | 
| 543 |  |  |  |  |  |  | captures => $captures, | 
| 544 |  |  |  |  |  |  | $self    -> args, | 
| 545 |  |  |  |  |  |  | @_; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | sub no_match { | 
| 549 | 6 |  |  | 6 |  | 4366 | my  $self    = shift; | 
| 550 | 6 |  |  |  |  | 8 | my  $subject = shift; | 
| 551 |  |  |  |  |  |  |  | 
| 552 | 6 |  |  |  |  | 11 | Test::Regexp::no_match subject  => $subject, | 
| 553 |  |  |  |  |  |  | $self    -> args, | 
| 554 |  |  |  |  |  |  | @_; | 
| 555 |  |  |  |  |  |  | } | 
| 556 |  |  |  |  |  |  |  | 
| 557 | 9 |  |  | 9 |  | 41 | sub name {$name {+shift}} | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | sub set_tag { | 
| 560 | 2 |  |  | 2 |  | 5 | my $self = shift; | 
| 561 | 2 |  |  |  |  | 7 | $tags {$self} {$_ [0]} = $_ [1]; | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  | sub tag { | 
| 564 | 11 |  |  | 11 |  | 14 | my $self = shift; | 
| 565 | 11 |  |  |  |  | 58 | $tags {$self} {$_ [0]}; | 
| 566 |  |  |  |  |  |  | } | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | 1; | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | __END__ |