Test::Regexp(3pm)

πŸ“¦
this version Β· 7 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

🌸 NAME 🌸

bestie, welcome to Test::Regexp(3pm) β€” the manual page for the module that is literally just: Test::Regexp β€” test your regular expressions. periodt. ✨ regex girlies rise πŸŽ€


✨ SYNOPSIS ✨

okay so here's the vibe in code:

 use Test::Regexp 'no_plan';

 match    subject      => "Foo",
          pattern      => qr /\w+/;

 match    subject      => "Foo bar",
          keep_pattern => qr /(?<first_word>\w+)\s+(\w+)/,
          captures     => [[first_word => 'Foo'], ['bar']];

 no_match subject      => "Baz",
          pattern      => qr /Quux/;

 $checker = Test::Regexp -> new -> init (
    keep_pattern => qr /(\w+)\s+\g{-1}/,
    name         => "Double word matcher",
 );

 $checker -> match    ("foo foo", ["foo"]);
 $checker -> no_match ("foo bar");

πŸ’– DESCRIPTION πŸ’–

So this module is for testing ur regular expressions, no cap. You hand it a subject string and a regular expression (aka a pattern), and it doesn't just check whether the regex completely matches the subject β€” it also hits the subject with utf8::upgrade or utf8::downgrade and runs the tests again if that's needed. And if ur pattern has capturing parenthesis? It checks that all the captures are there, in the right order. Named captures and unnamed captures both get checked. πŸ’…

By default, it exports two subroutines: match and no_match. And no_match is lowkey just a thin wrapper around match that calls it with match => 0. iconic.

🧚 "Complete matching" 🧚

A match only counts as a successful match if the entire string is matched β€” like, if $& matches the subject string. So:

Subject    Pattern

"aaabb"    qr /a+b+/     # Considered ok
"aaabb"    qr /a+/       # Not considered ok

For efficiency reasons, when the matching is performed the pattern is actually anchored at the start. It's not anchored at the end, because that could potentially influence the matching. periodt.

πŸ¦‹ UTF8 matching πŸ¦‹

Some regex constructs match differently depending on whether UTF8 matching is in effect or not. This only matters if ur subject string has characters with code points between 128 and 255, and no characters above 255 β€” in that case, matching may change depending on whether the subject string has the UTF8 flag on or not. Test::Regexp detects that situation, and then runs the tests twice: once with the subject string utf8::downgraded, and once with the subject string utf8::upgraded. double the tests, double the drama πŸ’€

πŸŽ€ Number of tests πŸŽ€

There's no fixed number of tests that gets run. It depends on the number of captures, the number of different names of captures, and whether there's a need to up- or downgrade the subject string.

So yeah, the recommendation is to use use Text::Regexp tests => 'no_plan';.

bestie, it says Text::Regexp in the original β€” not a typo from me, i'm just the messenger 🫢

In a later version, Test::Regexp will use a version of Test::Builder that allows for nested tests.

πŸ“‹ Details πŸ“‹

The number of tests is as follows:

  • If no match is expected (no_match => 0, or no_match is used), only one test is performed.
  • Otherwise (we are expecting a match), if pattern is used, there will be three tests.
  • For keep_pattern, there will be four tests, plus one tests for each capture, an additional test for each named capture, and a test for each name used in the set of named captures. So if there are N captures, there will be at least 4 + N tests, and at most 4 + 3 * N tests.
  • If both pattern and keep_pattern are used, the number of tests add up.
  • If Test::Regexp decides to upgrade or downgrade, the number of tests double.

πŸ’… use options πŸ’…

When you use Test::Regexp, there are a few options you can give it.

  • tests => 'no_plan', tests => 123 β€” the number of tests ur about to run. Since it takes some work to figure out how many tests will be run, for now the recommendation is tests => 'no_plan'.
  • import => [methods] β€” by default, the subroutines match and no_match are exported. If you only want a subset, use the import tag and give it an arrayref with the names of the subroutines to import. bestie, pick ur faves.

