File Coverage

blib/lib/Test/Identity.pm
Criterion Covered Total %
statement 36 37 97.3
branch 11 12 91.6
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 54 56 96.4


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010 -- leonerd@leonerd.org.uk
5              
6             package Test::Identity;
7              
8 2     2   24142 use strict;
  2         5  
  2         77  
9 2     2   12 use warnings;
  2         3  
  2         75  
10 2     2   11 use base qw( Test::Builder::Module );
  2         10  
  2         1051  
11              
12 2     2   575 use Scalar::Util qw( refaddr blessed );
  2         3  
  2         1002  
13              
14             our $VERSION = '0.01';
15              
16             our @EXPORT = qw(
17             identical
18             );
19              
20             =head1 NAME
21              
22             C - assert the referential identity of a reference
23              
24             =head1 SYNOPSIS
25              
26             use Test::More tests => 2;
27             use Test::Identity;
28              
29             use Thingy;
30              
31             {
32             my $thingy;
33              
34             sub get_thingy { return $thingy }
35             sub set_thingy { $thingy = shift; }
36             }
37              
38             identical( get_thingy, undef, 'get_thingy is undef' );
39              
40             my $test_thingy = Thingy->new;
41             set_thingy $test_thingy;
42              
43             identical( get_thingy, $thingy, 'get_thingy is now $test_thingy' );
44              
45             =head1 DESCRIPTION
46              
47             This module provides a single testing function, C. It asserts that
48             a given reference is as expected; that is, it either refers to the same object
49             or is C. It is similar to C except that it uses
50             C, ensuring that it behaves correctly even if the references under
51             test are objects that overload stringification or numification.
52              
53             It also provides better diagnostics if the test fails:
54              
55             $ perl -MTest::More=tests,1 -MTest::Identity -e'identical [], {}'
56             1..1
57             not ok 1
58             # Failed test at -e line 1.
59             # Expected an anonymous HASH ref, got an anonymous ARRAY ref
60             # Looks like you failed 1 test of 1.
61              
62             $ perl -MTest::More=tests,1 -MTest::Identity -e'identical [], []'
63             1..1
64             not ok 1
65             # Failed test at -e line 1.
66             # Expected an anonymous ARRAY ref to the correct object
67             # Looks like you failed 1 test of 1.
68              
69             =cut
70              
71             =head1 FUNCTIONS
72              
73             =cut
74              
75             sub _describe
76             {
77 16     16   22 my ( $ref ) = @_;
78              
79 16 100       65 if( !defined $ref ) {
    50          
    100          
80 5         11 return "undef";
81             }
82             elsif( !refaddr $ref ) {
83 0         0 return "a non-reference";
84             }
85             elsif( blessed $ref ) {
86 4         12 return "a reference to a " . ref( $ref );
87             }
88             else {
89 7         22 return "an anonymous " . ref( $ref ) . " ref";
90             }
91             }
92              
93             =head2 identical( $got, $expected, $name )
94              
95             Asserts that $got refers to the same object as $expected.
96              
97             =cut
98              
99             sub identical($$;$)
100             {
101 8     8 1 6354 my ( $got, $expected, $name ) = @_;
102              
103 8         38 my $tb = __PACKAGE__->builder;
104              
105 8         67 my $got_desc = _describe $got;
106 8         13 my $exp_desc = _describe $expected;
107              
108             # TODO: Consider if undef/undef ought to do this...
109 8 100       25 if( $got_desc ne $exp_desc ) {
110 4         12 $tb->ok( 0, $name );
111 4         1915 $tb->diag( "Expected $exp_desc, got $got_desc" );
112 4         271 return 0;
113             }
114              
115 4 100       12 if( !defined $got ) {
116             # Two undefs
117 1         7 $tb->ok( 1, $name );
118 1         349 return 1;
119             }
120              
121 3         6 my $got_addr = refaddr $got;
122 3         7 my $exp_addr = refaddr $expected;
123              
124 3 100       15 if( $got_addr != $exp_addr ) {
125 1         4 $tb->ok( 0, $name );
126 1         472 $tb->diag( "Expected $exp_desc to the correct object" );
127 1         70 return 0;
128             }
129              
130 2         8 $tb->ok( 1, $name );
131 2         542 return 1;
132             }
133              
134             # Keep perl happy; keep Britain tidy
135             1;
136              
137             __END__