File Coverage

blib/lib/Test/Refcount.pm
Criterion Covered Total %
statement 43 44 97.7
branch 5 6 83.3
condition n/a
subroutine 8 8 100.0
pod 2 2 100.0
total 58 60 96.6


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, 2008-2014 -- leonerd@leonerd.org.uk
5              
6             package Test::Refcount;
7              
8 5     5   138207 use strict;
  5         13  
  5         205  
9 5     5   30 use warnings;
  5         12  
  5         175  
10 5     5   33 use base qw( Test::Builder::Module );
  5         18  
  5         4396  
11              
12 5     5   2902 use Scalar::Util qw( weaken refaddr );
  5         17  
  5         610  
13 5     5   28 use B qw( svref_2object );
  5         11  
  5         630  
14              
15             our $VERSION = '0.08';
16              
17             our @EXPORT = qw(
18             is_refcount
19             is_oneref
20             );
21              
22 5     5   35 use constant HAVE_DEVEL_MAT_DUMPER => defined eval { require Devel::MAT::Dumper };
  5         9  
  5         10  
  5         5563  
23              
24             =head1 NAME
25              
26             C - assert reference counts on objects
27              
28             =head1 SYNOPSIS
29              
30             use Test::More tests => 2;
31             use Test::Refcount;
32              
33             use Some::Class;
34              
35             my $object = Some::Class->new();
36              
37             is_oneref( $object, '$object has a refcount of 1' );
38              
39             my $otherref = $object;
40              
41             is_refcount( $object, 2, '$object now has 2 references' );
42              
43             =head1 DESCRIPTION
44              
45             The Perl garbage collector uses simple reference counting during the normal
46             execution of a program. This means that cycles or unweakened references in
47             other parts of code can keep an object around for longer than intended. To
48             help avoid this problem, the reference count of a new object from its class
49             constructor ought to be 1. This way, the caller can know the object will be
50             properly DESTROYed when it drops all of its references to it.
51              
52             This module provides two test functions to help ensure this property holds
53             for an object class, so as to be polite to its callers.
54              
55             If the assertion fails; that is, if the actual reference count is different to
56             what was expected, either of the following two modules may be used to assist
57             the developer in finding where the references are.
58              
59             =over 4
60              
61             =item *
62              
63             If L module is installed, a reverse-references trace is
64             printed to the test output.
65              
66             =item *
67              
68             If L is installed, this test module will use it to dump the state
69             of the memory after a failure. It will create a F<.pmat> file named the same
70             as the unit test, but with the trailing F<.t> suffix replaced with
71             F<-TEST.pmat> where C is the number of the test that failed (in case
72             there was more than one).
73              
74             =back
75              
76             See the examples below for more information.
77              
78             =cut
79              
80             =head1 FUNCTIONS
81              
82             =cut
83              
84             =head2 is_refcount( $object, $count, $name )
85              
86             Test that $object has $count references to it.
87              
88             =cut
89              
90             sub is_refcount($$;$)
91             {
92 18     18 1 8368 my ( $object, $count, $name ) = @_;
93 18         28 @_ = ();
94              
95 18         102 my $tb = __PACKAGE__->builder;
96              
97 18 100       173 if( !ref $object ) {
98 1         3 my $ok = $tb->ok( 0, $name );
99 1         420 $tb->diag( " expected a reference, was not given one" );
100 1         54 return $ok;
101             }
102              
103 17         56 weaken $object; # So this reference itself doesn't show up
104              
105 17         203 my $REFCNT = svref_2object($object)->REFCNT;
106              
107 17         71 my $ok = $tb->ok( $REFCNT == $count, $name );
108              
109 17 100       5091 unless( $ok ) {
110 3         21 $tb->diag( " expected $count references, found $REFCNT" );
111              
112 3 50       254 if( eval { require Devel::FindRef } ) {
  3         1539  
113 0         0 $tb->diag( Devel::FindRef::track( $object ) );
114             }
115             elsif( HAVE_DEVEL_MAT_DUMPER ) {
116 3         13 my $file = $0;
117 3         17 my $num = $tb->current_test;
118              
119             # Trim the .t off first then append -$num.pmat, in case $0 wasn't a .t file
120 3         42 $file =~ s/\.(?:t|pm|pl)$//;
121 3         13 $file .= "-$num\.pmat";
122              
123 3         33 $tb->diag( sprintf "SV address is 0x%x", refaddr $object );
124 3         239 $tb->diag( "Writing heap dump to $file" );
125 3         157809 Devel::MAT::Dumper::dump( $file );
126             }
127             }
128              
129 17         83 return $ok;
130             }
131              
132             =head2 is_oneref( $object, $name )
133              
134             Assert that the $object has only 1 reference to it.
135              
136             =cut
137              
138             sub is_oneref($;$)
139             {
140 5     5 1 3506 splice( @_, 1, 0, ( 1 ) );
141 5         22 goto &is_refcount;
142             }
143              
144             =head1 EXAMPLE
145              
146             Suppose, having written a new class C, you now want to check that its
147             constructor and methods are well-behaved, and don't leak references. Consider
148             the following test script:
149            
150             use Test::More tests => 2;
151             use Test::Refcount;
152            
153             use MyBall;
154            
155             my $ball = MyBall->new();
156             is_oneref( $ball, 'One reference after construct' );
157            
158             $ball->bounce;
159              
160             # Any other code here that might be part of the test script
161            
162             is_oneref( $ball, 'One reference just before EOF' );
163              
164             The first assertion is just after the constructor, to check that the reference
165             returned by it is the only reference to that object. This fact is important if
166             we ever want C to behave properly. The second call is right at the
167             end of the file, just before the main scope closes. At this stage we expect
168             the reference count also to be one, so that the object is properly cleaned up.
169              
170             Suppose, when run, this produces the following output (presuming
171             C is available):
172              
173             1..2
174             ok 1 - One reference after construct
175             not ok 2 - One reference just before EOF
176             # Failed test 'One reference just before EOF'
177             # at demo.pl line 16.
178             # expected 1 references, found 2
179             # MyBall=ARRAY(0x817f880) is
180             # +- referenced by REF(0x82c1fd8), which is
181             # | in the member 'self' of HASH(0x82c1f68), which is
182             # | referenced by REF(0x81989d0), which is
183             # | in the member 'cycle' of HASH(0x82c1f68), which was seen before.
184             # +- referenced by REF(0x82811d0), which is
185             # in the lexical '$ball' in CODE(0x817fa00), which is
186             # the main body of the program.
187             # Looks like you failed 1 test of 2.
188              
189             From this output, we can see that the constructor was well-behaved, but that a
190             reference was leaked by the end of the script - the reference count was 2,
191             when we expected just 1. Reading the trace output, we can see that there were
192             2 references that C could find - one stored in the $ball
193             lexical in the main program, and one stored in a HASH. Since we expected to
194             find the $ball lexical variable, we know we are now looking for a leak in a
195             hash somewhere in the code. From reading the test script, we can guess this
196             leak is likely to be in the bounce() method. Furthermore, we know that the
197             reference to the object will be stored in a HASH in a member called C.
198              
199             By reading the code which implements the bounce() method, we can see this is
200             indeed the case:
201              
202             sub bounce
203             {
204             my $self = shift;
205             my $cycle = { self => $self };
206             $cycle->{cycle} = $cycle;
207             }
208              
209             From reading the C output, we find that the HASH this object
210             is referenced in also contains a reference to itself, in a member called
211             C. This comes from the last line in this function, a line that
212             purposely created a cycle, to demonstrate the point. While a real program
213             probably wouldn't do anything quite this obvious, the trace would still be
214             useful in finding the likely cause of the leak.
215              
216             If C is unavailable, then these detailed traces will not be
217             produced. The basic reference count testing will still take place, but a
218             smaller message will be produced:
219              
220             1..2
221             ok 1 - One reference after construct
222             not ok 2 - One reference just before EOF
223             # Failed test 'One reference just before EOF'
224             # at demo.pl line 16.
225             # expected 1 references, found 2
226             # Looks like you failed 1 test of 2.
227              
228             =head1 BUGS
229              
230             =over 4
231              
232             =item * Temporaries created on the stack
233              
234             Code which creates temporaries on the stack, to be released again when the
235             called function returns does not work correctly on perl 5.8 (and probably
236             before). Examples such as
237              
238             is_oneref( [] );
239              
240             may fail and claim a reference count of 2 instead.
241              
242             Passing a variable such as
243              
244             my $array = [];
245             is_oneref( $array );
246              
247             works fine. Because of the intention of this test module; that is, to assert
248             reference counts on some object stored in a variable during the lifetime of
249             the test script, this is unlikely to cause any problems.
250              
251             =back
252              
253             =head1 ACKNOWLEDGEMENTS
254              
255             Peter Rabbitson - for suggesting using core's C
256             instead of C to obtain refcounts
257              
258             =head1 AUTHOR
259              
260             Paul Evans
261              
262             =cut
263              
264             0x55AA;