/Test-Refcount-0.07/README

# · #! · 155 lines · 118 code · 37 blank · 0 comment · 0 complexity · ccf973c63ecd57feb5bbea91fce5fde1 MD5 · raw file

  1. NAME
  2. "Test::Refcount" - assert reference counts on objects
  3. SYNOPSIS
  4. use Test::More tests => 2;
  5. use Test::Refcount;
  6. use Some::Class;
  7. my $object = Some::Class->new();
  8. is_oneref( $object, '$object has a refcount of 1' );
  9. my $otherref = $object;
  10. is_refcount( $object, 2, '$object now has 2 references' );
  11. DESCRIPTION
  12. The Perl garbage collector uses simple reference counting during the
  13. normal execution of a program. This means that cycles or unweakened
  14. references in other parts of code can keep an object around for longer
  15. than intended. To help avoid this problem, the reference count of a new
  16. object from its class constructor ought to be 1. This way, the caller
  17. can know the object will be properly DESTROYed when it drops all of its
  18. references to it.
  19. This module provides two test functions to help ensure this property
  20. holds for an object class, so as to be polite to its callers.
  21. If the assertion fails; that is, if the actual reference count is
  22. different to what was expected, a trace of references to the object can
  23. be printed, if Marc Lehmann's Devel::FindRef module is installed. This
  24. may assist the developer in finding where the references are. See the
  25. examples below for more information.
  26. FUNCTIONS
  27. is_refcount( $object, $count, $name )
  28. Test that $object has $count references to it.
  29. is_oneref( $object, $name )
  30. Assert that the $object has only 1 reference to it.
  31. EXAMPLE
  32. Suppose, having written a new class "MyBall", you now want to check that
  33. its constructor and methods are well-behaved, and don't leak references.
  34. Consider the following test script:
  35. use Test::More tests => 2;
  36. use Test::Refcount;
  37. use MyBall;
  38. my $ball = MyBall->new();
  39. is_oneref( $ball, 'One reference after construct' );
  40. $ball->bounce;
  41. # Any other code here that might be part of the test script
  42. is_oneref( $ball, 'One reference just before EOF' );
  43. The first assertion is just after the constructor, to check that the
  44. reference returned by it is the only reference to that object. This fact
  45. is important if we ever want "DESTROY" to behave properly. The second
  46. call is right at the end of the file, just before the main scope closes.
  47. At this stage we expect the reference count also to be one, so that the
  48. object is properly cleaned up.
  49. Suppose, when run, this produces the following output (presuming
  50. "Devel::FindRef" is available):
  51. 1..2
  52. ok 1 - One reference after construct
  53. not ok 2 - One reference just before EOF
  54. # Failed test 'One reference just before EOF'
  55. # at demo.pl line 16.
  56. # expected 1 references, found 2
  57. # MyBall=ARRAY(0x817f880) is
  58. # +- referenced by REF(0x82c1fd8), which is
  59. # | in the member 'self' of HASH(0x82c1f68), which is
  60. # | referenced by REF(0x81989d0), which is
  61. # | in the member 'cycle' of HASH(0x82c1f68), which was seen before.
  62. # +- referenced by REF(0x82811d0), which is
  63. # in the lexical '$ball' in CODE(0x817fa00), which is
  64. # the main body of the program.
  65. # Looks like you failed 1 test of 2.
  66. From this output, we can see that the constructor was well-behaved, but
  67. that a reference was leaked by the end of the script - the reference
  68. count was 2, when we expected just 1. Reading the trace output, we can
  69. see that there were 2 references that "Devel::FindRef" could find - one
  70. stored in the $ball lexical in the main program, and one stored in a
  71. HASH. Since we expected to find the $ball lexical variable, we know we
  72. are now looking for a leak in a hash somewhere in the code. From reading
  73. the test script, we can guess this leak is likely to be in the bounce()
  74. method. Furthermore, we know that the reference to the object will be
  75. stored in a HASH in a member called "self".
  76. By reading the code which implements the bounce() method, we can see
  77. this is indeed the case:
  78. sub bounce
  79. {
  80. my $self = shift;
  81. my $cycle = { self => $self };
  82. $cycle->{cycle} = $cycle;
  83. }
  84. From reading the "Devel::FindRef" output, we find that the HASH this
  85. object is referenced in also contains a reference to itself, in a member
  86. called "cycle". This comes from the last line in this function, a line
  87. that purposely created a cycle, to demonstrate the point. While a real
  88. program probably wouldn't do anything quite this obvious, the trace
  89. would still be useful in finding the likely cause of the leak.
  90. If "Devel::FindRef" is unavailable, then these detailed traces will not
  91. be produced. The basic reference count testing will still take place,
  92. but a smaller message will be produced:
  93. 1..2
  94. ok 1 - One reference after construct
  95. not ok 2 - One reference just before EOF
  96. # Failed test 'One reference just before EOF'
  97. # at demo.pl line 16.
  98. # expected 1 references, found 2
  99. # Looks like you failed 1 test of 2.
  100. BUGS
  101. * Temporaries created on the stack
  102. Code which creates temporaries on the stack, to be released again
  103. when the called function returns does not work correctly on perl 5.8
  104. (and probably before). Examples such as
  105. is_oneref( [] );
  106. may fail and claim a reference count of 2 instead.
  107. Passing a variable such as
  108. my $array = [];
  109. is_oneref( $array );
  110. works fine. Because of the intention of this test module; that is,
  111. to assert reference counts on some object stored in a variable
  112. during the lifetime of the test script, this is unlikely to cause
  113. any problems.
  114. ACKNOWLEDGEMENTS
  115. Peter Rabbitson <ribasushi@cpan.org> - for suggesting using core's "B"
  116. instead of "Devel::Refcount" to obtain refcounts
  117. AUTHOR
  118. Paul Evans <leonerd@leonerd.org.uk>