1#!./perl 2 3BEGIN { 4 require Config; 5 if (($Config::Config{'extensions'} !~ m!\bList/Util\b!) ){ 6 print "1..0 # Skip -- Perl configured without List::Util module\n"; 7 exit 0; 8 } 9 10 # `make test` in the CPAN version of this module runs us with -w, but 11 # Dumpvalue.pm relies on all sorts of things that can cause warnings. I 12 # don't think that's worth fixing, so we just turn off all warnings 13 # during testing. 14 $^W = 0; 15} 16 17use lib ("./t/lib"); 18use TieOut; 19use Test::More tests => 88; 20 21use_ok( 'Dumpvalue' ); 22 23my $d; 24ok( $d = Dumpvalue->new(), 'create a new Dumpvalue object' ); 25 26$d->set( globPrint => 1, dumpReused => 1 ); 27is( $d->{globPrint}, 1, 'set an option correctly' ); 28is( $d->get('globPrint'), 1, 'get an option correctly' ); 29is_deeply( [ $d->get('globPrint', 'dumpReused') ], 30 [ 1, 1 ], 31 'get multiple options' 32); 33 34# check to see if unctrl works 35is( ref( Dumpvalue::unctrl(*FOO) ), 'GLOB', 'unctrl should not modify GLOB' ); 36is( Dumpvalue::unctrl('donotchange'), 'donotchange', "unctrl shouldn't modify"); 37like( Dumpvalue::unctrl("bo\007nd"), qr/bo\^.nd/, 'unctrl should escape' ); 38 39# check to see if stringify works 40is( $d->stringify(), 'undef', 'stringify handles undef okay' ); 41 42# the default is 1, but we want two single quotes 43$d->{printUndef} = 0; 44is( $d->stringify(), "''", 'stringify skips undef when asked nicely' ); 45 46is( $d->stringify(*FOO), *FOO . "", 'stringify stringifies globs alright' ); 47 48# check for double-quotes if there's an unprintable character 49$d->{tick} = 'auto'; 50like( $d->stringify("hi\005"), qr/^"hi/, 'added double-quotes when necessary' ); 51 52# if no unprintable character, escape ticks or backslashes 53is( $d->stringify('hi'), "'hi'", 'used single-quotes when appropriate' ); 54 55# if 'unctrl' is set 56$d->{unctrl} = 'unctrl'; 57like( $d->stringify('double and whack:\ "'), qr!\\ \"!, 'escaped with unctrl' ); 58like( $d->stringify("a\005"), qr/^"a\^/, 'escaped ASCII value in unctrl' ); 59like( $d->stringify("b\xb6"), qr!^'b.'$!, 'no high-bit escape value in unctrl'); 60 61$d->{quoteHighBit} = 1; 62like( $d->stringify("b\266"), qr!^'b\\266!, 'high-bit now escaped in unctrl'); 63 64# if 'quote' is set 65$d->{unctrl} = 'quote'; 66is( $d->stringify('5@ $1'), "'5\@ \$1'", 'quoted $ and @ fine' ); 67is( $d->stringify("5@\e\$1"), '"5\@\e\$1"', 'quoted $ and @ and \e fine' ); 68like( $d->stringify("\037"), qr/^"\\c/, 'escaped ASCII value okay' ); 69 70# add ticks, if necessary 71is( $d->stringify("no ticks", 1), 'no ticks', 'avoid ticks if asked' ); 72 73my $out = tie *OUT, 'TieOut'; 74select(OUT); 75 76# test DumpElem, it does its magic with veryCompact set 77$d->{veryCompact} = 1; 78$d->DumpElem([1, 2, 3]); 79is( $out->read, "0..2 1 2 3\n", 'DumpElem worked on array ref'); 80$d->DumpElem({ one => 1, two => 2 }); 81is( $out->read, "'one' => 1, 'two' => 2\n", 'DumpElem worked on hash ref' ); 82$d->DumpElem('hi'); 83is( $out->read, "'hi'\n", 'DumpElem worked on simple scalar' ); 84$d->{veryCompact} = 0; 85$d->DumpElem([]); 86like( $out->read, qr/ARRAY/, 'DumpElem okay with reference and no veryCompact'); 87 88# should compact simple arrays just fine 89$d->{veryCompact} = 1; 90$d->DumpElem([1, 2, 3]); 91is( $out->read, "0..2 1 2 3\n", 'dumped array fine' ); 92$d->{arrayDepth} = 2; 93$d->DumpElem([1, 2, 3]); 94is( $out->read, "0..2 1 2 ...\n", 'dumped limited array fine' ); 95 96# should compact simple hashes just fine 97$d->DumpElem({ a => 1, b => 2, c => 3 }); 98is( $out->read, "'a' => 1, 'b' => 2, 'c' => 3\n", 'dumped hash fine' ); 99$d->{hashDepth} = 2; 100$d->DumpElem({ a => 1, b => 2, c => 3 }); 101is( $out->read, "'a' => 1, 'b' => 2 ...\n", 'dumped limited hash fine' ); 102 103# should just stringify what it is 104$d->{veryCompact} = 0; 105$d->DumpElem([]); 106like( $out->read, qr/ARRAY.+empty array/s, 'stringified empty array ref' ); 107$d->DumpElem({}); 108like( $out->read, qr/HASH.+empty hash/s, 'stringified empty hash ref' ); 109$d->DumpElem(1); 110is( $out->read, "1\n", 'stringified simple scalar' ); 111 112# test unwrap 113$DB::signal = $d->{stopDbSignal} = 1; 114is( $d->unwrap(), undef, 'unwrap returns if DB signal is set' ); 115undef $DB::signal; 116 117my $foo = 7; 118$d->{dumpReused} = 0; 119$d->unwrap(\$foo); 120is( $out->read, "-> 7\n", 'unwrap worked on scalar' ); 121$d->unwrap(\$foo); 122is( $out->read, "-> REUSED_ADDRESS\n", 'unwrap worked on scalar' ); 123$d->unwrap({ one => 1 }); 124 125# leaving this at zero may cause some subsequent tests to fail 126# if they reuse an address creating an anonymous variable 127$d->{dumpReused} = 1; 128is( $out->read, "'one' => 1\n", 'unwrap worked on hash' ); 129$d->unwrap([ 2, 3 ]); 130is( $out->read, "0 2\n1 3\n", 'unwrap worked on array' ); 131$d->unwrap(*FOO); 132is( $out->read, '', 'unwrap ignored glob on first try'); 133$d->unwrap(*FOO); 134is( $out->read, "*DUMPED_GLOB*\n", 'unwrap worked on glob'); 135$d->unwrap(qr/foo(.+)/); 136 137my $modifiers = (qr// =~ /\Q(?^/) ? '^' : '-xism'; 138is( $out->read, "-> qr/(?${modifiers}:foo(.+))/\n", 'unwrap worked on Regexp' ); 139 140$d->unwrap( sub {} ); 141like( $out->read, qr/^-> &CODE/, 'unwrap worked on sub ref' ); 142 143# test matchvar 144# test to see if first arg 'eq' second 145ok( Dumpvalue::matchvar(1, 1), 'matchvar matched numbers fine' ); 146ok( Dumpvalue::matchvar('hi', 'hi'), 'matchvar matched strings fine' ); 147ok( !Dumpvalue::matchvar('hello', 1), 'matchvar caught failed match fine' ); 148 149# test compactDump, which doesn't do much 150is( $d->compactDump(3), 3, 'set compactDump to 3' ); 151is( $d->compactDump(1), 479, 'compactDump reset to 6*80-1 when less than 2' ); 152 153# test veryCompact, which does slightly more, setting compactDump sometimes 154$d->{compactDump} = 0; 155is( $d->veryCompact(1), 1, 'set veryCompact successfully' ); 156ok( $d->compactDump(), 'and it set compactDump as well' ); 157 158# test set_unctrl 159$d->set_unctrl('impossible value'); 160like( $out->read, qr/^Unknown value/, 'set_unctrl caught bad value' ); 161is( $d->set_unctrl('quote'), 'quote', 'set quote fine' ); 162is( $d->set_unctrl(), 'quote', 'retrieved quote fine' ); 163 164# test set_quote 165$d->set_quote('"'); 166is( $d->{tick}, '"', 'set_quote set tick right' ); 167is( $d->{unctrl}, 'quote', 'set unctrl right too' ); 168$d->set_quote('auto'); 169is( $d->{tick}, 'auto', 'set_quote set auto right' ); 170$d->set_quote('foo'); 171is( $d->{tick}, "'", 'default value set to " correctly' ); 172 173# test dumpglob 174# should do nothing if debugger signal flag is raised 175$d->{stopDbSignal} = $DB::signal = 1; 176is( $d->dumpglob(*DB::signal), undef, 'returned early with DB signal set' ); 177undef $DB::signal; 178 179# test dumping "normal" variables, this is a nasty glob trick 180$foo = 1; 181$d->dumpglob( '', 2, 'foo', local *foo = \$foo ); 182is( $out->read, " \$foo = 1\n", 'dumped glob for $foo correctly' ); 183our @bar = (1, 2); 184 185# the key name is a little different here 186$d->dumpglob( '', 0, 'boo', *bar ); 187is( $out->read, "\@boo = (\n 0..1 1 2\n)\n", 'dumped glob for @bar fine' ); 188 189our %baz = ( one => 1, two => 2 ); 190$d->dumpglob( '', 0, 'baz', *baz ); 191is( $out->read, "\%baz = (\n 'one' => 1, 'two' => 2\n)\n", 192 'dumped glob for %baz fine' ); 193 194SKIP: { 195 skip( "Couldn't open $0 for reading", 1 ) unless open(FILE, '<', $0); 196 my $fileno = fileno(FILE); 197 $d->dumpglob( '', 0, 'FILE', *FILE ); 198 is( $out->read, "FileHandle(FILE) => fileno($fileno)\n", 199 'dumped filehandle from glob fine' ); 200} 201 202$d->dumpglob( '', 0, 'read', *TieOut::read ); 203is( $out->read, '', 'no sub dumped without $all set' ); 204$d->dumpglob( '', 0, 'read', \&TieOut::read, 1 ); 205is( $out->read, "&read in ???\n", 'sub dumped when requested' ); 206 207# see if it dumps DB-like values correctly 208$d->{dumpDBFiles} = 1; 209$d->dumpglob( '', 0, '_<foo', *foo ); 210is( $out->read, "\$_<foo = 1\n", 'dumped glob for $_<foo correctly (DB)' ); 211 212# test CvGV name 213SKIP: { 214 if (" $Config::Config{'extensions'} " !~ m[ Devel/Peek ]) { 215 skip( 'no Devel::Peek', 2 ); 216 } 217 use_ok( 'Devel::Peek' ); 218 is( $d->CvGV_name(\&TieOut::read), 'TieOut::read', 'CvGV_name found sub' ); 219} 220 221# test dumpsub 222$d->dumpsub( '', 'TieOut::read' ); 223like( $out->read, qr/&TieOut::read in/, 'dumpsub found sub fine' ); 224 225# test findsubs 226is( $d->findsubs(), undef, 'findsubs returns nothing without %DB::sub' ); 227{ 228 no warnings 'once'; 229 $DB::sub{'TieOut::read'} = 'TieOut'; 230 is( $d->findsubs( \&TieOut::read ), 'TieOut::read', 'findsubs reported sub' ); 231} 232 233# now that it's capable of finding the package... 234$d->dumpsub( '', 'TieOut::read' ); 235is( $out->read, "&TieOut::read in TieOut\n", 'dumpsub found sub fine again' ); 236 237# this should print just a usage message 238$d->{usageOnly} = 1; 239$d->dumpvars( 'Fake', 'veryfake' ); 240like( $out->read, qr/^String space:/, 'printed usage message fine' ); 241delete $d->{usageOnly}; 242 243# this should report @INC and %INC 244$d->dumpvars( 'main', 'INC' ); 245like( $out->read, qr/\@INC =/, 'dumped variables from a package' ); 246 247# this should report nothing 248$DB::signal = 1; 249$d->dumpvars( 'main', 'INC' ); 250is( $out->read, '', 'no dump when $DB::signal is set' ); 251undef $DB::signal; 252 253is( $d->scalarUsage('12345'), 5, 'scalarUsage reports length correctly' ); 254is( $d->arrayUsage( [1, 2, 3], 'a' ), 3, 'arrayUsage reports correct lengths' ); 255is( $out->read, "\@a = 3 items (data: 3 bytes)\n", 'arrayUsage message okay' ); 256is( $d->hashUsage({ one => 1 }, 'b'), 4, 'hashUsage reports correct lengths' ); 257is( $out->read, "\%b = 1 item (keys: 3; values: 1; total: 4 bytes)\n", 258 'hashUsage message okay' ); 259is( $d->hashUsage({ one => [ 1, 2, 3 ]}, 'c'), 6, 'complex hash okay' ); 260is( $out->read, "\%c = 1 item (keys: 3; values: 3; total: 6 bytes)\n", 261 'hashUsage complex message okay' ); 262 263our $folly = 'one'; 264our @folly = ('two'); 265our %folly = ( three => '123' ); 266is( $d->globUsage(\*folly, 'folly'), 14, 'globUsage reports length correctly' ); 267like( $out->read, qr/\@folly =.+\%folly =/s, 'globValue message okay' ); 268 269# and now, the real show 270$d->dumpValue(undef); 271is( $out->read, "undef\n", 'dumpValue caught undef value okay' ); 272$d->dumpValue($folly); 273is( $out->read, "'one'\n", 'dumpValue worked' ); 274$d->dumpValue(@folly); 275is( $out->read, "'two'\n", 'dumpValue worked on array' ); 276$d->dumpValue(\$folly); 277is( $out->read, "-> 'one'\n", 'dumpValue worked on scalar ref' ); 278 279# dumpValues (the rest of these should be caught by unwrap) 280$d->dumpValues(undef); 281is( $out->read, "undef\n", 'dumpValues caught undef value fine' ); 282$d->dumpValues(\@folly); 283is( $out->read, "0 0..0 'two'\n", 'dumpValues worked on array ref' ); 284$d->dumpValues('one', 'two'); 285is( $out->read, "0..1 'one' 'two'\n", 'dumpValues worked on multiple values' ); 286 287