Pablo Marin-Garcia Pablo Marin-Garcia - 2 months ago 14
Perl Question

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?

Answer

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.