* Fixes
- Ensure failing on_connect* / on_disconnect* are dealt with properly,
notably on_connect* failures now properly abort the entire connect
+ - Make sure exception objects stringifying to '' are properly handled
+ and warned about (GH#15)
- Fix corner case of stringify-only overloaded objects being used in
create()/populate()
- Fix several corner cases with Many2Many over custom relationships
die $suberror
}
}
+ elsif (
+ # a ref evaluating to '' is definitively a "null object"
+ ( not $not_blank )
+ and
+ length( my $class = ref $e )
+ ) {
+ carp_unique( sprintf(
+ "Objects of external exception class '%s' stringify to '' (the "
+ . 'empty string), implementing the so called null-object-pattern. '
+ . 'Given Perl\'s "globally cooperative" exception handling using this '
+ . 'class of exceptions is extremely dangerous, as it may (and often '
+ . 'does) result in silent discarding of errors. DBIx::Class tries to '
+ . 'work around this as much as possible, but other parts of your '
+ . 'software stack may not be even aware of the problem. Please submit '
+ . 'a bugreport against the distribution containing %s.',
+
+ ($class) x 2,
+ ));
+
+ $not_blank = 1;
+ }
return $not_blank;
}
use Test::More;
use Test::Exception;
+use Test::Warn;
use lib qw(t/lib);
'Exception-arrayref contents preserved',
);
+for my $ap (qw(
+ DBICTest::AntiPattern::TrueZeroLen
+ DBICTest::AntiPattern::NullObject
+)) {
+ eval "require $ap";
+
+ warnings_like {
+ eval {
+ $schema->txn_do (sub { die $ap->new });
+ };
+
+ isa_ok $@, $ap;
+ } qr/\QObjects of external exception class '$ap' stringify to '' (the empty string)/,
+ 'Proper warning on encountered antipattern';
+}
+
done_testing;
throws_ok { $schema->storage->throw_exception('floob') }
qr/DBICTest::Exception is handling this: floob/;
+# test antipatterns
+for my $ap (qw(
+ DBICTest::AntiPattern::TrueZeroLen
+ DBICTest::AntiPattern::NullObject
+)) {
+ eval "require $ap";
+ my $exp_warn = qr/\QObjects of external exception class '$ap' stringify to '' (the empty string)/;
+
+ # make sure an exception_action can replace $@ with an antipattern
+ $schema->exception_action(sub { die $ap->new });
+ warnings_like {
+ eval { $throw->() };
+ isa_ok $@, $ap;
+ } $exp_warn, 'proper warning on antipattern encountered within exception_action';
+
+ # and make sure that the retrhow works
+ $schema->exception_action(sub { die @_ });
+ warnings_like {
+ eval {
+ $schema->txn_do (sub { die $ap->new });
+ };
+
+ isa_ok $@, $ap;
+ } $exp_warn, 'Proper warning on encountered antipattern';
+}
+
done_testing;
--- /dev/null
+package DBICTest::AntiPattern::NullObject;
+
+use warnings;
+use strict;
+
+use overload
+ 'bool' => sub { 0 },
+ '""' => sub { '' },
+ '0+' => sub { 0 },
+ fallback => 1
+;
+
+our $null = bless {}, __PACKAGE__;
+sub AUTOLOAD { $null }
+
+1;
--- /dev/null
+package DBICTest::AntiPattern::TrueZeroLen;
+
+use warnings;
+use strict;
+
+use overload
+ 'bool' => sub { 1 },
+ '""' => sub { '' },
+ fallback => 1
+;
+
+sub new { bless {}, shift }
+
+1;