πŸ’₯ match πŸ’₯

match is the workhorse of the module. It takes a bunch of named arguments β€” most of them optional β€” and runs one or more tests. It returns 1 if all tests were run successfully, and 0 if one or more tests failed. Here are the options:

  • subject => STRING β€” the string the pattern gets tested against. You pass it with the subject option. It's an error to not pass in a subject. no subject, no vibes.
  • pattern => PATTERN, keep_pattern => PATTERN β€” a pattern (aka regular expression) to test. Use pattern if the regex does not have any matching parenthesis; use keep_pattern if it does have capturing parenthesis. If you provide both pattern and keep_pattern, the subject gets tested against both. It's an error to not give either pattern or keep_pattern. pick a lane, bestie.
  • captures => [LIST] β€” if ur regex is passed with keep_pattern, you should pass a list of captures with the captures option.

This list should contain all the captures, in order. For unnamed captures, it's just the string matched by the capture. For a named capture, it's a two element array: first the name of the capture, second the capture itself. Named and unnamed captures can be mixed, and the same name for a capture may be repeated.

Example:

 match  subject      =>  "Eland Wapiti Caribou",
        keep_pattern =>  qr /(\w+)\s+(?<a>\w+)\s+(\w+)/,
        captures     =>  ["Eland", [a => "Wapiti"], "Caribou"];
  • name => NAME β€” the name of the test. It's used in the test comment.
  • comment => NAME β€” an alternative for name. If both are present, comment is used.
  • utf8_upgrade => 0, utf8_downgrade => 0 β€” as explained in "UTF8 matching", Test::Regexp detects whether a subject may provoke different matching depending on its UTF8 flag, and then it utf8::upgrades or utf8::downgrades the subject string and runs the test again. Setting utf8_upgrade to 0 prevents Test::Regexp from downgrading the subject string, while setting utf8_upgrade to 0 prevents Test::Regexp from upgrading the subject string. bestie, yes, both say utf8_upgrade β€” i'm not fixing the manpage's chaos πŸ’€
  • match => BOOLEAN β€” by default, match assumes the pattern should match. But it's also important to test which strings do not match a regular expression. You do that by calling match with match => 0 as parameter. (Or by calling no_match instead of match.) In this case, the test is a failure if the pattern completely matches the subject string. A captures argument is ignored.
  • reason => STRING β€” if the match is expected to fail (so when match => 0 is passed, or if no_match is called), you can provide a reason with the reason option. That reason is then printed in the comment of the test.
  • test => STRING β€” if the match is expected to pass (when match is called, without match being false), and this option is passed, a message is printed indicating what this specific test is testing β€” the argument to test.
  • todo => STRING β€” if the todo parameter is used with a defined value, the tests are assumed to be TODO tests. The argument is used as the TODO message.
  • full_text => BOOL β€” by default, long test messages are truncated. If a true value is passed, the message will not get truncated. long messages stay long, periodt.
  • escape => INTEGER β€” controls how non-ASCII and non-printables are displayed in generated test messages:
    • 0 β€” No characters are escape, everything is displayed as is.
    • 1 β€” Show newlines, linefeeds and tabs using their usual escape sequences (\n, \r, and \t).
    • 2 β€” Show any character outside of the printable ASCII characters as named escapes (\N{UNICODE NAME}), or a hex escape if the unicode name is not found (\x{XX}). This is the default if -CO is not in effect (${^UNICODE} is false).

