X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xt%2Fextra%2Finternals%2Fattributes.t;fp=xt%2Fextra%2Finternals%2Fattributes.t;h=0000000000000000000000000000000000000000;hb=92705f7f05161f7dba36d9b09dc6e893af7b2773;hp=6c1998d65f42a933bc11819a0959d2fd5ffcc846;hpb=953f8eb062bd84ffcb5b59d9a0d27d1db55f3927;p=dbsrgits%2FDBIx-Class.git diff --git a/xt/extra/internals/attributes.t b/xt/extra/internals/attributes.t deleted file mode 100644 index 6c1998d..0000000 --- a/xt/extra/internals/attributes.t +++ /dev/null @@ -1,583 +0,0 @@ -BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) } - -use strict; -use warnings; -no warnings 'once'; - -use Config; -my $skip_threads; -BEGIN { - if( ! $Config{useithreads} ) { - $skip_threads = 'your perl does not support ithreads'; - } - elsif( "$]" < 5.008005 ) { - $skip_threads = 'DBIC does not actively support threads before perl 5.8.5'; - } - elsif( $INC{'Devel/Cover.pm'} ) { - $skip_threads = 'Devel::Cover does not work with ithreads yet'; - } - - unless( $skip_threads ) { - require threads; - threads->import; - } -} - -use Test::More; -use Test::Exception; -use DBIx::Class::_Util qw( quote_sub describe_class_methods serialize refdesc ); -use List::Util 'shuffle'; -use Errno (); - -use DBICTest; - -my $pkg_gen_history = {}; - -{ package UEBERVERSAL; sub ueber {} } -@UNIVERSAL::ISA = "UEBERVERSAL"; -sub UNIVERSAL::uni { "unistuff" } - -sub grab_pkg_gen ($) { - push @{ $pkg_gen_history->{$_[0]} }, [ - DBIx::Class::_Util::get_real_pkg_gen($_[0]), - 'line ' . ( (caller(0))[2] ), - ]; -} - -@DBICTest::AttrLegacy::ISA = 'DBIx::Class'; -sub DBICTest::AttrLegacy::VALID_DBIC_CODE_ATTRIBUTE { 1 } - -grab_pkg_gen("DBICTest::AttrLegacy"); - -my $var = \42; -my $s = quote_sub( - 'DBICTest::AttrLegacy::attr', - '$v', - { '$v' => $var }, - { - attributes => [qw( ResultSet DBIC_random_attr )], - package => 'DBICTest::AttrLegacy', - }, -); - -grab_pkg_gen("DBICTest::AttrLegacy"); - -is $s, \&DBICTest::AttrLegacy::attr, 'Same cref installed'; - -is DBICTest::AttrLegacy::attr(), 42, 'Sub properly installed and callable'; - -is_deeply - [ sort( attributes::get( $s ) ) ], - [qw( DBIC_random_attr ResultSet )], - 'Attribute installed', -; - -{ - package DBICTest::SomeGrandParentClass; - use base 'DBIx::Class::MethodAttributes'; - sub VALID_DBIC_CODE_ATTRIBUTE { shift->next::method(@_) }; -} -{ - package DBICTest::SomeParentClass; - use base qw(DBICTest::SomeGrandParentClass); -} -{ - package DBICTest::AnotherParentClass; - use base 'DBIx::Class::MethodAttributes'; - sub VALID_DBIC_CODE_ATTRIBUTE { $_[1] =~ /DBIC_attr/ }; -} - -{ - package DBICTest::AttrTest; - - @DBICTest::AttrTest::ISA = qw( DBICTest::SomeParentClass DBICTest::AnotherParentClass ); - use mro 'c3'; - - # pathological case - but can (and sadly does) happen - *VALID_DBIC_CODE_ATTRIBUTE = \&DBICTest::SomeGrandParentClass::VALID_DBIC_CODE_ATTRIBUTE; - - ::grab_pkg_gen("DBICTest::AttrTest"); - - eval <<'EOS' or die $@; - sub attr :lvalue :method :DBIC_attr1 { $$var} - 1; -EOS - - ::grab_pkg_gen("DBICTest::AttrTest"); - - ::throws_ok { - attributes->import( - 'DBICTest::AttrTest', - DBICTest::AttrTest->can('attr'), - 'DBIC_unknownattr', - ); - } qr/DBIC-specific attribute 'DBIC_unknownattr' did not pass validation/; -} - -is_deeply - [ sort( attributes::get( DBICTest::AttrTest->can("attr") )) ], - [qw( DBIC_attr1 lvalue method )], - 'Attribute installed', -; - -ok( - ! DBICTest::AttrTest->can('__attr_cache'), - 'Inherited classdata never created on core attrs' -); - -is_deeply( - DBICTest::AttrTest->_attr_cache, - {}, - 'Cache never instantiated on core attrs' -); - -sub add_more_attrs { - - # Test that secondary attribute application works - attributes->import( - 'DBICTest::AttrLegacy', - DBICTest::AttrLegacy->can('attr'), - 'SomethingNobodyUses', - ); - - # and that double-application also works - attributes->import( - 'DBICTest::AttrLegacy', - DBICTest::AttrLegacy->can('attr'), - 'SomethingNobodyUses', - ); - - grab_pkg_gen("DBICTest::AttrLegacy"); - - is_deeply - [ sort( attributes::get( $s ) )], - [ qw( DBIC_random_attr ResultSet SomethingNobodyUses ) ], - 'Secondary attributes installed', - ; - - is_deeply ( - DBICTest::AttrLegacy->_attr_cache->{$s}, - [ qw( ResultSet SomethingNobodyUses ) ], - 'Attributes visible in legacy DBIC attribute API', - ); - - # Test that secondary attribute application works - attributes->import( - 'DBICTest::AttrTest', - DBICTest::AttrTest->can('attr'), - 'DBIC_attr2', - ); - - grab_pkg_gen("DBICTest::AttrTest"); - - # and that double-application also works - attributes->import( - 'DBICTest::AttrTest', - DBICTest::AttrTest->can('attr'), - 'DBIC_attr2', - 'DBIC_attr3', - ); - - grab_pkg_gen("DBICTest::AttrTest"); - - is_deeply - [ sort( attributes::get( DBICTest::AttrTest->can("attr") )) ], - [qw( DBIC_attr1 DBIC_attr2 DBIC_attr3 lvalue method )], - 'DBIC-specific attribute installed', - ; - - ok( - ! DBICTest::AttrTest->can('__attr_cache'), - 'Inherited classdata never created on core+DBIC-specific attrs' - ); - - is_deeply( - DBICTest::AttrTest->_attr_cache, - {}, - 'Legacy DBIC attribute cache never instantiated on core+DBIC-specific attrs' - ); - - # no point dragging in threads::shared, just do the check here - for my $class ( keys %$pkg_gen_history ) { - my $stack = $pkg_gen_history->{$class}; - - for my $i ( 1 .. $#$stack ) { - cmp_ok( - $stack->[$i-1][0], - ( DBIx::Class::_ENV_::OLD_MRO ? '!=' : '<' ), - $stack->[$i][0], - "pkg_gen for $class changed from $stack->[$i-1][1] to $stack->[$i][1]" - ); - } - } - - my $cnt; - # check that class description is stable, and changes when needed - # - # FIXME - this list used to contain 'main', but that started failing as - # of the commit introducing this line with bizarre "unstable gen" errors - # Punting for the time being - will fix at some point in the future - # - for my $class (qw( - DBICTest::AttrTest - DBICTest::AttrLegacy - DBIx::Class - )) { - my $desc = describe_class_methods($class); - - is_deeply( - describe_class_methods($class), - $desc, - "describe_class_methods result is stable over '$class' (pass $_)" - ) for (1,2,3); - - my $desc2 = do { - no strict 'refs'; - - $cnt++; - - eval "sub UEBERVERSAL::some_unimethod_$cnt {}; 1" or die $@; - - my $rv = describe_class_methods($class); - - delete ${"UEBERVERSAL::"}{"some_unimethod_$cnt"}; - - $rv - }; - - delete $_->{cumulative_gen} for $desc, $desc2; - ok( - serialize( $desc ) - ne - serialize( $desc2 ), - "touching UNIVERSAL changed '$class' method availability" - ); - } - - my $bottom_most_V_D_C_A = refdesc( - describe_class_methods("DBIx::Class::MethodAttributes") - ->{methods} - ->{VALID_DBIC_CODE_ATTRIBUTE} - ->[0] - ); - - for my $class ( shuffle( qw( - DBICTest::AttrTest - DBICTest::AttrLegacy - DBICTest::SomeGrandParentClass - DBIx::Class::Schema - DBIx::Class::ResultSet - DBICTest::Schema::Track - ))) { - my $desc = describe_class_methods($class); - - is ( - refdesc( $desc->{methods}{VALID_DBIC_CODE_ATTRIBUTE}[-1] ), - $bottom_most_V_D_C_A, - "Same physical structure returned for last VALID_DBIC_CODE_ATTRIBUTE via class $class" - ); - - is ( - refdesc( $desc->{methods_with_supers}{VALID_DBIC_CODE_ATTRIBUTE}[-1] ), - $bottom_most_V_D_C_A, - "Same physical structure returned for bottom-most SUPER of VALID_DBIC_CODE_ATTRIBUTE via class $class" - ) if $desc->{methods_with_supers}{VALID_DBIC_CODE_ATTRIBUTE}; - } - - # check that describe_class_methods returns the right stuff - # ( on the simpler class ) - my $expected_AttrTest_linear_ISA = [qw( - DBICTest::SomeParentClass - DBICTest::SomeGrandParentClass - DBICTest::AnotherParentClass - DBIx::Class::MethodAttributes - )]; - - my $expected_AttrTest_full_ISA = { map { $_ => 1 } ( - qw( UEBERVERSAL UNIVERSAL DBICTest::AttrTest ), - @$expected_AttrTest_linear_ISA, - )}; - - my $expected_desc = { - class => "DBICTest::AttrTest", - - # sum and/or is_deeply are buggy on old List::Util/Test::More - # do the sum by hand ourselves to be sure - cumulative_gen => do { - require Math::BigInt; - my $gen = Math::BigInt->new(0); - - $gen += DBIx::Class::_Util::get_real_pkg_gen($_) - for keys %$expected_AttrTest_full_ISA; - - $gen; - }, - mro => { - type => 'c3', - is_c3 => 1, - }, - linear_isa => $expected_AttrTest_linear_ISA, - isa => $expected_AttrTest_full_ISA, - methods => { - FETCH_CODE_ATTRIBUTES => [ - { - attributes => {}, - name => "FETCH_CODE_ATTRIBUTES", - via_class => "DBIx::Class::MethodAttributes" - }, - ], - MODIFY_CODE_ATTRIBUTES => [ - { - attributes => {}, - name => "MODIFY_CODE_ATTRIBUTES", - via_class => "DBIx::Class::MethodAttributes" - }, - ], - VALID_DBIC_CODE_ATTRIBUTE => ( my $V_D_C_A_stack = [ - { - attributes => {}, - name => 'VALID_DBIC_CODE_ATTRIBUTE', - via_class => 'DBICTest::AttrTest' - }, - { - attributes => {}, - name => "VALID_DBIC_CODE_ATTRIBUTE", - via_class => "DBICTest::SomeGrandParentClass", - }, - { - attributes => {}, - name => "VALID_DBIC_CODE_ATTRIBUTE", - via_class => "DBICTest::AnotherParentClass" - }, - { - attributes => {}, - name => "VALID_DBIC_CODE_ATTRIBUTE", - via_class => "DBIx::Class::MethodAttributes" - }, - ]), - _attr_cache => [ - { - attributes => {}, - name => "_attr_cache", - via_class => "DBIx::Class::MethodAttributes" - }, - ], - attr => [ - { - attributes => { - DBIC_attr1 => 1, - DBIC_attr2 => 1, - DBIC_attr3 => 1, - lvalue => 1, - method => 1 - }, - name => "attr", - via_class => "DBICTest::AttrTest" - } - ], - ueber => [ - { - attributes => {}, - name => "ueber", - via_class => "UEBERVERSAL", - } - ], - uni => [ - { - attributes => {}, - name => "uni", - via_class => "UNIVERSAL", - } - ], - can => [ - { - attributes => {}, - name => "can", - via_class => "UNIVERSAL", - }, - ], - isa => [ - { - attributes => {}, - name => "isa", - via_class => "UNIVERSAL", - }, - ], - VERSION => [ - { - attributes => {}, - name => "VERSION", - via_class => "UNIVERSAL", - }, - ], - ( DBIx::Class::_ENV_::OLD_MRO ? () : ( - DOES => [{ - attributes => {}, - name => "DOES", - via_class => "UNIVERSAL", - }], - ) ), - }, - }; - - $expected_desc->{methods_with_supers}{VALID_DBIC_CODE_ATTRIBUTE} - = $V_D_C_A_stack; - - $expected_desc->{methods_defined_in_class}{VALID_DBIC_CODE_ATTRIBUTE} - = $V_D_C_A_stack->[0]; - - $expected_desc->{methods_defined_in_class}{attr} - = $expected_desc->{methods}{attr}[0]; - - is_deeply ( - describe_class_methods("DBICTest::AttrTest"), - $expected_desc, - 'describe_class_methods returns correct data', - ); - - # ensure that asking with a different MRO will not perturb the cache - my $cached_desc = serialize( - $DBIx::Class::_Util::__describe_class_query_cache->{"DBICTest::AttrTest|c3"} - ); - - # now try to ask for DFS explicitly, adjust our expectations - $expected_desc->{mro} = { type => 'dfs', is_c3 => 0 }; - - # due to DFS the last 2 entries of ISA and the VALID_DBIC_CODE_ATTRIBUTE - # sourcing-list will change places - splice @$_, -2, 2, @{$_}[-1, -2] - for $V_D_C_A_stack, $expected_AttrTest_linear_ISA; - - is_deeply ( - # work around taint, see TODO below - { - %{ describe_class_methods({ class => "DBICTest::AttrTest", use_mro => "dfs" }) }, - cumulative_gen => $expected_desc->{cumulative_gen}, - }, - $expected_desc, - 'describing with explicit mro returns correct data' - ); - - # FIXME: TODO does not work on new T::B under threads sigh - # https://github.com/Test-More/test-more/issues/683 - unless( - ! DBIx::Class::_ENV_::OLD_MRO - and - ${^TAINT} - ) { - #local $TODO = "On 5.10+ -T combined with stash peeking invalidates the pkg_gen (wtf)" if ... - - ok( - ( - serialize( describe_class_methods("DBICTest::AttrTest") ) - eq - $cached_desc - ), - "Asking for alternative mro type did not invalidate cache" - ); - } - - # setting mro explicitly still matches what we expect - mro::set_mro("DBICTest::AttrTest", "dfs"); - - is_deeply ( - # in case set_mro starts increasing pkg_gen... - { - %{describe_class_methods("DBICTest::AttrTest")}, - cumulative_gen => $expected_desc->{cumulative_gen}, - }, - $expected_desc, - 'describing with implicit mro returns correct data' - ); - - # check that a UNIVERSAL-parent interrogation makes sense - # ( it should not list anything from UNIVERSAL itself ) - is_deeply ( - describe_class_methods("UEBERVERSAL"), - { - # should be cached by now, thus safe to rely on...? - cumulative_gen => DBIx::Class::_Util::get_real_pkg_gen('UEBERVERSAL'), - - class => 'UEBERVERSAL', - mro => { is_c3 => 0, type => 'dfs' }, - isa => { UEBERVERSAL => 1 }, - linear_isa => [], - methods => { - ueber => $expected_desc->{methods}{ueber} - }, - methods_defined_in_class => { - ueber => $expected_desc->{methods}{ueber}[0] - }, - }, - "Expected description of a parent-of-UNIVERSAL class (pathological case)", - ); -} - -if ($skip_threads) { - SKIP: { skip "Skipping the thread test: $skip_threads", 1 } - - add_more_attrs(); -} -else { SKIP: { - - my $t = threads->create(sub { - - my $t = threads->create(sub { - - add_more_attrs(); - select( undef, undef, undef, 0.2 ); # without this many tasty crashes even on latest perls - - 42; - - }) || do { - die "Unable to start thread: $!" - unless $! == Errno::EAGAIN(); - - SKIP: { skip "EAGAIN encountered, your system is likely bogged down: skipping rest of test", 1 } - - return 42 ; - }; - - my $rv = $t->join; - - select( undef, undef, undef, 0.2 ); # without this many tasty crashes even on latest perls - - $rv; - }) || do { - die "Unable to start thread: $!" - unless $! == Errno::EAGAIN(); - - skip "EAGAIN encountered, your system is likely bogged down: skipping rest of test", 1; - }; - - is ( - $t->join, - 42, - 'Thread stack exitted succesfully' - ); -}} - -# this doesn't really belong in this test, but screw it -{ - package DBICTest::WackyDFS; - use base qw( DBICTest::SomeGrandParentClass DBICTest::SomeParentClass ); -} - -is_deeply - describe_class_methods("DBICTest::WackyDFS")->{methods}{VALID_DBIC_CODE_ATTRIBUTE}, - [ - { - attributes => {}, - name => "VALID_DBIC_CODE_ATTRIBUTE", - via_class => "DBICTest::SomeGrandParentClass", - }, - { - attributes => {}, - name => "VALID_DBIC_CODE_ATTRIBUTE", - via_class => "DBIx::Class::MethodAttributes" - }, - ], - 'Expected description on unusable inheritance hierarchy' -; - -done_testing;