| File: | local/lib/perl5/Test/Deep.pm |
| Coverage: | 37.5% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | 6 6 6 | 14 4 99 | use strict; | |||
| 2 | 6 6 6 | 13 2 105 | use warnings; | |||
| 3 | ||||||
| 4 | package Test::Deep; | |||||
| 5 | 6 6 6 | 10 4 182 | use Carp qw( confess ); | |||
| 6 | ||||||
| 7 | 6 6 6 | 808 8 74 | use Test::Deep::Cache; | |||
| 8 | 6 6 6 | 818 6 70 | use Test::Deep::Stack; | |||
| 9 | 6 6 6 | 772 5 81 | use Test::Deep::RegexpVersion; | |||
| 10 | ||||||
| 11 | require overload; | |||||
| 12 | 6 6 6 | 12 5 1074 | use Scalar::Util; | |||
| 13 | ||||||
| 14 | my $Test; | |||||
| 15 | unless (defined $Test::Deep::NoTest::NoTest) | |||||
| 16 | { | |||||
| 17 | # for people who want eq_deeply but not Test::Builder | |||||
| 18 | require Test::Builder; | |||||
| 19 | $Test = Test::Builder->new; | |||||
| 20 | } | |||||
| 21 | ||||||
| 22 | our ($Stack, %Compared, $CompareCache, %WrapCache, $Shallow); | |||||
| 23 | ||||||
| 24 | our $VERSION = '0.112'; | |||||
| 25 | $VERSION = eval $VERSION; | |||||
| 26 | ||||||
| 27 | require Exporter; | |||||
| 28 | our @ISA = qw( Exporter ); | |||||
| 29 | ||||||
| 30 | our $Snobby = 1; # should we compare classes? | |||||
| 31 | our $Expects = 0; # are we comparing got vs expect or expect vs expect | |||||
| 32 | ||||||
| 33 | our $DNE = \""; | |||||
| 34 | our $DNE_ADDR = Scalar::Util::refaddr($DNE); | |||||
| 35 | ||||||
| 36 | # if no sub name is supplied then we use the package name in lower case | |||||
| 37 | my @constructors = ( | |||||
| 38 | All => "", | |||||
| 39 | Any => "", | |||||
| 40 | Array => "", | |||||
| 41 | ArrayEach => "array_each", | |||||
| 42 | ArrayElementsOnly => "", | |||||
| 43 | ArrayLength => "", | |||||
| 44 | ArrayLengthOnly => "", | |||||
| 45 | Blessed => "", | |||||
| 46 | Boolean => "bool", | |||||
| 47 | Code => "", | |||||
| 48 | Hash => "", | |||||
| 49 | HashEach => "hash_each", | |||||
| 50 | HashKeys => "", | |||||
| 51 | HashKeysOnly => "", | |||||
| 52 | Ignore => "", | |||||
| 53 | Isa => "Isa", | |||||
| 54 | ListMethods => "", | |||||
| 55 | Methods => "", | |||||
| 56 | Number => "num", | |||||
| 57 | Obj => "obj_isa", | |||||
| 58 | RefType => "", | |||||
| 59 | Regexp => "re", | |||||
| 60 | RegexpMatches => "", | |||||
| 61 | RegexpOnly => "", | |||||
| 62 | RegexpRef => "", | |||||
| 63 | RegexpRefOnly => "", | |||||
| 64 | ScalarRef => "scalref", | |||||
| 65 | ScalarRefOnly => "", | |||||
| 66 | Shallow => "", | |||||
| 67 | String => "str", | |||||
| 68 | ); | |||||
| 69 | ||||||
| 70 | my @CONSTRUCTORS_FROM_CLASSES; | |||||
| 71 | ||||||
| 72 | while (my ($pkg, $name) = splice @constructors, 0, 2) | |||||
| 73 | { | |||||
| 74 | $name = lc($pkg) unless $name; | |||||
| 75 | my $full_pkg = "Test::Deep::$pkg"; | |||||
| 76 | my $file = "$full_pkg.pm"; | |||||
| 77 | $file =~ s#::#/#g; | |||||
| 78 | my $sub = sub { | |||||
| 79 | 176 | 5616 | require $file; | |||
| 80 | 176 | 285 | return $full_pkg->new(@_); | |||
| 81 | }; | |||||
| 82 | { | |||||
| 83 | 6 6 6 | 16 5 5955 | no strict 'refs'; | |||
| 84 | *{$name} = $sub; | |||||
| 85 | } | |||||
| 86 | ||||||
| 87 | push @CONSTRUCTORS_FROM_CLASSES, $name; | |||||
| 88 | } | |||||
| 89 | ||||||
| 90 | { | |||||
| 91 | our @EXPORT_OK = qw( descend render_stack class_base cmp_details deep_diag ); | |||||
| 92 | ||||||
| 93 | our %EXPORT_TAGS; | |||||
| 94 | $EXPORT_TAGS{v0} = [ | |||||
| 95 | qw( | |||||
| 96 | Isa | |||||
| 97 | blessed | |||||
| 98 | obj_isa | |||||
| 99 | ||||||
| 100 | all any array array_each arrayelementsonly arraylength arraylengthonly | |||||
| 101 | bag bool cmp_bag cmp_deeply cmp_methods cmp_set code eq_deeply | |||||
| 102 | hash hash_each hashkeys hashkeysonly ignore isa listmethods methods | |||||
| 103 | noclass num re reftype regexpmatches regexponly regexpref regexprefonly | |||||
| 104 | scalarrefonly scalref set shallow str subbagof subhashof subsetof | |||||
| 105 | superbagof superhashof supersetof useclass | |||||
| 106 | ) | |||||
| 107 | ]; | |||||
| 108 | ||||||
| 109 | $EXPORT_TAGS{v1} = [ | |||||
| 110 | qw( | |||||
| 111 | obj_isa | |||||
| 112 | ||||||
| 113 | all any array array_each arrayelementsonly arraylength arraylengthonly | |||||
| 114 | bag bool cmp_bag cmp_deeply cmp_methods cmp_set code eq_deeply | |||||
| 115 | hash hash_each hashkeys hashkeysonly ignore listmethods methods | |||||
| 116 | noclass num re reftype regexpmatches regexponly regexpref regexprefonly | |||||
| 117 | scalarrefonly scalref set shallow str subbagof subhashof subsetof | |||||
| 118 | superbagof superhashof supersetof useclass | |||||
| 119 | ) | |||||
| 120 | ]; | |||||
| 121 | ||||||
| 122 | our @EXPORT = @{ $EXPORT_TAGS{ v0 } }; | |||||
| 123 | ||||||
| 124 | $EXPORT_TAGS{all} = [ @EXPORT, @EXPORT_OK ]; | |||||
| 125 | } | |||||
| 126 | ||||||
| 127 | # this is ugly, I should never have exported a sub called isa now I | |||||
| 128 | # have to try figure out if the recipient wanted my isa or if a class | |||||
| 129 | # imported us and UNIVERSAL::isa is being called on that class. | |||||
| 130 | # Luckily our isa always expects 1 argument and U::isa always expects | |||||
| 131 | # 2, so we can figure out (assuming the caller is not buggy). | |||||
| 132 | sub isa | |||||
| 133 | { | |||||
| 134 | 0 | 0 | if (@_ == 1) | |||
| 135 | { | |||||
| 136 | 0 | 0 | goto &Isa; | |||
| 137 | } | |||||
| 138 | else | |||||
| 139 | { | |||||
| 140 | 0 | 0 | goto &UNIVERSAL::isa; | |||
| 141 | } | |||||
| 142 | } | |||||
| 143 | ||||||
| 144 | sub cmp_deeply | |||||
| 145 | { | |||||
| 146 | 54 | 37 | my ($d1, $d2, $name) = @_; | |||
| 147 | ||||||
| 148 | 54 | 62 | my ($ok, $stack) = cmp_details($d1, $d2); | |||
| 149 | ||||||
| 150 | 54 | 102 | if (not $Test->ok($ok, $name)) | |||
| 151 | { | |||||
| 152 | 0 | 0 | my $diag = deep_diag($stack); | |||
| 153 | 0 | 0 | $Test->diag($diag); | |||
| 154 | } | |||||
| 155 | ||||||
| 156 | 54 | 8425 | return $ok; | |||
| 157 | } | |||||
| 158 | ||||||
| 159 | sub cmp_details | |||||
| 160 | { | |||||
| 161 | 54 | 39 | my ($d1, $d2) = @_; | |||
| 162 | ||||||
| 163 | 54 | 114 | local $Stack = Test::Deep::Stack->new; | |||
| 164 | 54 | 99 | local $CompareCache = Test::Deep::Cache->new; | |||
| 165 | 54 | 66 | local %WrapCache; | |||
| 166 | ||||||
| 167 | 54 | 59 | my $ok = descend($d1, $d2); | |||
| 168 | ||||||
| 169 | 54 | 231 | return ($ok, $Stack); | |||
| 170 | } | |||||
| 171 | ||||||
| 172 | sub eq_deeply | |||||
| 173 | { | |||||
| 174 | 0 | 0 | my ($d1, $d2) = @_; | |||
| 175 | ||||||
| 176 | 0 | 0 | my ($ok) = cmp_details($d1, $d2); | |||
| 177 | ||||||
| 178 | 0 | 0 | return $ok | |||
| 179 | } | |||||
| 180 | ||||||
| 181 | sub eq_deeply_cache | |||||
| 182 | { | |||||
| 183 | # this is like cross between eq_deeply and descend(). It doesn't start | |||||
| 184 | # with a new $CompareCache but if the comparison fails it will leave | |||||
| 185 | # $CompareCache as if nothing happened. However, if the comparison | |||||
| 186 | # succeeds then $CompareCache retains all the new information | |||||
| 187 | ||||||
| 188 | # this allows Set and Bag to handle circular refs | |||||
| 189 | ||||||
| 190 | 0 | 0 | my ($d1, $d2, $name) = @_; | |||
| 191 | ||||||
| 192 | 0 | 0 | local $Stack = Test::Deep::Stack->new; | |||
| 193 | 0 | 0 | $CompareCache->local; | |||
| 194 | ||||||
| 195 | 0 | 0 | my $ok = descend($d1, $d2); | |||
| 196 | ||||||
| 197 | 0 | 0 | $CompareCache->finish($ok); | |||
| 198 | ||||||
| 199 | 0 | 0 | return $ok; | |||
| 200 | } | |||||
| 201 | ||||||
| 202 | sub deep_diag | |||||
| 203 | { | |||||
| 204 | 0 | 0 | my $stack = shift; | |||
| 205 | # ick! incArrow and other things expect the stack has to be visible | |||||
| 206 | # in a well known place . TODO clean this up | |||||
| 207 | 0 | 0 | local $Stack = $stack; | |||
| 208 | ||||||
| 209 | 0 | 0 | my $where = render_stack('$data', $stack); | |||
| 210 | ||||||
| 211 | 0 | 0 | confess "No stack to diagnose" unless $stack; | |||
| 212 | 0 | 0 | my $last = $stack->getLast; | |||
| 213 | ||||||
| 214 | 0 | 0 | my $diag; | |||
| 215 | my $message; | |||||
| 216 | 0 | 0 | my $got; | |||
| 217 | 0 | 0 | my $expected; | |||
| 218 | ||||||
| 219 | 0 | 0 | my $exp = $last->{exp}; | |||
| 220 | 0 | 0 | if (Scalar::Util::blessed($exp)) | |||
| 221 | { | |||||
| 222 | 0 | 0 | if ($exp->can("diagnostics")) | |||
| 223 | { | |||||
| 224 | 0 | 0 | $diag = $exp->diagnostics($where, $last); | |||
| 225 | 0 | 0 | $diag =~ s/\n+$/\n/; | |||
| 226 | } | |||||
| 227 | else | |||||
| 228 | { | |||||
| 229 | 0 | 0 | if ($exp->can("diag_message")) | |||
| 230 | { | |||||
| 231 | 0 | 0 | $message = $exp->diag_message($where); | |||
| 232 | } | |||||
| 233 | } | |||||
| 234 | } | |||||
| 235 | ||||||
| 236 | 0 | 0 | if (not defined $diag) | |||
| 237 | { | |||||
| 238 | 0 | 0 | $got = $exp->renderGot($last->{got}) unless defined $got; | |||
| 239 | 0 | 0 | $expected = $exp->renderExp unless defined $expected; | |||
| 240 | 0 | 0 | $message = "Compared $where" unless defined $message; | |||
| 241 | ||||||
| 242 | 0 | 0 | $diag = <<EOM | |||
| 243 | $message | |||||
| 244 | got : $got | |||||
| 245 | expect : $expected | |||||
| 246 | EOM | |||||
| 247 | } | |||||
| 248 | ||||||
| 249 | 0 | 0 | return $diag; | |||
| 250 | } | |||||
| 251 | ||||||
| 252 | sub render_val | |||||
| 253 | { | |||||
| 254 | 0 | 0 | my $val = shift; | |||
| 255 | ||||||
| 256 | 0 | 0 | my $rendered; | |||
| 257 | 0 | 0 | if (defined $val) | |||
| 258 | { | |||||
| 259 | 0 | 0 | $rendered = ref($val) ? | |||
| 260 | (Scalar::Util::refaddr($val) eq $DNE_ADDR ? | |||||
| 261 | "Does not exist" : | |||||
| 262 | overload::StrVal($val) | |||||
| 263 | ) : | |||||
| 264 | qq('$val'); | |||||
| 265 | } | |||||
| 266 | else | |||||
| 267 | { | |||||
| 268 | 0 | 0 | $rendered = "undef"; | |||
| 269 | } | |||||
| 270 | ||||||
| 271 | 0 | 0 | return $rendered; | |||
| 272 | } | |||||
| 273 | ||||||
| 274 | sub descend | |||||
| 275 | { | |||||
| 276 | 248 | 167 | my ($d1, $d2) = @_; | |||
| 277 | ||||||
| 278 | 248 | 354 | if (!ref $d1 and !ref $d2) | |||
| 279 | { | |||||
| 280 | # Shortcut comparison for the non-reference case. | |||||
| 281 | 72 | 59 | if (defined $d1) | |||
| 282 | { | |||||
| 283 | 72 | 241 | return 1 if defined $d2 and $d1 eq $d2; | |||
| 284 | } | |||||
| 285 | else | |||||
| 286 | { | |||||
| 287 | 0 | 0 | return 1 if !defined $d2; | |||
| 288 | } | |||||
| 289 | } | |||||
| 290 | ||||||
| 291 | 176 | 451 | if (! $Expects and Scalar::Util::blessed($d1) and $d1->isa("Test::Deep::Cmp")) | |||
| 292 | { | |||||
| 293 | 0 | 0 | my $where = $Stack->render('$data'); | |||
| 294 | 0 | 0 | confess "Found a special comparison in $where\nYou can only use specials in the expects structure"; | |||
| 295 | } | |||||
| 296 | ||||||
| 297 | 176 | 315 | if (ref $d1 and ref $d2) | |||
| 298 | { | |||||
| 299 | # this check is only done when we're comparing 2 expecteds against each | |||||
| 300 | # other | |||||
| 301 | ||||||
| 302 | 132 | 157 | if ($Expects and Scalar::Util::blessed($d1) and $d1->isa("Test::Deep::Cmp")) | |||
| 303 | { | |||||
| 304 | # check they are the same class | |||||
| 305 | 0 | 0 | return 0 unless Test::Deep::blessed(Scalar::Util::blessed($d2))->descend($d1); | |||
| 306 | 0 | 0 | if ($d1->can("compare")) | |||
| 307 | { | |||||
| 308 | 0 | 0 | return $d1->compare($d2); | |||
| 309 | } | |||||
| 310 | } | |||||
| 311 | ||||||
| 312 | 132 | 109 | my $s1 = Scalar::Util::refaddr($d1); | |||
| 313 | 132 | 81 | my $s2 = Scalar::Util::refaddr($d2); | |||
| 314 | ||||||
| 315 | 132 | 143 | if ($s1 eq $s2) | |||
| 316 | { | |||||
| 317 | 0 | 0 | return 1; | |||
| 318 | } | |||||
| 319 | 132 | 159 | if ($CompareCache->cmp($d1, $d2)) | |||
| 320 | { | |||||
| 321 | # we've tried comparing these already so either they turned out to | |||||
| 322 | # be the same or we must be in a loop and we have to assume they're | |||||
| 323 | # the same | |||||
| 324 | ||||||
| 325 | 0 | 0 | return 1; | |||
| 326 | } | |||||
| 327 | else | |||||
| 328 | { | |||||
| 329 | 132 | 144 | $CompareCache->add($d1, $d2) | |||
| 330 | } | |||||
| 331 | } | |||||
| 332 | ||||||
| 333 | 176 | 158 | $d2 = wrap($d2); | |||
| 334 | ||||||
| 335 | 176 | 331 | $Stack->push({exp => $d2, got => $d1}); | |||
| 336 | ||||||
| 337 | 176 | 371 | if (ref($d1) and (Scalar::Util::refaddr($d1) == $DNE_ADDR)) | |||
| 338 | { | |||||
| 339 | # whatever it was supposed to be, it didn't exist and so it's an | |||||
| 340 | # automatic fail | |||||
| 341 | 0 | 0 | return 0; | |||
| 342 | } | |||||
| 343 | ||||||
| 344 | 176 | 174 | if ($d2->descend($d1)) | |||
| 345 | { | |||||
| 346 | # print "d1 = $d1, d2 = $d2\nok\n"; | |||||
| 347 | 176 | 163 | $Stack->pop; | |||
| 348 | ||||||
| 349 | 176 | 260 | return 1; | |||
| 350 | } | |||||
| 351 | else | |||||
| 352 | { | |||||
| 353 | # print "d1 = $d1, d2 = $d2\nnot ok\n"; | |||||
| 354 | 0 | 0 | return 0; | |||
| 355 | } | |||||
| 356 | } | |||||
| 357 | ||||||
| 358 | sub wrap | |||||
| 359 | { | |||||
| 360 | 176 | 93 | my $data = shift; | |||
| 361 | ||||||
| 362 | 176 | 626 | return $data if Scalar::Util::blessed($data) and $data->isa("Test::Deep::Cmp"); | |||
| 363 | ||||||
| 364 | 22 | 23 | my ($class, $base) = class_base($data); | |||
| 365 | ||||||
| 366 | 22 | 15 | my $cmp; | |||
| 367 | ||||||
| 368 | 22 | 34 | if($base eq '') | |||
| 369 | { | |||||
| 370 | 0 | 0 | $cmp = shallow($data); | |||
| 371 | } | |||||
| 372 | else | |||||
| 373 | { | |||||
| 374 | 22 | 20 | my $addr = Scalar::Util::refaddr($data); | |||
| 375 | ||||||
| 376 | 22 | 29 | return $WrapCache{$addr} if $WrapCache{$addr}; | |||
| 377 | ||||||
| 378 | 22 | 22 | if($base eq 'ARRAY') | |||
| 379 | { | |||||
| 380 | 22 | 18 | $cmp = array($data); | |||
| 381 | } | |||||
| 382 | elsif($base eq 'HASH') | |||||
| 383 | { | |||||
| 384 | 0 | 0 | $cmp = hash($data); | |||
| 385 | } | |||||
| 386 | elsif($base eq 'SCALAR' or $base eq 'REF') | |||||
| 387 | { | |||||
| 388 | 0 | 0 | $cmp = scalref($data); | |||
| 389 | } | |||||
| 390 | elsif(($base eq 'Regexp') or ($base eq 'REGEXP')) | |||||
| 391 | { | |||||
| 392 | 0 | 0 | $cmp = regexpref($data); | |||
| 393 | } | |||||
| 394 | else | |||||
| 395 | { | |||||
| 396 | 0 | 0 | $cmp = shallow($data); | |||
| 397 | } | |||||
| 398 | ||||||
| 399 | 22 | 29 | $WrapCache{$addr} = $cmp; | |||
| 400 | } | |||||
| 401 | 22 | 17 | return $cmp; | |||
| 402 | } | |||||
| 403 | ||||||
| 404 | sub class_base | |||||
| 405 | { | |||||
| 406 | 22 | 16 | my $val = shift; | |||
| 407 | ||||||
| 408 | 22 | 23 | if (ref $val) | |||
| 409 | { | |||||
| 410 | 22 | 22 | my $blessed = Scalar::Util::blessed($val); | |||
| 411 | 22 | 23 | $blessed = defined($blessed) ? $blessed : ""; | |||
| 412 | 22 | 24 | my $reftype = Scalar::Util::reftype($val); | |||
| 413 | ||||||
| 414 | ||||||
| 415 | 22 | 26 | if ($Test::Deep::RegexpVersion::OldStyle) { | |||
| 416 | 0 | 0 | if ($blessed eq "Regexp" and $reftype eq "SCALAR") | |||
| 417 | { | |||||
| 418 | 0 | 0 | $reftype = "Regexp" | |||
| 419 | } | |||||
| 420 | } | |||||
| 421 | 22 | 24 | return ($blessed, $reftype); | |||
| 422 | } | |||||
| 423 | else | |||||
| 424 | { | |||||
| 425 | 0 | return ("", ""); | ||||
| 426 | } | |||||
| 427 | } | |||||
| 428 | ||||||
| 429 | sub render_stack | |||||
| 430 | { | |||||
| 431 | 0 | my ($var, $stack) = @_; | ||||
| 432 | ||||||
| 433 | 0 | return $stack->render($var); | ||||
| 434 | } | |||||
| 435 | ||||||
| 436 | sub cmp_methods | |||||
| 437 | { | |||||
| 438 | 0 | local $Test::Builder::Level = $Test::Builder::Level + 1; | ||||
| 439 | 0 0 | return cmp_deeply(shift, methods(@{shift()}), shift); | ||||
| 440 | } | |||||
| 441 | ||||||
| 442 | sub requireclass | |||||
| 443 | { | |||||
| 444 | 0 | require Test::Deep::Class; | ||||
| 445 | ||||||
| 446 | 0 | my $val = shift; | ||||
| 447 | ||||||
| 448 | 0 | return Test::Deep::Class->new(1, $val); | ||||
| 449 | } | |||||
| 450 | ||||||
| 451 | # docs and export say this is called useclass, doh! | |||||
| 452 | ||||||
| 453 | *useclass = \&requireclass; | |||||
| 454 | ||||||
| 455 | sub noclass | |||||
| 456 | { | |||||
| 457 | 0 | require Test::Deep::Class; | ||||
| 458 | ||||||
| 459 | 0 | my $val = shift; | ||||
| 460 | ||||||
| 461 | 0 | return Test::Deep::Class->new(0, $val); | ||||
| 462 | } | |||||
| 463 | ||||||
| 464 | sub set | |||||
| 465 | { | |||||
| 466 | 0 | require Test::Deep::Set; | ||||
| 467 | ||||||
| 468 | 0 | return Test::Deep::Set->new(1, "", @_); | ||||
| 469 | } | |||||
| 470 | ||||||
| 471 | sub supersetof | |||||
| 472 | { | |||||
| 473 | 0 | require Test::Deep::Set; | ||||
| 474 | ||||||
| 475 | 0 | return Test::Deep::Set->new(1, "sup", @_); | ||||
| 476 | } | |||||
| 477 | ||||||
| 478 | sub subsetof | |||||
| 479 | { | |||||
| 480 | 0 | require Test::Deep::Set; | ||||
| 481 | ||||||
| 482 | 0 | return Test::Deep::Set->new(1, "sub", @_); | ||||
| 483 | } | |||||
| 484 | ||||||
| 485 | sub cmp_set | |||||
| 486 | { | |||||
| 487 | 0 | local $Test::Builder::Level = $Test::Builder::Level + 1; | ||||
| 488 | 0 0 | return cmp_deeply(shift, set(@{shift()}), shift); | ||||
| 489 | } | |||||
| 490 | ||||||
| 491 | sub bag | |||||
| 492 | { | |||||
| 493 | 0 | require Test::Deep::Set; | ||||
| 494 | ||||||
| 495 | 0 | return Test::Deep::Set->new(0, "", @_); | ||||
| 496 | } | |||||
| 497 | ||||||
| 498 | sub superbagof | |||||
| 499 | { | |||||
| 500 | 0 | require Test::Deep::Set; | ||||
| 501 | ||||||
| 502 | 0 | return Test::Deep::Set->new(0, "sup", @_); | ||||
| 503 | } | |||||
| 504 | ||||||
| 505 | sub subbagof | |||||
| 506 | { | |||||
| 507 | 0 | require Test::Deep::Set; | ||||
| 508 | ||||||
| 509 | 0 | return Test::Deep::Set->new(0, "sub", @_); | ||||
| 510 | } | |||||
| 511 | ||||||
| 512 | sub cmp_bag | |||||
| 513 | { | |||||
| 514 | 0 | local $Test::Builder::Level = $Test::Builder::Level + 1; | ||||
| 515 | 0 | my $ref = ref($_[1]) || ""; | ||||
| 516 | 0 | confess "Argument 2 to cmp_bag is not an ARRAY ref (".render_val($_[1]).")" | ||||
| 517 | unless $ref eq "ARRAY"; | |||||
| 518 | 0 0 | return cmp_deeply(shift, bag(@{shift()}), shift); | ||||
| 519 | } | |||||
| 520 | ||||||
| 521 | sub superhashof | |||||
| 522 | { | |||||
| 523 | 0 | require Test::Deep::Hash; | ||||
| 524 | ||||||
| 525 | 0 | my $val = shift; | ||||
| 526 | ||||||
| 527 | 0 | return Test::Deep::SuperHash->new($val); | ||||
| 528 | } | |||||
| 529 | ||||||
| 530 | sub subhashof | |||||
| 531 | { | |||||
| 532 | 0 | require Test::Deep::Hash; | ||||
| 533 | ||||||
| 534 | 0 | my $val = shift; | ||||
| 535 | ||||||
| 536 | 0 | return Test::Deep::SubHash->new($val); | ||||
| 537 | } | |||||
| 538 | ||||||
| 539 | sub builder | |||||
| 540 | { | |||||
| 541 | 0 | if (@_) | ||||
| 542 | { | |||||
| 543 | 0 | $Test = shift; | ||||
| 544 | } | |||||
| 545 | 0 | return $Test; | ||||
| 546 | } | |||||
| 547 | ||||||
| 548 | 1; | |||||
| 549 | ||||||