Hello community, here is the log from the commit of package perl-Test-Refcount for openSUSE:Factory checked in at 2019-06-26 16:04:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Test-Refcount (Old) and /work/SRC/openSUSE:Factory/.perl-Test-Refcount.new.4615 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Test-Refcount" Wed Jun 26 16:04:24 2019 rev:2 rq:712052 version:0.09 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Test-Refcount/perl-Test-Refcount.changes 2015-05-11 19:49:24.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.perl-Test-Refcount.new.4615/perl-Test-Refcount.changes 2019-06-26 16:04:55.599705176 +0200 @@ -1,0 +2,13 @@ +Wed Jun 26 05:43:08 UTC 2019 - Stephan Kulow <coolo@please-enter-an-email-address> + +- updated to 0.09 + see /usr/share/doc/packages/perl-Test-Refcount/Changes + + 0.09 2019-06-25 21:06:57 + [CHANGES] + * Add a `refcount()` function that callers can use to build + refcount-preserving tests + * Adjust docs to explain more about the Devel::MAT use-case + * General build file style updates + +------------------------------------------------------------------- Old: ---- Test-Refcount-0.08.tar.gz New: ---- Test-Refcount-0.09.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Test-Refcount.spec ++++++ --- /var/tmp/diff_new_pack.r29uJO/_old 2019-06-26 16:04:58.183708833 +0200 +++ /var/tmp/diff_new_pack.r29uJO/_new 2019-06-26 16:04:58.211708872 +0200 @@ -1,7 +1,7 @@ # # spec file for package perl-Test-Refcount # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,25 +12,26 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: perl-Test-Refcount -Version: 0.08 +Version: 0.09 Release: 0 %define cpan_name Test-Refcount -Summary: Assert Reference Counts On Objects -License: Artistic-1.0 or GPL-1.0+ +Summary: Assert reference counts on objects +License: Artistic-1.0 OR GPL-1.0-or-later Group: Development/Libraries/Perl -Url: http://search.cpan.org/dist/Test-Refcount/ -Source0: http://www.cpan.org/authors/id/P/PE/PEVANS/%{cpan_name}-%{version}.tar.gz +Url: https://metacpan.org/release/%{cpan_name} +Source0: https://cpan.metacpan.org/authors/id/P/PE/PEVANS/%{cpan_name}-%{version}.tar.gz Source1: cpanspec.yml BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: perl BuildRequires: perl-macros -BuildRequires: perl(Module::Build) +BuildRequires: perl(Module::Build) >= 0.400400 +BuildRequires: perl(Test::More) >= 0.88 Recommends: perl(Devel::MAT) >= 0.04 %{perl_requires} @@ -53,7 +54,7 @@ %setup -q -n %{cpan_name}-%{version} %build -%{__perl} Build.PL installdirs=vendor +perl Build.PL installdirs=vendor ./Build build flags=%{?_smp_mflags} %check @@ -65,6 +66,7 @@ %files -f %{name}.files %defattr(-,root,root,755) -%doc Changes LICENSE README +%doc Changes README +%license LICENSE %changelog ++++++ Test-Refcount-0.08.tar.gz -> Test-Refcount-0.09.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/Build.PL new/Test-Refcount-0.09/Build.PL --- old/Test-Refcount-0.08/Build.PL 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/Build.PL 2019-06-25 22:09:32.000000000 +0200 @@ -13,15 +13,19 @@ recommends => { 'Devel::MAT' => '0.04', }, - build_requires => { + configure_requires => { + 'Module::Build' => '0.4004', # test_requires + }, + test_requires => { 'Test::Builder::Tester' => 0, - 'Test::More' => 0, + 'Test::More' => '0.88', # done_testing }, - auto_configure_requires => 0, # Don't add M::B to configure_requires license => 'perl', - create_makefile_pl => 'traditional', create_license => 1, create_readme => 1, + extra_manify_args => { + utf8 => 1, # We have UTF-8 manpages + }, ); $build->create_build_script; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/Changes new/Test-Refcount-0.09/Changes --- old/Test-Refcount-0.08/Changes 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/Changes 2019-06-25 22:09:32.000000000 +0200 @@ -1,5 +1,12 @@ Revision history for Test-Refcount +0.09 2019-06-25 21:06:57 + [CHANGES] + * Add a `refcount()` function that callers can use to build + refcount-preserving tests + * Adjust docs to explain more about the Devel::MAT use-case + * General build file style updates + 0.08 2014/03/27 16:10:38 [CHANGES] * Optional integration with Devel::MAT if available, to heapdump the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/LICENSE new/Test-Refcount-0.09/LICENSE --- old/Test-Refcount-0.08/LICENSE 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/LICENSE 2019-06-25 22:09:32.000000000 +0200 @@ -1,4 +1,4 @@ -This software is copyright (c) 2014 by Paul Evans <[email protected]>. +This software is copyright (c) 2019 by Paul Evans <[email protected]>. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. @@ -12,7 +12,7 @@ --- The GNU General Public License, Version 1, February 1989 --- -This software is Copyright (c) 2014 by Paul Evans <[email protected]>. +This software is Copyright (c) 2019 by Paul Evans <[email protected]>. This is free software, licensed under: @@ -22,7 +22,7 @@ Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. - 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -272,7 +272,7 @@ --- The Artistic License 1.0 --- -This software is Copyright (c) 2014 by Paul Evans <[email protected]>. +This software is Copyright (c) 2019 by Paul Evans <[email protected]>. This is free software, licensed under: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/MANIFEST new/Test-Refcount-0.09/MANIFEST --- old/Test-Refcount-0.08/MANIFEST 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/MANIFEST 2019-06-25 22:09:32.000000000 +0200 @@ -2,8 +2,8 @@ Changes lib/Test/Refcount.pm LICENSE -Makefile.PL MANIFEST This list of files +META.json META.yml README t/00use.t @@ -12,4 +12,3 @@ t/03weak.t t/04reftypes.t t/99pod.t -META.json diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/META.json new/Test-Refcount-0.09/META.json --- old/Test-Refcount-0.08/META.json 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/META.json 2019-06-25 22:09:32.000000000 +0200 @@ -4,20 +4,19 @@ "Paul Evans <[email protected]>" ], "dynamic_config" : 1, - "generated_by" : "Module::Build version 0.4204", + "generated_by" : "Module::Build version 0.4224", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : "2" + "version" : 2 }, "name" : "Test-Refcount", "prereqs" : { - "build" : { + "configure" : { "requires" : { - "Test::Builder::Tester" : "0", - "Test::More" : "0" + "Module::Build" : "0.4004" } }, "runtime" : { @@ -29,12 +28,18 @@ "Scalar::Util" : "0", "Test::Builder" : "0" } + }, + "test" : { + "requires" : { + "Test::Builder::Tester" : "0", + "Test::More" : "0.88" + } } }, "provides" : { "Test::Refcount" : { "file" : "lib/Test/Refcount.pm", - "version" : "0.08" + "version" : "0.09" } }, "release_status" : "stable", @@ -43,5 +48,6 @@ "http://dev.perl.org/licenses/" ] }, - "version" : "0.08" + "version" : "0.09", + "x_serialization_backend" : "JSON::PP version 4.00" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/META.yml new/Test-Refcount-0.09/META.yml --- old/Test-Refcount-0.08/META.yml 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/META.yml 2019-06-25 22:09:32.000000000 +0200 @@ -4,9 +4,11 @@ - 'Paul Evans <[email protected]>' build_requires: Test::Builder::Tester: '0' - Test::More: '0' + Test::More: '0.88' +configure_requires: + Module::Build: '0.4004' dynamic_config: 1 -generated_by: 'Module::Build version 0.4204, CPAN::Meta::Converter version 2.133380' +generated_by: 'Module::Build version 0.4224, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -15,7 +17,7 @@ provides: Test::Refcount: file: lib/Test/Refcount.pm - version: '0.08' + version: '0.09' recommends: Devel::MAT: '0.04' requires: @@ -24,4 +26,5 @@ Test::Builder: '0' resources: license: http://dev.perl.org/licenses/ -version: '0.08' +version: '0.09' +x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/Makefile.PL new/Test-Refcount-0.09/Makefile.PL --- old/Test-Refcount-0.08/Makefile.PL 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/Makefile.PL 1970-01-01 01:00:00.000000000 +0100 @@ -1,18 +0,0 @@ -# Note: this file was auto-generated by Module::Build::Compat version 0.4204 -use ExtUtils::MakeMaker; -WriteMakefile -( - 'NAME' => 'Test::Refcount', - 'VERSION_FROM' => 'lib/Test/Refcount.pm', - 'PREREQ_PM' => { - 'B' => 0, - 'Scalar::Util' => 0, - 'Test::Builder' => 0, - 'Test::Builder::Tester' => 0, - 'Test::More' => 0 - }, - 'INSTALLDIRS' => 'site', - 'EXE_FILES' => [], - 'PL_FILES' => {} -) -; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/README new/Test-Refcount-0.09/README --- old/Test-Refcount-0.08/README 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/README 2019-06-25 22:09:32.000000000 +0200 @@ -1,21 +1,24 @@ NAME - `Test::Refcount' - assert reference counts on objects -SYNOPSIS - use Test::More tests => 2; - use Test::Refcount; - - use Some::Class; - - my $object = Some::Class->new(); + Test::Refcount - assert reference counts on objects - is_oneref( $object, '$object has a refcount of 1' ); - - my $otherref = $object; +SYNOPSIS - is_refcount( $object, 2, '$object now has 2 references' ); + use Test::More tests => 2; + use Test::Refcount; + + use Some::Class; + + my $object = Some::Class->new(); + + is_oneref( $object, '$object has a refcount of 1' ); + + my $otherref = $object; + + is_refcount( $object, 2, '$object now has 2 references' ); DESCRIPTION + The Perl garbage collector uses simple reference counting during the normal execution of a program. This means that cycles or unweakened references in other parts of code can keep an object around for longer @@ -31,133 +34,195 @@ different to what was expected, either of the following two modules may be used to assist the developer in finding where the references are. - * If Devel::FindRef module is installed, a reverse-references trace is - printed to the test output. + * 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). - * 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). + * If Devel::FindRef module is installed, a reverse-references trace + is printed to the test output. See the examples below for more information. FUNCTIONS - is_refcount( $object, $count, $name ) + + is_refcount + + is_refcount( $object, $count, $name ) + Test that $object has $count references to it. - is_oneref( $object, $name ) + is_oneref + + is_oneref( $object, $name ) + Assert that the $object has only 1 reference to it. + refcount + + $count = refcount( $object ) + + Since version 0.09. + + Returns the reference count of the given object as used by the test + functions. This is useful for making tests that don't care what the + count is before they start, but simply assert that the count hasn't + changed by the end. + + use Test::Refcount import => [qw( is_refcount refcount )]; + { + my $count = refcount( $object ); + + do_something( $object ); + + is_refcount( $object, $count, 'do_something() preserves refcount' ); + } + EXAMPLE - Suppose, having written a new class `MyBall', you now want to check that - its constructor and methods are well-behaved, and don't leak references. - Consider the following test script: - - use Test::More tests => 2; - use Test::Refcount; - - use MyBall; - - my $ball = MyBall->new(); - is_oneref( $ball, 'One reference after construct' ); - - $ball->bounce; - - # Any other code here that might be part of the test script - - is_oneref( $ball, 'One reference just before EOF' ); + + Suppose, having written a new class MyBall, you now want to check that + its constructor and methods are well-behaved, and don't leak + references. Consider the following test script: + + use Test::More tests => 2; + use Test::Refcount; + + use MyBall; + + my $ball = MyBall->new(); + is_oneref( $ball, 'One reference after construct' ); + + $ball->bounce; + + # Any other code here that might be part of the test script + + is_oneref( $ball, 'One reference just before EOF' ); 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. + 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): + Devel::MAT::Dumper 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. + 1..2 + ok 1 - One reference after construct + not ok 2 - One reference just before EOF + # Failed test 'One reference just before EOF' + # at ex.pl line 26. + # expected 1 references, found 2 + # SV address is 0x55e14c310278 + # Writing heap dump to ex-2.pmat + # Looks like you failed 1 test of 2. + + This has written a ex-2.pmat file we can load using the pmat shell and + use the identify command on the given address to find where it went: + + $ pmat ex-2.pmat + Perl memory dumpfile from perl 5.28.1 threaded + Heap contains 25233 objects + pmat> identify 0x55e14c310278 + HASH(0)=MyBall at 0x55e14c310278 is: + ├─(via RV) the lexical $ball at depth 1 of CODE() at 0x55e14c3104a0=main_cv, which is: + │ └─the main code + └─(via RV) value {self} of HASH(2) at 0x55e14cacb860, which is (*A): + └─(via RV) value {cycle} of HASH(2) at 0x55e14cacb860, which is: + itself + + (This document isn't intended to be a full tutorial on Devel::MAT and + the pmat shell; for that see Devel::MAT::UserGuide). + + Alternatively, this produces the following output when using + Devel::FindRef instead: + + 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() + see that there were 2 references that could be found - 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'. + 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: - sub bounce - { - my $self = shift; - my $cycle = { self => $self }; - $cycle->{cycle} = $cycle; - } - - 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 + sub bounce + { + my $self = shift; + my $cycle = { self => $self }; + $cycle->{cycle} = $cycle; + } + + From reading the tracing 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 wouldn't 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: - - 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 - # Looks like you failed 1 test of 2. + If neither Devel::MAT::Dumper nor Devel::FindRef are available, then + these detailed traces will not be produced. The basic reference count + testing will still take place, but a smaller message will be produced: + + 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 + # Looks like you failed 1 test of 2. BUGS - * 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 + + * 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. + may fail and claim a reference count of 2 instead. - Passing a variable such as + 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. + 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. ACKNOWLEDGEMENTS - Peter Rabbitson <[email protected]> - for suggesting using core's `B' - instead of `Devel::Refcount' to obtain refcounts + + Peter Rabbitson <[email protected]> - for suggesting using core's B + instead of Devel::Refcount to obtain refcounts AUTHOR + Paul Evans <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/lib/Test/Refcount.pm new/Test-Refcount-0.09/lib/Test/Refcount.pm --- old/Test-Refcount-0.08/lib/Test/Refcount.pm 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/lib/Test/Refcount.pm 2019-06-25 22:09:32.000000000 +0200 @@ -1,7 +1,7 @@ # You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # -# (C) Paul Evans, 2008-2014 -- [email protected] +# (C) Paul Evans, 2008-2019 -- [email protected] package Test::Refcount; @@ -12,33 +12,40 @@ use Scalar::Util qw( weaken refaddr ); use B qw( svref_2object ); -our $VERSION = '0.08'; +our $VERSION = '0.09'; our @EXPORT = qw( is_refcount is_oneref ); +our @EXPORT_OK = qw( + refcount +); + +use constant HAVE_DEVEL_FINDREF => defined eval { require Devel::FindRef }; use constant HAVE_DEVEL_MAT_DUMPER => defined eval { require Devel::MAT::Dumper }; +=encoding UTF-8 + =head1 NAME C<Test::Refcount> - assert reference counts on objects =head1 SYNOPSIS - use Test::More tests => 2; - use Test::Refcount; + use Test::More tests => 2; + use Test::Refcount; - use Some::Class; + use Some::Class; - my $object = Some::Class->new(); + my $object = Some::Class->new(); - is_oneref( $object, '$object has a refcount of 1' ); + is_oneref( $object, '$object has a refcount of 1' ); - my $otherref = $object; + my $otherref = $object; - is_refcount( $object, 2, '$object now has 2 references' ); + is_refcount( $object, 2, '$object now has 2 references' ); =head1 DESCRIPTION @@ -60,17 +67,17 @@ =item * -If L<Devel::FindRef> module is installed, a reverse-references trace is -printed to the test output. - -=item * - If L<Devel::MAT> is installed, this test module will use it to dump the state of the memory after a failure. It will create a F<.pmat> file named the same as the unit test, but with the trailing F<.t> suffix replaced with F<-TEST.pmat> where C<TEST> is the number of the test that failed (in case there was more than one). +=item * + +If L<Devel::FindRef> module is installed, a reverse-references trace is +printed to the test output. + =back See the examples below for more information. @@ -81,7 +88,9 @@ =cut -=head2 is_refcount( $object, $count, $name ) +=head2 is_refcount + + is_refcount( $object, $count, $name ) Test that $object has $count references to it. @@ -102,17 +111,14 @@ weaken $object; # So this reference itself doesn't show up - my $REFCNT = svref_2object($object)->REFCNT; + my $REFCNT = refcount( $object ); my $ok = $tb->ok( $REFCNT == $count, $name ); unless( $ok ) { $tb->diag( " expected $count references, found $REFCNT" ); - if( eval { require Devel::FindRef } ) { - $tb->diag( Devel::FindRef::track( $object ) ); - } - elsif( HAVE_DEVEL_MAT_DUMPER ) { + if( HAVE_DEVEL_MAT_DUMPER ) { my $file = $0; my $num = $tb->current_test; @@ -124,12 +130,17 @@ $tb->diag( "Writing heap dump to $file" ); Devel::MAT::Dumper::dump( $file ); } + if( HAVE_DEVEL_FINDREF ) { + $tb->diag( Devel::FindRef::track( $object ) ); + } } return $ok; } -=head2 is_oneref( $object, $name ) +=head2 is_oneref + + is_oneref( $object, $name ) Assert that the $object has only 1 reference to it. @@ -141,25 +152,51 @@ goto &is_refcount; } +=head2 refcount + + $count = refcount( $object ) + +I<Since version 0.09.> + +Returns the reference count of the given object as used by the test functions. +This is useful for making tests that don't care what the count is before they +start, but simply assert that the count hasn't changed by the end. + + use Test::Refcount import => [qw( is_refcount refcount )]; + { + my $count = refcount( $object ); + + do_something( $object ); + + is_refcount( $object, $count, 'do_something() preserves refcount' ); + } + +=cut + +sub refcount +{ + return svref_2object( $_[0] )->REFCNT; +} + =head1 EXAMPLE Suppose, having written a new class C<MyBall>, you now want to check that its constructor and methods are well-behaved, and don't leak references. Consider the following test script: - - use Test::More tests => 2; - use Test::Refcount; - - use MyBall; - - my $ball = MyBall->new(); - is_oneref( $ball, 'One reference after construct' ); - - $ball->bounce; - - # Any other code here that might be part of the test script - - is_oneref( $ball, 'One reference just before EOF' ); + + use Test::More tests => 2; + use Test::Refcount; + + use MyBall; + + my $ball = MyBall->new(); + is_oneref( $ball, 'One reference after construct' ); + + $ball->bounce; + + # Any other code here that might be part of the test script + + is_oneref( $ball, 'One reference just before EOF' ); 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 @@ -168,62 +205,92 @@ the reference count also to be one, so that the object is properly cleaned up. Suppose, when run, this produces the following output (presuming -C<Devel::FindRef> is available): +L<Devel::MAT::Dumper> 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. + 1..2 + ok 1 - One reference after construct + not ok 2 - One reference just before EOF + # Failed test 'One reference just before EOF' + # at ex.pl line 26. + # expected 1 references, found 2 + # SV address is 0x55e14c310278 + # Writing heap dump to ex-2.pmat + # Looks like you failed 1 test of 2. + +This has written a F<ex-2.pmat> file we can load using the C<pmat> shell and +use the C<identify> command on the given address to find where it went: + + $ pmat ex-2.pmat + Perl memory dumpfile from perl 5.28.1 threaded + Heap contains 25233 objects + pmat> identify 0x55e14c310278 + HASH(0)=MyBall at 0x55e14c310278 is: + ├─(via RV) the lexical $ball at depth 1 of CODE() at 0x55e14c3104a0=main_cv, which is: + │ └─the main code + └─(via RV) value {self} of HASH(2) at 0x55e14cacb860, which is (*A): + └─(via RV) value {cycle} of HASH(2) at 0x55e14cacb860, which is: + itself + +(This document isn't intended to be a full tutorial on L<Devel::MAT> and the +C<pmat> shell; for that see L<Devel::MAT::UserGuide>). + +Alternatively, this produces the following output when using L<Devel::FindRef> +instead: + + 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 C<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 C<self>. +2 references that could be found - 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 C<self>. By reading the code which implements the bounce() method, we can see this is indeed the case: - sub bounce - { - my $self = shift; - my $cycle = { self => $self }; - $cycle->{cycle} = $cycle; - } + sub bounce + { + my $self = shift; + my $cycle = { self => $self }; + $cycle->{cycle} = $cycle; + } -From reading the C<Devel::FindRef> output, we find that the HASH this object -is referenced in also contains a reference to itself, in a member called +From reading the tracing output, we find that the HASH this object is +referenced in also contains a reference to itself, in a member called C<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 wouldn't do anything quite this obvious, the trace would still be useful in finding the likely cause of the leak. -If C<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: - - 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 - # Looks like you failed 1 test of 2. +If neither C<Devel::MAT::Dumper> nor C<Devel::FindRef> are available, then +these detailed traces will not be produced. The basic reference count testing +will still take place, but a smaller message will be produced: + + 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 + # Looks like you failed 1 test of 2. =head1 BUGS @@ -235,14 +302,14 @@ called function returns does not work correctly on perl 5.8 (and probably before). Examples such as - is_oneref( [] ); + is_oneref( [] ); may fail and claim a reference count of 2 instead. Passing a variable such as - my $array = []; - is_oneref( $array ); + 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/00use.t new/Test-Refcount-0.09/t/00use.t --- old/Test-Refcount-0.08/t/00use.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/00use.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,5 +1,10 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl -use Test::More tests => 1; +use strict; +use warnings; + +use Test::More; use_ok( "Test::Refcount" ); + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/01count.t new/Test-Refcount-0.09/t/01count.t --- old/Test-Refcount-0.08/t/01count.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/01count.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,8 +1,10 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl use strict; +use warnings; -use Test::Builder::Tester tests => 8; +use Test::More; +use Test::Builder::Tester; use Test::Refcount; @@ -74,3 +76,5 @@ $pmat =~ s/\.t$/-1.pmat/; unlink $pmat if -f $pmat; } + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/02one.t new/Test-Refcount-0.09/t/02one.t --- old/Test-Refcount-0.08/t/02one.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/02one.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,8 +1,10 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl use strict; +use warnings; -use Test::Builder::Tester tests => 3; +use Test::More; +use Test::Builder::Tester; use Test::Refcount; @@ -42,3 +44,5 @@ $pmat =~ s/\.t$/-1.pmat/; unlink $pmat if -f $pmat; } + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/03weak.t new/Test-Refcount-0.09/t/03weak.t --- old/Test-Refcount-0.08/t/03weak.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/03weak.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,8 +1,10 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl use strict; +use warnings; -use Test::Builder::Tester tests => 2; +use Test::More; +use Test::Builder::Tester; use Scalar::Util qw( weaken ); @@ -40,3 +42,5 @@ $pmat =~ s/\.t$/-1.pmat/; unlink $pmat if -f $pmat; } + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/04reftypes.t new/Test-Refcount-0.09/t/04reftypes.t --- old/Test-Refcount-0.08/t/04reftypes.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/04reftypes.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,9 +1,10 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl use strict; +use warnings; -use Test::Builder::Tester tests => 6; use Test::More; +use Test::Builder::Tester; use Symbol qw( gensym ); @@ -35,3 +36,5 @@ test_test( "anon $type ref succeeds" ); } } + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Test-Refcount-0.08/t/99pod.t new/Test-Refcount-0.09/t/99pod.t --- old/Test-Refcount-0.08/t/99pod.t 2014-03-27 17:13:01.000000000 +0100 +++ new/Test-Refcount-0.09/t/99pod.t 2019-06-25 22:09:32.000000000 +0200 @@ -1,4 +1,7 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl + +use strict; +use warnings; use Test::More;
