4dad76
From 01aed385e6bdbdcfd13bb66e9d8b7c55d2cfc34a Mon Sep 17 00:00:00 2001
4dad76
From: James E Keenan <jkeenan@cpan.org>
4dad76
Date: Thu, 19 Sep 2019 23:02:54 -0400
4dad76
Subject: [PATCH] Handle undefined values correctly
4dad76
MIME-Version: 1.0
4dad76
Content-Type: text/plain; charset=UTF-8
4dad76
Content-Transfer-Encoding: 8bit
4dad76
4dad76
As reported by Henrik Pauli in RT 134441, the documentation's claim that
4dad76
4dad76
        $dv->dumpValue([$x, $y]);
4dad76
4dad76
and
4dad76
4dad76
        $dv->dumpValues($x, $y);
4dad76
4dad76
was not being sustained in the case where one of the elements in the
4dad76
array (or array ref) was undefined.  This was due to an insufficiently
4dad76
precise specification within the dumpValues() method for determining
4dad76
when the value "undef\n" should be printed.
4dad76
4dad76
Tests for previously untested cases have been provided in
4dad76
t/rt-134441-dumpvalue.t.  They were not appended to t/Dumpvalue.t (as
4dad76
would normally have been the case) because the tests in that file have
4dad76
accreted over the years in a sub-optimal manner:  changes in attributes
4dad76
of the Dumpvalue object are tested but those changes are not zeroed-out
4dad76
(by, e.g., use of 'local $self->{attribute} = undef')
4dad76
before additional attributes are modified and tested.  As a consequence,
4dad76
it's difficult to determine the state of the Dumpvalue object at any
4dad76
particular point and interactions between attributes cannot be ruled
4dad76
out.
4dad76
4dad76
Package TieOut, used to capture STDOUT during testing, has been
4dad76
extracted to its own file so that it can be used by all test files.
4dad76
4dad76
Signed-off-by: Petr Písař <ppisar@redhat.com>
4dad76
---
4dad76
 MANIFEST                               |  2 +
4dad76
 dist/Dumpvalue/lib/Dumpvalue.pm        |  4 +-
4dad76
 dist/Dumpvalue/t/Dumpvalue.t           | 20 +-----
4dad76
 dist/Dumpvalue/t/lib/TieOut.pm         | 20 ++++++
4dad76
 dist/Dumpvalue/t/rt-134441-dumpvalue.t | 86 ++++++++++++++++++++++++++
4dad76
 5 files changed, 112 insertions(+), 20 deletions(-)
4dad76
 create mode 100644 dist/Dumpvalue/t/lib/TieOut.pm
4dad76
 create mode 100644 dist/Dumpvalue/t/rt-134441-dumpvalue.t
4dad76
4dad76
diff --git a/MANIFEST b/MANIFEST
4dad76
index 7bf62d8479..8159ac8cc1 100644
4dad76
--- a/MANIFEST
4dad76
+++ b/MANIFEST
4dad76
@@ -3455,6 +3455,8 @@ dist/Devel-SelfStubber/lib/Devel/SelfStubber.pm	Generate stubs for SelfLoader.pm
4dad76
 dist/Devel-SelfStubber/t/Devel-SelfStubber.t	See if Devel::SelfStubber works
4dad76
 dist/Dumpvalue/lib/Dumpvalue.pm	Screen dump of perl values
4dad76
 dist/Dumpvalue/t/Dumpvalue.t	See if Dumpvalue works
4dad76
+dist/Dumpvalue/t/lib/TieOut.pm	Helper module for Dumpvalue tests
4dad76
+dist/Dumpvalue/t/rt-134441-dumpvalue.t	See if Dumpvalue works
4dad76
 dist/encoding-warnings/lib/encoding/warnings.pm	warn on implicit encoding conversions
4dad76
 dist/encoding-warnings/t/1-warning.t	tests for encoding::warnings
4dad76
 dist/encoding-warnings/t/2-fatal.t	tests for encoding::warnings
4dad76
diff --git a/dist/Dumpvalue/lib/Dumpvalue.pm b/dist/Dumpvalue/lib/Dumpvalue.pm
4dad76
index eef9b27157..3faf829538 100644
4dad76
--- a/dist/Dumpvalue/lib/Dumpvalue.pm
4dad76
+++ b/dist/Dumpvalue/lib/Dumpvalue.pm
4dad76
@@ -1,7 +1,7 @@
4dad76
 use 5.006_001;			# for (defined ref) and $#$v and our
