Workaround for double-call of destructors (based on 3d56e026 and e1d9e578)
[dbsrgits/DBIx-Class.git] / t / lib / DBICTest / Util.pm
index a6c8dfd..985e072 100644 (file)
@@ -17,31 +17,13 @@ BEGIN {
   }
 }
 
-use Module::Runtime 'module_notional_filename';
-BEGIN {
-  for my $mod (qw( SQL::Abstract::Test SQL::Abstract )) {
-    if ( $INC{ module_notional_filename($mod) } ) {
-      # FIXME this does not seem to work in BEGIN - why?!
-      #require Carp;
-      #$Carp::Internal{ (__PACKAGE__) }++;
-      #Carp::croak( __PACKAGE__ . " must be loaded before $mod" );
-
-      my ($fr, @frame) = 1;
-      while (@frame = caller($fr++)) {
-        last if $frame[1] !~ m|^t/lib/DBICTest|;
-      }
-
-      die __PACKAGE__ . " must be loaded before $mod (or modules using $mod) at $frame[1] line $frame[2]\n";
-    }
-  }
-}
-
 use Config;
 use Carp 'confess';
 use Scalar::Util qw(blessed refaddr);
+use DBIx::Class::_Util;
 
 use base 'Exporter';
-our @EXPORT_OK = qw(local_umask stacktrace check_customcond_args);
+our @EXPORT_OK = qw(local_umask stacktrace check_customcond_args visit_namespaces);
 
 sub local_umask {
   return unless defined $Config{d_umask};
@@ -57,6 +39,8 @@ sub local_umask {
 {
   package DBICTest::Util::UmaskGuard;
   sub DESTROY {
+    &DBIx::Class::_Util::detected_reinvoked_destructor;
+
     local ($@, $!);
     eval { defined (umask ${$_[0]}) or die };
     warn ( "Unable to reset old umask ${$_[0]}: " . ($!||'Unknown error') )
@@ -99,30 +83,60 @@ sub check_customcond_args ($) {
   confess "Passed resultsource has no record of the supplied rel_name - likely wrong \$rsrc"
     unless ref $args->{self_resultsource}->relationship_info($args->{rel_name});
 
-  my $rowobj_cnt = 0;
+  my $struct_cnt = 0;
 
-  if (defined $args->{self_resultobj} or defined $args->{self_rowobj} ) {
-    $rowobj_cnt++;
-    for (qw(self_resultobj self_rowobj)) {
+  if (defined $args->{self_result_object} or defined $args->{self_rowobj} ) {
+    $struct_cnt++;
+    for (qw(self_result_object self_rowobj)) {
       confess "Custom condition argument '$_' must be a result instance"
         unless defined blessed $args->{$_} and $args->{$_}->isa('DBIx::Class::Row');
     }
 
-    confess "Current and legacy self_resultobj arguments do not match"
-      if refaddr($args->{self_resultobj}) != refaddr($args->{self_rowobj});
+    confess "Current and legacy self_result_object arguments do not match"
+      if refaddr($args->{self_result_object}) != refaddr($args->{self_rowobj});
   }
 
-  if (defined $args->{foreign_resultobj}) {
-    $rowobj_cnt++;
+  if (defined $args->{foreign_values}) {
+    $struct_cnt++;
 
-    confess "Custom condition argument 'foreign_resultobj' must be a result instance"
-      unless defined blessed $args->{foreign_resultobj} and $args->{foreign_resultobj}->isa('DBIx::Class::Row');
+    confess "Custom condition argument 'foreign_values' must be a hash reference"
+      unless ref $args->{foreign_values} eq 'HASH';
   }
 
-  confess "Result objects supplied on both ends of a relationship"
-    if $rowobj_cnt == 2;
+  confess "Data structures supplied on both ends of a relationship"
+    if $struct_cnt == 2;
 
   $args;
 }
 
+sub visit_namespaces {
+  my $args = { (ref $_[0]) ? %{$_[0]} : @_ };
+
+  my $visited_count = 1;
+
+  # A package and a namespace are subtly different things
+  $args->{package} ||= 'main';
+  $args->{package} = 'main' if $args->{package} =~ /^ :: (?: main )? $/x;
+  $args->{package} =~ s/^:://;
+
+  if ( $args->{action}->($args->{package}) ) {
+    my $ns =
+      ( ($args->{package} eq 'main') ? '' :  $args->{package} )
+        .
+      '::'
+    ;
+
+    $visited_count += visit_namespaces( %$args, package => $_ ) for
+      grep
+        # this happens sometimes on %:: traversal
+        { $_ ne '::main' }
+        map
+          { $_ =~ /^(.+?)::$/ ? "$ns$1" : () }
+          do { no strict 'refs'; keys %$ns }
+    ;
+  }
+
+  return $visited_count;
+}
+
 1;