Pablo Marin-Garcia
Pablo Marin-Garcia

Reputation: 4251

Can I use smart matching, ~~, in Test::More's cmp_ok?

I am testing a function that returns an array. The array could be different depending on the environment but it will always have at least one constant value (the one that I want to test).

As I am using Perl 5.12, I can use the smartmatch operator to find if the element is in the array:

ok($known_value ~~ @returned, 'testing method abc')

But I like the enhanced output of is and like with the "found" and "expected" parts. So I tried this:

cmp_ok($known_value, '~~', @returned, 'testing method abc')

This does not work because it seems that cmp_ok expects a scalar in both parts of the comparison:

not ok 1 - testing method abc
#   Failed test 'testing method abc'
#   at abc.t line 53.
#     'stable_value'
#         ~~
#     '2'

The array in the "expected" slot is evaluated in scalar context and converted to 2.

I can work around this with a hack using like and stringifying the array, but having a test where you can use the smartmatch operator as a comparison method (like when) would be nice. Is there a way to do this with Test::More or some other module?

At the moment I am using:

ok($known_value ~~ @returned, 'testing method abc')
  or diag (
      "ERROR:\n".
      "Found: ". Dumper @returned."\n".
      "Expected at least one element equal to '$known_value'"
  )

Is this the best that I can do?

Upvotes: 1

Views: 548

Answers (3)

rafl
rafl

Reputation: 12341

Test::Deep provides many utilities for testing parts of (possibly very deeply nested) structures, and also produces quite useful diagnostics in case of failures. I believe one of its bag functions could do the job for you.

use Test::Deep;

my @foo = ('bar', 'baz', 'moo');

cmp_deeply(
    \@foo,
    superbagof('baz'),
    '@foo contains at least one "baz"',
);

This way you can, if it ever turns out to be necessary, do much more complicated assertions than what smartmatching would allow without having to break things down into much smaller chunks, and will also continue to function on old perls.

Upvotes: 3

Michael Carman
Michael Carman

Reputation: 30831

You can't use @returned because of how Perl passes arguments to subroutines. (Arrays are flattened into the argument list and lose their identity.) Pass an array reference instead:

cmp_ok($known_value, '~~', \@returned, 'testing method abc')

The smart match operator is smart enough to do the right thing. From perlsyn:

Note that the smart match implicitly dereferences any non-blessed hash or array ref, so the "Hash" and "Array" entries apply in those cases.

Upvotes: 10

daxim
daxim

Reputation: 39158

Automatic dumping with Test::More, Test::Most:

use Test::More 0.82; diag explain \@returned;

use Test::Most 0.21; show \@returned;

Upvotes: 2

Related Questions