Test::Stream::Compare - Tools for comparing data structures.


This distribution is deprecated in favor of Test2, Test2::Suite, and Test2::Workflow.

See Test::Stream::Manual::ToTest2 for a conversion guide.


This library is the driving force behind is(). The library is the base class for several comparison classes that allow for deep structure comparisons.



    package Test::Stream::Compare::MyCheck;
    use strict;
    use warnings;

    use base 'Test::Stream::Compare';
    use Test::Stream::HashBase accessors => [qw/stuff/];

    sub name { 'STUFF' }

    sub operator {
        my $self = shift;
        my ($got) = @_;
        return 'eq';

    sub verify {
        my $self = shift;
        my $params = @_;

        # Always check if $got even exists, this will be false if no value at
        # all was received. (as opposed to a $got of 'undef' or '0' which are
        # valid meaning this field will be true).
        return 0 unless $params{exists};

        my $got = $params{got};

        return $got eq $self->stuff;


    package Test::Stream::Plugin::MyCheck;

    use Test::Stream::Compare::MyCheck;

    use Test::Stream::Compare qw/compare get_build push_build pop_build build/;

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

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

        if ($delta) {
            $ctx->ok(0, $name, [$delta->table, @diag]);
        else {
            $ctx->ok(1, $name);

        return !$delta;

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

        return Test::Stream::Compare::MyCheck->new(stuff => $thing);


$delta = compare($got, $expect, \&convert)

This will compare the structures in $got with those in $expect, The convert sub should convert vanilla structures inside $expect into checks. If there are differences in the structures they will be reported back as an Test::Stream::Delta tree.

$build = get_build()

Get the current global build, if any.


Set the current global build.

$build = pop_build($build)

Unset the current global build. This will throw an exception if the build passed in is different from the current global.

build($class, sub { ... })

Run the provided codeblock with a new instance of $class as the current build. Returns the new build.


Some of these must be overriden, others can be.

$dclass = $check->delta_class

Returns the delta subclass that should be used. By default Test::Stream::Delta is used.

@deltas = $check->deltas(id => $id, exists => $bool, got => $got, convert => \&convert, seen => \%seen)

Should return child deltas.

@lines = $check->got_lines($got)

This is your chance to provide line numbers for errors in the $got structure.

$op = $check->operator()
$op = $check->operator($got)

Returns the operator that was used to compare the check with the received data in $got. If there was no value for got then there will be no arguments, undef will only be an argument if undef was seen in $got, this is how you can tell the difference between a missing value and an undefined one.

$bool = $check->verify(id => $id, exists => $bool, got => $got, convert => \&convert, seen => \%seen)

Return true if there is a shallow match, that is both items are arrayrefs, both items are the same string or same number, etc. This should not look deep, deep checks are done in $check->deltas().

$name = $check->name

Get the name of the check.

$display = $check->render

What should be displayed in a table for this check, usually the name or value.

$delta = $check->run(id => $id, exists => $bool, got => $got, convert => \&convert, seen => \%seen)

This is where the checking is done, first a shallow check using $check->verify, then checking $check->deltas(). \%seen is used to prevent cycles.


The source code repository for Test::Stream can be found at


Chad Granum <>


Chad Granum <>


Copyright 2015 Chad Granum <>.

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