LanX has asked for the wisdom of the Perl Monks concerning the following question:

I'm a little surprised about the behavior of Test::More::is_deeply()

I have a deeply nested data-structure supposed to return contain scalar refs.

But is_deeply() digs into the refs and compares the scalar values.

I can understand why array- and hash-refs are dereferenced ...

Any elegant way to solve this? I also tried Test::Deep::cmp_deeply() but no success

will try Test::Differences now ...

use strict; use warnings; use Data::Dump qw/pp dd/; use Test::More; use Test::Deep; my ($pos1,$pos2)=("a","a"); diag \$pos1,", ",\$pos2; diag 0+\$pos1,", ",0+\$pos2; diag pp \$pos1,\$pos2; is_deeply( \$pos1, \$pos2,"is_deeply"); #should fail cmp_deeply( \$pos1, \$pos2,"cmp_deeply"); #should fail done_testing;

C:/Perl_524/bin\perl.exe -w d:/exp/pm_is_deeply.pl ok 1 - is_deeply ok 2 - cmp_deeply # SCALAR(0xd286e8), SCALAR(0xd28d48) # 13797096, 13798728 # (\"a", \"a") 1..2

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re: Test scalar refs (not values) in deeply nested structure
by Corion (Patriarch) on Jul 23, 2020 at 19:50 UTC

    The Test::More documentation says for is_deeply:

    is_deeply() compares the dereferenced values of references, the references themselves (except for their type) are ignored.

    ... so I'm not sure what you expect.

    If you want to compare the identity of the references too, you will need to write your own comparison tool, but I guess that a simple shallow comparison already is enough for that case.

      unfortunately my data is far from being shallow.

      My pragmatic approach is to write a recursive diver which will replace the scalar values with the stringification of their refs.

      $$ref = "$ref"

      I'll feed this to is_deeply() then, seems to work so far.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        So you have a nested data structure, but you want only scalar refs to be compared for identity, while you want to compare everything else structurally?

        If that's not it, maybe show examples and counterexamples of what you want your comparison routine to do.

Re: Test scalar refs (not values) in deeply nested structure
by syphilis (Archbishop) on Jul 24, 2020 at 03:51 UTC
    Hi Rolf,

    So ... you have:
    my ($pos1,$pos2)=("a","a");
    and you want a test that will report that \$pos1 and \$pos2 are "different".
    I think a simple cmp_ok(\$pos1, 'eq', \$pos2, "should fail"); will fail.
    The bit I haven't quite grasped is the circumstances under which \$pos1 and \$pos2 should be considered the same.
    What values do you assign to $pos1 and $pos2 such that this test should report that \$pos1 and \$pos2 are "the same" ?

    Cheers,
    Rob
      >The bit I haven't quite grasped is the circumstances under which \$pos1 and \$pos2 should be considered the same.

      I am also confused since your example is not nested at all, i.e., I don't think the scalar reference itself is considered nested since you're pointing to two different memory structures (addresses). Do you have an actual nested data structure, LanX?

      > The bit I haven't quite grasped is the circumstances under which \$pos1 and \$pos2 should be considered the same.

      Never, it's a false positive.

      (Or to be more precise only if both are aliases, hence \$pos1 == \$pos2 , but which can't happen in my use case )

      They are not nested in the OP because it's the easiest possible demo.

      See here Re: Test scalar refs (not values) in deeply nested structure (workaround) for more test cases.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

Re: Test scalar refs (not values) in deeply nested structure (workaround)
by LanX (Saint) on Jul 23, 2020 at 20:29 UTC
    FWIW: Here my workaround for the afterworld
    use strict; use warnings; use Test::More; my ($pos1,$pos2)=("a","a"); # *** Those should pass suite(\$pos1,\$pos1); # *** Those should fail suite(\$pos1,\$pos2); done_testing; # --- my tests for various scalar refs sub suite { my ($ref1,$ref2) = @_; is_deeply( scr($ref1), scr($ref2), "is_deeply"); is_deeply( scr([$ref1]), scr([$ref2]), "is_deeply ARRAY"); is_deeply( scr({t=> $ref1}), scr({t=>$ref2}), "is_deeply HASH"); is_deeply( scr({t => [$ref1]}), scr({t => [$ref2]}), "is_deeply HoA"); is_deeply( scr({t => [$ref1,$ref1], t2 => [$ref1]}), scr({t => [$ref2,$ref2], t2 => [$ref2]}), "is_deeply HoA multiple refs"); } # --- stringify_scalar_refs sub scr { my ($ref) = @_; my $reftype = ref $ref; if( $reftype eq 'SCALAR') { $$ref = "$ref"; } elsif ( $reftype eq 'ARRAY') { for my $el (@$ref) { scr($el); } } elsif ( $reftype eq 'HASH') { while (my ($key,$val) = each %$ref ){ scr($val); } } else { ... # dunno yet } return $ref }
    -*- mode: compilation; default-directory: "d:/exp/" -*- Compilation started at Thu Jul 23 22:28:14 C:/Perl_524/bin\perl.exe -w d:/exp/pm_is_deeply.pl ok 1 - is_deeply ok 2 - is_deeply ARRAY ok 3 - is_deeply HASH ok 4 - is_deeply HoA ok 5 - is_deeply HoA multiple refs not ok 6 - is_deeply # Failed test 'is_deeply' # at d:/exp/pm_is_deeply.pl line 28. # Structures begin differing at: # ${ $got} = 'SCALAR(0x26589e8)' # ${$expected} = 'SCALAR(0x2650480)' not ok 7 - is_deeply ARRAY # Failed test 'is_deeply ARRAY' # at d:/exp/pm_is_deeply.pl line 32. # Structures begin differing at: # ${ $got->[0]} = 'SCALAR(0x26589e8)' # ${$expected->[0]} = 'SCALAR(0x2650480)' not ok 8 - is_deeply HASH # Failed test 'is_deeply HASH' # at d:/exp/pm_is_deeply.pl line 36. # Structures begin differing at: # ${ $got->{t}} = 'SCALAR(0x26589e8)' # ${$expected->{t}} = 'SCALAR(0x2650480)' not ok 9 - is_deeply HoA # Failed test 'is_deeply HoA' # at d:/exp/pm_is_deeply.pl line 40. # Structures begin differing at: # ${ $got->{t}[0]} = 'SCALAR(0x26589e8)' # ${$expected->{t}[0]} = 'SCALAR(0x2650480)' not ok 10 - is_deeply HoA multiple refs # Failed test 'is_deeply HoA multiple refs' # at d:/exp/pm_is_deeply.pl line 44. # Structures begin differing at: # ${ $got->{t2}[0]} = 'SCALAR(0x26589e8)' # ${$expected->{t2}[0]} = 'SCALAR(0x2650480)' 1..10 # Looks like you failed 5 tests of 10. Compilation exited abnormally with code 5 at Thu Jul 23 22:28:14

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery