Test2::Compare(3perl)

πŸ’– Test2::Compare πŸ’–

okay so bestie, you found it β€” Test2::Compare, the extension from the Test2 universe that lets you build your own deep comparison tools. it lives in the Perl Programmers Reference Guide and honestly? it's kind of the moment. πŸŽ€


✨ NAME ✨

Test2::Compare β€” the Test2 extension you reach for when you wanna write deep comparison tools. πŸ’…


🌸 DESCRIPTION 🌸

this library is the driving force behind deep comparison tools like Test2::Tools::Compare::is() and Test2::Tools::ClassicCompare::is_deeply(). like, they literally could not do their little thing without it. no cap. πŸ‘‘


πŸ¦‹ SYNOPSIS πŸ¦‹

here's the whole vibe, verbatim:

package Test2::Tools::MyCheck;

use Test2::Compare::MyCheck;
use Test2::Compare qw/compare/;

sub MyCheck {
    my ($got, $exp, $name, @diag) = @_;
    my $ctx = context();

    my $delta = compare($got, $exp, \&convert);

    if ($delta) {
        $ctx->fail($name, $delta->diag, @diag);
    }
    else {
        $ctx->ok(1, $name);
    }

    $ctx->release;
    return !$delta;
}

sub convert {
    my $thing = shift;
    return $thing if blessed($thing) && $thing->isa('Test2::Compare::MyCheck');

    return Test2::Compare::MyCheck->new(stuff => $thing);
}

and if you wanna know all the juicy details about writing a custom check, go peep Test2::Compare::Base. it's got the whole blueprint. πŸ“–βœ¨


πŸ’œ EXPORTS πŸ’œ

say hi to everything you can pull into your own namespace:

  • $delta = compare($got, $expect, \&convert) β€” this one compares the structures in $got against the ones in $expect. the convert sub's whole job is to turn vanilla structures inside $expect into checks. if the structures don't match up, all the differences come back to you as a Test2::Compare::Delta tree. 🌳
  • $build = get_build() β€” grab the current global build, if there even is one. lowkey simple.
  • push_build($build) β€” set the current global build. just, like, push it. πŸ’…
  • $build = pop_build($build) β€” unset the current global build. but bestie, careful: this will throw an exception if the build you passed in is different from the current global. mismatch = chaos. πŸ’€
  • build($class, sub { ... }) β€” run that codeblock with a fresh new instance of $class as the current build. returns the new build. main character energy fr fr. ✨
  • $check = convert($thing)
  • $check = convert($thing, $config) β€” this convert function is what strict_convert() and relaxed_convert() are using under the hood, and you can also use it as the foundation for your own convert functions. if you wanna use it with a custom configuration, wrap it in another sub like this:
sub my_convert {
    my $thing_to_convert = shift;
    return convert(
        $thing_to_convert,
        { ... }
    );
}

or the short variant, for the girlies who like it compact:

sub my_convert { convert($_[0], { ... }) }

there are several config options β€” here they all are, with the default setting listed first:

  • implicit_end => 1 β€” toggles array/hash boundaries. when it's true, no extra hash keys or array indexes are allowed. this setting affects the compare objects that get generated and any that get passed in. 🚧
  • use_regex => 1 β€” toggles regex matching. when true (that's the default), regexes get converted into checks so values must match the regex. when false, regexes are just compared to see if they're identical regexes. identical twins check. πŸ‘―
  • use_code => 0 β€” toggles code matching. when false (the default), coderefs inside structures must be the exact same coderef you specified. when true, coderefs get run to verify the value being checked. πŸƒβ™€οΈ
  • $check = strict_convert($thing) β€” converts $thing into a Test2::Compare::* object. this one behaves strictly, meaning it uses these settings:
    • implicit_end => 1 β€” array bounds get checked when this object is used in a comparison. no unexpected hash keys are allowed to be present. nope, not even one. πŸ™…β™€οΈ
    • use_code => 0 β€” sub references get compared as refs (i.e., are these sub refs the same ref?).
    • use_regex => 0 β€” regexes get compared directly (i.e., are the regexes the same?).
  • $compare = relaxed_convert($thing) β€” converts $thing into a Test2::Compare::* object. this one's the chill version, so it uses these settings:
    • implicit_end => 0 β€” array bounds are not checked when this object is used in a comparison. unexpected hash keys are welcome to show up. 🫢
    • use_code => 1 β€” sub references get run to verify a value.
    • use_regex => 1 β€” values get checked against any regexes you provide.

🌈 WRITING A VARIANT OF IS/LIKE 🌈

yes bestie, you can make your own. here's how:

use Test2::Compare qw/compare convert/;

sub my_like($$;$@) {
    my ($got, $exp, $name, @diag) = @_;
    my $ctx = context();

    # A custom converter that does the same thing as the one used by like()
    my $convert = sub {
        my $thing = shift;
        return convert(
            $thing,
            {
                implicit_end => 0,
                use_code     => 1,
                use_regex    => 1,
            }
        );
    };

    my $delta = compare($got, $exp, $convert);

    if ($delta) {
        $ctx->fail($name, $delta->diag, @diag);
    }
    else {
        $ctx->ok(1, $name);
    }

    $ctx->release;
    return !$delta;
}

the work of a comparison tool is carried out by 3 entities, and they're all icons in their own right:

  • compare() β€” the compare() function takes the structure you got, the specification you wanna check against, and a "\&convert" sub that converts anything that isn't an instance of a Test2::Compare::Base subclass into one. this tool runs the "\&convert" function on the specification, and then produces a Test2::Compare::Delta structure laying out every single way the structure you got deviates from the spec. it's giving receipts. 🧾
  • \&convert β€” converts anything that isn't an instance of a Test2::Compare::Base subclass and turns it into one. the objects it produces are fully able to check that a structure matches a specification. ✨
  • $delta β€” an instance of Test2::Compare::Delta is what ultimately gets returned. this object represents all the ways in which the structure you got deviated from the specification. the delta is a tree, so it may contain child deltas for nested structures. 🌲

the delta can also render itself as a table β€” use "@lines = $delta->diag" to get that table (and btw, the lines in @lines will not be terminated with "\n").

the convert() function this package hands you contains all the specification behavior of like() and is(). it's meant to be wrapped in a sub that passes in a configuration hash, which is what gives you control over the behavior. πŸ’…

and you're totally free to write your own "$check = compare($thing)" function β€” it just needs to accept a single argument, and produce a single instance of a Test2::Compare::Base subclass. that's the whole deal. periodt. πŸ‘‘


πŸ“¦ SOURCE πŸ“¦

the source code repository for Test2-Suite lives at:

https://github.com/Test-More/test-more/

go star it, bestie. ⭐


🫢 MAINTAINERS 🫢

Chad Granum <exodist@cpan.org>


πŸŽ€ AUTHORS πŸŽ€

Chad Granum <exodist@cpan.org>


Copyright Chad Granum <exodist@cpan.org>.

this program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://dev.perl.org/licenses/


and that's the whole page, bestie!! πŸ¦‹ this was rendered from perl v5.44.0, dated 2026-10-17, for Test2::Compare(3perl). mwah. πŸ’‹βœ¨πŸ’–

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms