Test for expected warnings

There are many modules with function that would give a warning in certain situations. This can be a deprecation warning,
when the function is left in to provide backward compability, but you actually want to remove it in the future.

Or, it can be warning of improper input values if for some reason you do not want to throw an exception.

In either case, the warning must stay there as changes are made to the code-base. That warning is now part of API of the module
and as such we should write a test that will make sure the warning isn't removed by accident or by someone who
likes to eliminate warnings....

If we run it using prove -l t/fibonacci_negative.t we get the following output:

1..1
Given number must be > 0 at lib/MyTools.pm line 19.
ok 1 - fibonacci on -1 returns 0

As checked by the is function, the returned values was correct, but the warning was printed on the output of the script.

It is bad because an observer will notice the warning and start complaining that the test found some problems, and it is bad
because if the code in the module changes and the warning stops appearing no one will notice.

We need to capture the warning and check if the captured value is the expected string.

We could capture the warning ourself using the SIG{__WARN__}, but it just as we build a testing module
based on Test::Builder, there is also a testing module called Test::Warn
that provides exactly this service.

use strict;
use warnings;
use Test::More tests => 2;
use Test::Warn;
use MyTools;
my $result;
warning_is {$result = fibonacci(-1)} "Given number must be > 0",
'warning when called with -1';
is($result, 0, 'fibonacci on -1 returns 0');

After importing the Test::Warn module it provides a number of testing function
with a slightly strange syntax.

The function names are warning_is to check if the given piece of code generates exactly one warning and if we would like to compare
the text of the warning exactly.

warnings_are expects a list of warnings and succeeds if the actual warnings came the exact same order and had the exact same text.

warning_like expects one warning, but instead of comparing for equality it checks if the warning matches a given regular expression.

They are just like the is and like functions of Test::More, but of course,
they also capture a warning.

There are a few others, but I think these can give you the idea.

Now for the syntax:

Each one of these receives a block in curly braces {}, that is the code-block that will be executed, and then immediately
after it, without even a separating comma , we put the expected value(s). In case of warning_is this is a single string.
In case of warnings_are, this is a reference to an array of strings. In case of warning_like this is a regular
expression created using qr.

After that, separated by a comma, we can add the optional "name" parameter of this test unit.

As we also still would like to compare the value returned by the fibonacci function to some expected value, we need to assign it
to a variable, but because the fibonacci call is now in a block, we need to declare that variable outside of the block,
in order to have it after the warning_is function has finished. That's why we declare $result before the
warning_is call.

Running the test script now prove -l t/fibonacci_negative.t will yield the following output: