|o||If Devel::FindRef module is installed, a reverse-references trace is printed to the test output.|
|o||If Devel::MAT is installed, this test module will use it to dump the state of the memory after a failure. It will create a .pmat file named the same as the unit test, but with the trailing .t suffix replaced with -TEST.pmat where TEST is the number of the test that failed (in case there was more than one).|
is_refcount( CW$object, CW$count, CW$name )Test that $object has $count references to it.
is_oneref( CW$object, CW$name )Assert that the $object has only 1 reference to it.
Suppose, having written a new class MyBall, you now want to check that its constructor and methods are well-behaved, and dont leak references. Consider the following test script:
The first assertion is just after the constructor, to check that the reference returned by it is the only reference to that object. This fact is important if we ever want DESTROY to behave properly. The second call is right at the end of the file, just before the main scope closes. At this stage we expect the reference count also to be one, so that the object is properly cleaned up.
Suppose, when run, this produces the following output (presuming Devel::FindRef is available):
1..2 ok 1 - One reference after construct not ok 2 - One reference just before EOF # Failed test One reference just before EOF # at demo.pl line 16. # expected 1 references, found 2 # MyBall=ARRAY(0x817f880) is # +- referenced by REF(0x82c1fd8), which is # | in the member self of HASH(0x82c1f68), which is # | referenced by REF(0x81989d0), which is # | in the member cycle of HASH(0x82c1f68), which was seen before. # +- referenced by REF(0x82811d0), which is # in the lexical $ball in CODE(0x817fa00), which is # the main body of the program. # Looks like you failed 1 test of 2.
From this output, we can see that the constructor was well-behaved, but that a reference was leaked by the end of the script - the reference count was 2, when we expected just 1. Reading the trace output, we can see that there were 2 references that Devel::FindRef could find - one stored in the $ball lexical in the main program, and one stored in a HASH. Since we expected to find the $ball lexical variable, we know we are now looking for a leak in a hash somewhere in the code. From reading the test script, we can guess this leak is likely to be in the bounce() method. Furthermore, we know that the reference to the object will be stored in a HASH in a member called self.
By reading the code which implements the bounce() method, we can see this is indeed the case:
From reading the Devel::FindRef output, we find that the HASH this object is referenced in also contains a reference to itself, in a member called cycle. This comes from the last line in this function, a line that purposely created a cycle, to demonstrate the point. While a real program probably wouldnt do anything quite this obvious, the trace would still be useful in finding the likely cause of the leak.
If Devel::FindRef is unavailable, then these detailed traces will not be produced. The basic reference count testing will still take place, but a smaller message will be produced:
o Temporaries created on the stack
Code which creates temporaries on the stack, to be released again when the called function returns does not work correctly on perl 5.8 (and probably before). Examples such as
is_oneref(  );
may fail and claim a reference count of 2 instead.
Passing a variable such as
my $array = ; is_oneref( $array );
works fine. Because of the intention of this test module; that is, to assert reference counts on some object stored in a variable during the lifetime of the test script, this is unlikely to cause any problems.
Peter Rabbitson <email@example.com> - for suggesting using cores B instead of Devel::Refcount to obtain refcounts
Paul Evans <firstname.lastname@example.org>
|perl v5.20.3||TEST::REFCOUNT (3)||2014-03-27|