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