Search code examples
unit-testingperlwarnings

"Prototype mismatch" warning with Test2::Mock


Running the following code:

#!/usr/bin/env perl

use 5.038;

use Test2::Mock;
use Time::HiRes;

my($mock) = Test2::Mock->new(
    class => 'Time::HiRes',
    override => [
        gettimeofday => sub { return 1; },
    ]
);

my($foo) = Time::HiRes::gettimeofday;
say $foo;

results in this output:

Prototype mismatch: sub Time::HiRes::gettimeofday () vs none at /opt/perl/lib/site_perl/5.38.0/Test2/Mock.pm line 434.
1
Prototype mismatch: sub Time::HiRes::gettimeofday: none vs () at /opt/perl/lib/site_perl/5.38.0/Test2/Mock.pm line 452.

I don't know how to get rid of the prototype mismatch warnings. I've tried a number of things with no effect (some of them out of desperation, not because I thought they would work):

  • adding a prototype to the anon sub
gettimeofday => sub () { return 1; },
  • defined a named sub with a prototype in a BEGIN block & used it instead
BEGIN {
    sub gtod () { return 1; }
}

my($mock) = Test2::Mock->new(
    class => 'Time::HiRes',
    override => [
        gettimeofday => \&gtod,
    ]
);
  • using Time::Hires before Test2::Mock
  • imported gettimeofday into main and overrode that, in combination with all of the above, e.g.:
use Test2::Mock;
use Time::HiRes qw(gettimeofday);

my($mock) = Test2::Mock->new(
    class => 'main',
    override => [
        gettimeofday => sub () { return 1; },
    ]
);

my($foo) = gettimeofday;
say $foo;
  • wrapped it in a no warnings 'prototype' block
{
    no warnings 'prototype';

    my($mock) = Test2::Mock->new(
        class => 'main',
        override => [
            gettimeofday => sub () { return 1; },
        ]
    );
}

Nothing made any difference.

My code works, but there's a warning for a reason, and I'd really like to deal with it in the proper manner. The best I've come up with Googling for an answer is to suppress the message by modifying $SIG{__WARN__}, which just seems like a bad idea, if there are other options.

Note: I am aware of Test::Mock::Time, Test::MockTime, and Test::MockTime::HiRes -- they don't do what I need them to do, so I thought I'd roll my own. Also, I've looked at Sub::Prototype but haven't tried it, yet, as it's not a core module and I'd rather not go there unless there's no other choice (at which point I may modify $SIG{__WARN__} instead.


Solution

  • When the signatures feature is enabled, () is not a prototype but a signature.

    You are enabling this feature using use 5.038;.

    The fix is to use

    sub :prototype() { return 1; }
    

    Alternatively, you could use the classic prototype syntax (sub() { return 1; }) in a section of code where the signatures feature is disabled (e.g. using no feature qw( signatures );).