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