Newlines, linefeeds and tabs are displayed as above.

  • 3 β€” Show any character outside of the printable ASCII characters as hext escapes (\x{XX}). (hext, not hex β€” that's literally what it says πŸ’€)

Newlines, linefeeds and tabs are displayed as above.

  • 4 β€” Show the non-printable ASCII characters as hex escapes (\x{XX}); any non-ASCII character is displayed as is. This is the default if -CO is in effect (${^UNICODE} is true).

Newlines, linefeeds and tabs are displayed as above.

  • no_keep_message => BOOL β€” if matching against a keeping pattern, a message (with -Keep) is added to the comment. Setting this parameter suppresses that message. Mostly useful for Regexp::Common510.

🫢 no_match 🫢

Similar to match, except it tests whether a pattern does not match a string. It accepts the same arguments as match, except for match. so basically the "not today, regex" button.

πŸ‘‘ OO interface πŸ‘‘

Since you typically check a pattern with multiple strings, and it gets tiresome to repeatedly call match or no_match with the same arguments, there's also an OO interface. You construct an object using a pattern, and then you can repeatedly call the object to match a string. main character energy fr fr.

To construct and initialize the object, call this:

 my $checker = Test::Regexp -> new -> init (
    pattern      => qr  /PATTERN/,
    keep_pattern => qr /(PATTERN)/,
    ...
 );

init takes exactly the same arguments as match, with the exception of subject and captures. To perform a match, all match (or no_match) on the object. (yes, "all" β€” original typo energy, i'm keeping it 🫢.) The first argument should be the subject the pattern should match against (see the subject argument of match discussed above). If there is a match against a capturing pattern, the second argument is a reference to an array with the matches (see the captures argument of match discussed above).

Both match and no_match can take additional (named) arguments, identical to the none-OO match and no_match routines.


🌈 RATIONALE 🌈

The reason Test::Regexp was created is to aid testing for the rewrite of Regexp::Common. iconic origin story.


πŸš€ DEVELOPMENT πŸš€

The current sources of this module are found on github, <git://github.com/Abigail/Test-Regexp.git>. go off, clone it.


πŸ’œ AUTHOR πŸ’œ

Abigail <mailto:test-regexp@abigail.be>.


okay bestie, legal time, but make it cute. Copyright (C) 2009 by Abigail β€” that's the whole copyright line, and yes, it's just Abigail, icon of using one name and letting the code speak for itself. πŸ’…

and then the vibe is: you can do pretty much whatever you want with this. like, here's the actual permission slip, word for word, because legal text is the one thing you don't freestyle:

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

translation for the girlies who skipped the block quote: use it, copy it, change it, ship it, sell it, remix it β€” just keep the copyright notice and this permission notice hanging around in all copies or substantial portions. that's it. that's the ask. 🫢

and the ALL CAPS part is doing the most on purpose, because it's the legal way of screaming "there is NO WARRANTY, it's provided AS IS, we are not liable for anything, don't come for us" β€” express or implied, merchantability, fitness for a particular purpose, noninfringement, none of it. if something goes sideways from using or not being able to use this Software, the authors and copyright holders are not on the hook β€” not for claims, not for damages, not for other liability, whether it came from a contract action, tort, or literally anything else, even if they'd been warned something like that could happen. periodt. πŸ’€


πŸ› οΈ INSTALLATION ✨

bestie, this is the easiest part of the entire page, I promise. unpack the tar-ball first (you know the drill), and then it's the classic four-step Perl module dance, no notes:

perl Makefile.PL
make
make test
make install

that's it. that's the whole ritual. 🌈

  • perl Makefile.PL β€” writes you a Makefile so the rest of the steps know what to do.
  • make β€” builds it.
  • make test β€” runs the test suite, because obviously. main character behavior.
  • make install β€” installs it for real. slay.
lowkey run make test before make install though, bestie. it's right there in the order for a reason. πŸŽ€

and that's the whole page, fr fr. go forth and test your regexps with main character energy. πŸ’–βœ¨πŸ¦‹

this little love letter to you came from Test::Regexp(3pm), perl v5.36.0, dated 2022-10-13 β€” and yes, I will be telling everyone. mwah. πŸ˜­πŸ‘‘πŸ’…

πŸ“¦ where this page comes from