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