4dad76
 package Dumpvalue;
4dad76
 use strict;
4dad76
-our $VERSION = '1.18';
4dad76
+our $VERSION = '1.19';
4dad76
 our(%address, $stab, @stab, %stab, %subs);
4dad76
 
4dad76
 sub ASCII { return ord('A') == 65; }
4dad76
@@ -79,7 +79,7 @@ sub dumpValues {
4dad76
   my $self = shift;
4dad76
   local %address;
4dad76
   local $^W=0;
4dad76
-  (print "undef\n"), return unless defined $_[0];
4dad76
+  (print "undef\n"), return if (@_ == 1 and not defined $_[0]);
4dad76
   $self->unwrap(\@_,0);
4dad76
 }
4dad76
 
4dad76
diff --git a/dist/Dumpvalue/t/Dumpvalue.t b/dist/Dumpvalue/t/Dumpvalue.t
4dad76
index 7063dd984c..ba8775126e 100644
4dad76
--- a/dist/Dumpvalue/t/Dumpvalue.t
4dad76
+++ b/dist/Dumpvalue/t/Dumpvalue.t
4dad76
@@ -16,6 +16,8 @@ BEGIN {
4dad76
 
4dad76
 our ( $foo, @bar, %baz );
4dad76
 
4dad76
+use lib ("./t/lib");
4dad76
+use TieOut;
4dad76
 use Test::More tests => 88;
4dad76
 
4dad76
 use_ok( 'Dumpvalue' );
4dad76
@@ -278,21 +280,3 @@ is( $out->read, "0  0..0  'two'\n", 'dumpValues worked on array ref' );
4dad76
 $d->dumpValues('one', 'two');
4dad76
 is( $out->read, "0..1  'one' 'two'\n", 'dumpValues worked on multiple values' );
4dad76
 
4dad76
-
4dad76
-package TieOut;
4dad76
-use overload '"' => sub { "overloaded!" };
4dad76
-
4dad76
-sub TIEHANDLE {
4dad76
-	my $class = shift;
4dad76
-	bless(\( my $ref), $class);
4dad76
-}
4dad76
-
4dad76
-sub PRINT {
4dad76
-	my $self = shift;
4dad76
-	$$self .= join('', @_);
4dad76
-}
4dad76
-
4dad76
-sub read {
4dad76
-	my $self = shift;
4dad76
-	return substr($$self, 0, length($$self), '');
4dad76
-}
4dad76
diff --git a/dist/Dumpvalue/t/lib/TieOut.pm b/dist/Dumpvalue/t/lib/TieOut.pm
4dad76
new file mode 100644
4dad76
index 0000000000..568caedf9c
4dad76
--- /dev/null
4dad76
+++ b/dist/Dumpvalue/t/lib/TieOut.pm
4dad76
@@ -0,0 +1,20 @@
4dad76
+package TieOut;
4dad76
+use overload '"' => sub { "overloaded!" };
4dad76
+
4dad76
+sub TIEHANDLE {
4dad76
+	my $class = shift;
4dad76
+	bless(\( my $ref), $class);
4dad76
+}
4dad76
+
4dad76
+sub PRINT {
4dad76
+	my $self = shift;
4dad76
+	$$self .= join('', @_);
4dad76
+}
4dad76
+
4dad76
+sub read {
4dad76
+	my $self = shift;
4dad76
+	return substr($$self, 0, length($$self), '');
4dad76
+}
4dad76
+
4dad76
+1;
4dad76
+
4dad76
diff --git a/dist/Dumpvalue/t/rt-134441-dumpvalue.t b/dist/Dumpvalue/t/rt-134441-dumpvalue.t
4dad76
new file mode 100644
4dad76
index 0000000000..cc9f270f5a
4dad76
--- /dev/null
4dad76
+++ b/dist/Dumpvalue/t/rt-134441-dumpvalue.t
4dad76
@@ -0,0 +1,86 @@
4dad76
+BEGIN {
4dad76
+	require Config;
4dad76
+	if (($Config::Config{'extensions'} !~ m!\bList/Util\b!) ){
4dad76
+	    print "1..0 # Skip -- Perl configured without List::Util module\n";
4dad76
+	    exit 0;
4dad76
+	}
4dad76
+
4dad76
+	# `make test` in the CPAN version of this module runs us with -w, but
4dad76
+	# Dumpvalue.pm relies on all sorts of things that can cause warnings. I
4dad76
+	# don't think that's worth fixing, so we just turn off all warnings
4dad76
+	# during testing.
4dad76
+	$^W = 0;
4dad76
+}
4dad76
+
4dad76
+use lib ("./t/lib");
4dad76
+use TieOut;
4dad76
+use Test::More tests => 17;
4dad76
+
4dad76
+use_ok( 'Dumpvalue' );
4dad76
+
4dad76
+my $d;
4dad76
+ok( $d = Dumpvalue->new(), 'create a new Dumpvalue object' );
4dad76
+
4dad76
+my $out = tie *OUT, 'TieOut';
4dad76
+select(OUT);
4dad76
+
4dad76
+my (@foobar, $x, $y);
4dad76
+
4dad76
+@foobar = ('foo', 'bar');
4dad76
+$d->dumpValue([@foobar]);
4dad76
+$x = $out->read;
4dad76
+is( $x, "0  'foo'\n1  'bar'\n", 'dumpValue worked on array ref' );
4dad76
+$d->dumpValues(@foobar);
4dad76
+$y = $out->read;
4dad76
+is( $y, "0  'foo'\n1  'bar'\n", 'dumpValues worked on array' );
4dad76
+is( $y, $x,
4dad76
+    "dumpValues called on array returns same as dumpValue on array ref");
4dad76
+
4dad76
+@foobar = (undef, 'bar');
4dad76
+$d->dumpValue([@foobar]);
4dad76
+$x = $out->read;
4dad76
+is( $x, "0  undef\n1  'bar'\n",
4dad76
+    'dumpValue worked on array ref, first element undefined' );
4dad76
+$d->dumpValues(@foobar);
4dad76
+$y = $out->read;
4dad76
+is( $y, "0  undef\n1  'bar'\n",
4dad76
+    'dumpValues worked on array, first element undefined' );
4dad76
+is( $y, $x,
4dad76
+    "dumpValues called on array returns same as dumpValue on array ref, first element undefined");
4dad76
+
4dad76
+@foobar = ('bar', undef);
4dad76
+$d->dumpValue([@foobar]);
4dad76
+$x = $out->read;
4dad76
+is( $x, "0  'bar'\n1  undef\n",
4dad76
+    'dumpValue worked on array ref, last element undefined' );
4dad76
+$d->dumpValues(@foobar);
4dad76
+$y = $out->read;
4dad76
+is( $y, "0  'bar'\n1  undef\n",
4dad76
+    'dumpValues worked on array, last element undefined' );
4dad76
+is( $y, $x,
4dad76
+    "dumpValues called on array returns same as dumpValue on array ref, last element undefined");
4dad76
+
4dad76
+@foobar = ('', 'bar');
4dad76
+$d->dumpValue([@foobar]);
4dad76
+$x = $out->read;
4dad76
+is( $x, "0  ''\n1  'bar'\n",
4dad76
+    'dumpValue worked on array ref, first element empty string' );
4dad76
+$d->dumpValues(@foobar);
4dad76
+$y = $out->read;
4dad76
+is( $y, "0  ''\n1  'bar'\n",
4dad76
+    'dumpValues worked on array, first element empty string' );
4dad76
+is( $y, $x,
4dad76
+    "dumpValues called on array returns same as dumpValue on array ref, first element empty string");
4dad76
+
4dad76
+@foobar = ('bar', '');
4dad76
+$d->dumpValue([@foobar]);
4dad76
+$x = $out->read;
4dad76
+is( $x, "0  'bar'\n1  ''\n",
4dad76
+    'dumpValue worked on array ref, last element empty string' );
4dad76
+$d->dumpValues(@foobar);
4dad76
+$y = $out->read;
4dad76
+is( $y, "0  'bar'\n1  ''\n",
4dad76
+    'dumpValues worked on array, last element empty string' );
4dad76
+is( $y, $x,
4dad76
+    "dumpValues called on array returns same as dumpValue on array ref, last element empty string");
4dad76
+
4dad76
-- 
4dad76
2.21.0
4dad76