From: Peter Rabbitson <ribasushi@cpan.org>
Date: Thu, 4 Jul 2013 06:45:13 +0000 (+0200)
Subject: Sanity check erroneous invocations
X-Git-Tag: Try-Tiny-0.13~6^2~5
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=9d0e04660c421c7e2be49ff45bca0ff8599be7ce;p=p5sagit%2FTry-Tiny.git

Sanity check erroneous invocations
---

diff --git a/Changes b/Changes
index fd0aac1..0b1704a 100644
--- 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
diff --git a/lib/Try/Tiny.pm b/lib/Try/Tiny.pm
index 5aaeae2..3056c4c 100644
--- a/lib/Try/Tiny.pm
+++ b/lib/Try/Tiny.pm
@@ -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
index 0000000..c447c61
--- /dev/null
+++ b/t/erroneous_usage.t
@@ -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';
+