On 1/11/16 4:53 PM, Chad Granum wrote: > Test::More/Test::Builder work VERY hard to ensure nothing inside them alters > $! or $@. This is for > thing like this: > > ok(do_something_scary()); > is($!, 0, "expected $! val"); > is($@, undef, '$@ not changed'); > > Without Test::More/Builder being careful to support this, the second 2 > assertions could fail because > something inside ok() modifies $! or $@.
If your test functions modify the really common parts of your global environment then it becomes very difficult to test them... and testing error reporting is a very common thing you'd want to do! Kent already pointed out why changing this makes testing $! and $@ very, very awkward. Let's see that again. my ( $error, $exception ); ok(do { local $@; local $!; my $ret = do_something_scary()); ( $error, $exception ) = ($!, $@); $ret }); is($error, 0, "expected $! val"); is($exception, undef, '$@ not changed); Gross. I don't know how many times I've written code like this. I hate it. I always encapsulate it somehow. And when a library doesn't have good global discipline it makes it even harder for me to have good global discipline. We tell the users that $! and $@ are only safe per function call. Then we encourage them all over the docs and interface to pass function return values directly into test functions. Then we tell them they should be testing their error cases... but to do safely requires gross scaffolding. That's not fair to the user. The result will be that people won't test their error conditions, library quality will drop, and you'll waste a lot of time on a bug that should have been tested. The argument that $! is only reliable per function call, that's a lowest common denominator thinking. One of the fundamental design principles of Test::Builder was that it had to be the GREATEST common denominator! I don't write libraries to the lowest common denominator. I write libraries that raise the bar and encourage others to do so as well. Perl 5's error handling is bad, but that doesn't mean my library's error handling also has to be bad. As library authors we've been spending decades working around Perl 5's bad parts. We know how to do it better. This is extraordinarily important for a language's testing library: if you can't test it (or it's gross and annoying) then it won't happen. If you want to see better global discipline in Perl libraries, then the testing library has to start first, because everything will use it. Test libraries are first and foremost about the user. They encourage the user to more and better testing! Implementation effort is a much, much lesser concern. And all the positives reasons below not to do it are implementation reasons. There are no positives for the Test2 user. > *Reasons for dropping this promise from Test2:* > > * Simplifies code > * $! and $@ are altered by many many things, adding { local ... } around > all of them is a pain > * Sometimes internals you don't expect to set $! will > * Perl itself documents that you cannot depend on $! and $@ being unchanged > past the immediate > line after you set it. > * Test::Builder will continue to protect $! and $@, so nothing will break > * Test2 is new, nothing depends on it preserving these The one below is the only reason that talks about making Test2 better for the user. > *Reasons not to drop it:* > > * It is helpful to people who might not realize $! and $@ are often altered > unexpectedly. > > I am asking for input in case I missed any reasons/arguments for either side. > In either case > backwards compatibility will be preserved. > > -Chad > >