<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Test2::Compare::Object;
use strict;
use warnings;

use Test2::Util qw/try/;

use Test2::Compare::Meta();

use base 'Test2::Compare::Base';

our $VERSION = '0.000162';

use Test2::Util::HashBase qw/calls meta refcheck ending/;

use Carp qw/croak confess/;
use Scalar::Util qw/reftype blessed/;

sub init {
    my $self = shift;
    $self-&gt;{+CALLS} ||= [];
    $self-&gt;SUPER::init();
}

sub name { '&lt;OBJECT&gt;' }

sub meta_class  { 'Test2::Compare::Meta' }
sub object_base { 'UNIVERSAL' }

sub verify {
    my $self = shift;
    my %params = @_;
    my ($got, $exists) = @params{qw/got exists/};

    return 0 unless $exists;
    return 0 unless defined $got;
    return 0 unless ref($got);
    return 0 unless blessed($got);
    return 0 unless $got-&gt;isa($self-&gt;object_base);
    return 1;
}

sub add_prop {
    my $self = shift;
    $self-&gt;{+META} = $self-&gt;meta_class-&gt;new unless defined $self-&gt;{+META};
    $self-&gt;{+META}-&gt;add_prop(@_);
}

sub add_field {
    my $self = shift;
    $self-&gt;{+REFCHECK} = Test2::Compare::Hash-&gt;new unless defined $self-&gt;{+REFCHECK};

    croak "Underlying reference does not have fields"
        unless $self-&gt;{+REFCHECK}-&gt;can('add_field');

    $self-&gt;{+REFCHECK}-&gt;add_field(@_);
}

sub add_item {
    my $self = shift;
    $self-&gt;{+REFCHECK} = Test2::Compare::Array-&gt;new unless defined $self-&gt;{+REFCHECK};

    croak "Underlying reference does not have items"
        unless $self-&gt;{+REFCHECK}-&gt;can('add_item');

    $self-&gt;{+REFCHECK}-&gt;add_item(@_);
}

sub add_call {
    my $self = shift;
    my ($meth, $check, $name, $context) = @_;
    $name ||= ref $meth eq 'ARRAY' ? $meth-&gt;[0]
        : ref $meth eq 'CODE' ? '\&amp;CODE'
        : $meth;
    push @{$self-&gt;{+CALLS}} =&gt; [$meth, $check, $name, $context || 'scalar'];
}

sub deltas {
    my $self = shift;
    my %params = @_;
    my ($got, $convert, $seen) = @params{qw/got convert seen/};

    my @deltas;
    my $meta     = $self-&gt;{+META};
    my $refcheck = $self-&gt;{+REFCHECK};

    push @deltas =&gt; $meta-&gt;deltas(%params) if defined $meta;

    for my $call (@{$self-&gt;{+CALLS}}) {
        my ($meth, $check, $name, $context)= @$call;
        $context ||= 'scalar';

        $check = $convert-&gt;($check);

        my @args;
        if (ref($meth) eq 'ARRAY') {
            ($meth,@args) = @{$meth};
        }

        my $exists = ref($meth) || $got-&gt;can($meth);
        my $val;
        my ($ok, $err) = try {
            $val = $exists
                ? ( $context eq 'list' ? [ $got-&gt;$meth(@args) ] :
                    $context eq 'hash' ? { $got-&gt;$meth(@args) } :
                    $got-&gt;$meth(@args)
                )
                : undef;
        };

        if (!$ok) {
            push @deltas =&gt; $self-&gt;delta_class-&gt;new(
                verified  =&gt; undef,
                id        =&gt; [METHOD =&gt; $name],
                got       =&gt; undef,
                check     =&gt; $check,
                exception =&gt; $err,
            );
        }
        else {
            push @deltas =&gt; $check-&gt;run(
                id      =&gt; [METHOD =&gt; $name],
                convert =&gt; $convert,
                seen    =&gt; $seen,
                exists  =&gt; $exists,
                $exists ? (got =&gt; $val) : (),
            );
        }
    }

    return @deltas unless defined $refcheck;

    $refcheck-&gt;set_ending($self-&gt;{+ENDING});

    if ($refcheck-&gt;verify(%params)) {
        push @deltas =&gt; $refcheck-&gt;deltas(%params);
    }
    else {
        push @deltas =&gt; $self-&gt;delta_class-&gt;new(
            verified =&gt; undef,
            id       =&gt; [META =&gt; 'Object Ref'],
            got      =&gt; $got,
            check    =&gt; $refcheck,
        );
    }

    return @deltas;
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test2::Compare::Object - Representation of an object during deep
comparison.

=head1 DESCRIPTION

This class lets you specify an expected object in a deep comparison. You can
check the fields/elements of the underlying reference, call methods to verify
results, and do meta checks for object type and ref type.

=head1 METHODS

=over 4

=item $class = $obj-&gt;meta_class

The meta-class to be used when checking the object type. This is mainly listed
because it is useful to override for specialized object subclasses.

This normally just returns L&lt;Test2::Compare::Meta&gt;.

=item $class = $obj-&gt;object_base

The base-class to be expected when checking the object type. This is mainly
listed because it is useful to override for specialized object subclasses.

This normally just returns 'UNIVERSAL'.

=item $obj-&gt;add_prop(...)

Add a meta-property to check, see L&lt;Test2::Compare::Meta&gt;. This method
just delegates.

=item $obj-&gt;add_field(...)

Add a hash-field to check, see L&lt;Test2::Compare::Hash&gt;. This method
just delegates.

=item $obj-&gt;add_item(...)

Add an array item to check, see L&lt;Test2::Compare::Array&gt;. This method
just delegates.

=item $obj-&gt;add_call($method, $check)

=item $obj-&gt;add_call($method, $check, $name)

=item $obj-&gt;add_call($method, $check, $name, $context)

Add a method call check. This will call the specified method on your object and
verify the result. C&lt;$method&gt; may be a method name, an array ref, or a coderef.

If it's an arrayref, the first element must be the method name, and
the rest are arguments that will be passed to it.

In the case of a coderef it can be helpful to provide an alternate
name. When no name is provided the name is either C&lt;$method&gt; or the
string '\&amp;CODE'.

If C&lt;$context&gt; is C&lt;'list'&gt;, the method will be invoked in list
context, and the result will be an arrayref.

If C&lt;$context&gt; is C&lt;'hash'&gt;, the method will be invoked in list
context, and the result will be a hashref (this will warn if the
method returns an odd number of values).

=back

=head1 SOURCE

The source code repository for Test2-Suite can be found at
F&lt;https://github.com/Test-More/Test2-Suite/&gt;.

=head1 MAINTAINERS

=over 4

=item Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;

=back

=head1 AUTHORS

=over 4

=item Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;

=back

=head1 COPYRIGHT

Copyright 2018 Chad Granum E&lt;lt&gt;exodist@cpan.orgE&lt;gt&gt;.

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

See F&lt;http://dev.perl.org/licenses/&gt;

=cut
</pre></body></html>