Sanity check erroneous invocations
Peter Rabbitson [Thu, 4 Jul 2013 06:45:13 +0000 (08:45 +0200)]
Changes
lib/Try/Tiny.pm
t/erroneous_usage.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index fd0aac1..0b1704a 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,6 +2,8 @@
   - fix tests failing on 5.6.x due to differing DESTROY semantics
   - excise superfluous local($@) call - 7% speedup
   - fix (fsvo) broken URLs (RT#55659)
+  - proper exception on erroneous usage of bare catch/finally (RT#81070)
+  - proper exception on erroneous use of multiple catch{} blocks
 
 0.12
   - doc fixes
index 5aaeae2..3056c4c 100644 (file)
@@ -33,6 +33,8 @@ sub try (&;@) {
     my $ref = ref($code_ref);
 
     if ( $ref eq 'Try::Tiny::Catch' ) {
+      croak 'A try() may not be followed by multiple catch() blocks'
+        if $catch;
       $catch = ${$code_ref};
     } elsif ( $ref eq 'Try::Tiny::Finally' ) {
       push @finally, ${$code_ref};
@@ -101,6 +103,8 @@ sub try (&;@) {
 sub catch (&;@) {
   my ( $block, @rest ) = @_;
 
+  croak 'Useless bare catch()' unless defined wantarray;
+
   return (
     bless(\$block, 'Try::Tiny::Catch'),
     @rest,
@@ -110,6 +114,8 @@ sub catch (&;@) {
 sub finally (&;@) {
   my ( $block, @rest ) = @_;
 
+  croak 'Useless bare finally()' unless defined wantarray;
+
   return (
     bless(\$block, 'Try::Tiny::Finally'),
     @rest,
diff --git a/t/erroneous_usage.t b/t/erroneous_usage.t
new file mode 100644 (file)
index 0000000..c447c61
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 5;
+use Try::Tiny;
+
+sub _eval {
+  local $@;
+  local $Test::Builder::Level = $Test::Builder::Level + 2;
+  return ( scalar(eval { $_[0]->(); 1 }), $@ );
+}
+
+sub throws_ok (&$$) {
+  my ( $code, $regex, $desc ) = @_;
+  local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+  my ( $ok, $error ) = _eval($code);
+
+  if ( $ok ) {
+    fail($desc);
+  } else {
+    like($error || '', $regex, $desc );
+  }
+}
+
+throws_ok {
+  try { 1 }; catch { 2 };
+} qr/\QUseless bare catch()/, 'Bare catch() detected';
+
+throws_ok {
+  try { 1 }; finally { 2 };
+} qr/\QUseless bare finally()/, 'Bare finally() detected';
+
+throws_ok {
+  try { 1 }; catch { 2 } finally { 2 };
+} qr/\QUseless bare catch()/, 'Bare catch()/finally() detected';
+
+throws_ok {
+  try { 1 }; finally { 2 } catch { 2 };
+} qr/\QUseless bare finally()/, 'Bare finally()/catch() detected';
+
+
+throws_ok {
+  try { 1 } catch { 2 } catch { 3 } finally { 4 } finally { 5 }
+} qr/\QA try() may not be followed by multiple catch() blocks/, 'Multi-catch detected';
+