X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2Flib%2Fdbixcsl_common_tests.pm;h=45a09e3e983092b2bac062e811ecd6c6d5a2322a;hb=e35e5a64c36c7a39809c9b4221ef0528c0bd448e;hp=159d4e5943aa5922139510ca7314d4232ef4c4c5;hpb=b1e43108db28b5a04a41dc5d2565ca2feb1a5e16;p=dbsrgits%2FDBIx-Class-Schema-Loader.git diff --git a/t/lib/dbixcsl_common_tests.pm b/t/lib/dbixcsl_common_tests.pm index 159d4e5..45a09e3 100644 --- a/t/lib/dbixcsl_common_tests.pm +++ b/t/lib/dbixcsl_common_tests.pm @@ -8,6 +8,8 @@ use DBIx::Class::Schema::Loader; use Class::Unload; use File::Path; use DBI; +use Digest::MD5; +use File::Find 'find'; my $DUMP_DIR = './t/_common_dump'; rmtree $DUMP_DIR; @@ -36,6 +38,10 @@ sub new { # Optional extra tables and tests $self->{extra} ||= {}; + # Not all DBS do SQL-standard CURRENT_TIMESTAMP + $self->{default_function} ||= "CURRENT_TIMESTAMP"; + $self->{default_function_def} ||= "TIMESTAMP DEFAULT $self->{default_function}"; + return bless $self => $class; } @@ -54,11 +60,16 @@ sub _monikerize { sub run_tests { my $self = shift; - plan tests => 3 + 134 + ($self->{extra}->{count} || 0); + plan tests => 145 + ($self->{extra}->{count} || 0); $self->create(); - my @connect_info = ( $self->{dsn}, $self->{user}, $self->{password} ); + my @connect_info = ( + $self->{dsn}, + $self->{user}, + $self->{password}, + $self->{connect_info_opts}, + ); # First, with in-memory classes my $schema_class = $self->setup_schema(@connect_info); @@ -66,6 +77,11 @@ sub run_tests { $self->drop_tables; } +# defined in sub create +my (@statements, @statements_reltests, @statements_advanced, + @statements_advanced_sqlite, @statements_inline_rels, + @statements_implicit_rels); + sub setup_schema { my $self = shift; my @connect_info = @_; @@ -87,6 +103,7 @@ sub setup_schema { inflect_singular => { fkid => 'fkid_singular' }, moniker_map => \&_monikerize, debug => $debug, + use_namespaces => 0, dump_directory => $DUMP_DIR, ); @@ -103,11 +120,38 @@ sub setup_schema { __PACKAGE__->connection(\@connect_info); }; - ok(!$@, "Loader initialization") or diag $@; + ok(!$@, "Loader initialization") or diag $@; + + my $file_count; + find sub { return if -d; $file_count++ }, $DUMP_DIR; + + my $expected_count = 35; + + $expected_count += grep /CREATE (?:TABLE|VIEW)/i, + @{ $self->{extra}{create} || [] }; + + $expected_count -= grep /CREATE TABLE/, @statements_inline_rels + if $self->{skip_rels} || $self->{no_inline_rels}; + + $expected_count -= grep /CREATE TABLE/, @statements_implicit_rels + if $self->{skip_rels} || $self->{no_implicit_rels}; + + $expected_count -= grep /CREATE TABLE/, ($self->{vendor} =~ /sqlite/ ? @statements_advanced_sqlite : @statements_advanced), @statements_reltests + if $self->{skip_rels}; + + is $file_count, $expected_count, 'correct number of files generated'; + + exit if $file_count != $expected_count; my $warn_count = 2; $warn_count++ if grep /ResultSetManager/, @loader_warnings; + $warn_count++ for grep /^Bad table or view/, @loader_warnings; + + my $vendor = $self->{vendor}; + $warn_count++ for grep /${vendor}_\S+ has no primary key/, + @loader_warnings; + if($self->{skip_rels}) { SKIP: { is(scalar(@loader_warnings), $warn_count, "No loader warnings") @@ -158,10 +202,15 @@ sub test_schema { my $class24 = $classes->{LoAdEr_test24}; my $rsobj24 = $conn->resultset($moniker2); + my $moniker35 = $monikers->{loader_test35}; + my $class35 = $classes->{loader_test35}; + my $rsobj35 = $conn->resultset($moniker35); + isa_ok( $rsobj1, "DBIx::Class::ResultSet" ); isa_ok( $rsobj2, "DBIx::Class::ResultSet" ); isa_ok( $rsobj23, "DBIx::Class::ResultSet" ); isa_ok( $rsobj24, "DBIx::Class::ResultSet" ); + isa_ok( $rsobj35, "DBIx::Class::ResultSet" ); my @columns_lt2 = $class2->columns; is_deeply( \@columns_lt2, [ qw/id dat dat2/ ], "Column Ordering" ); @@ -265,6 +314,29 @@ sub test_schema { my ($obj2) = $rsobj2->search({ dat => 'bbb' })->first; is( $obj2->id, 2 ); + is( + $class35->column_info('a_varchar')->{default_value}, 'foo', + 'constant character default', + ); + + is( + $class35->column_info('an_int')->{default_value}, 42, + 'constant integer default', + ); + + is( + $class35->column_info('a_double')->{default_value}, 10.555, + 'constant numeric default', + ); + + my $function_default = $class35->column_info('a_function')->{default_value}; + + isa_ok( $function_default, 'SCALAR', 'default_value for function default' ); + is_deeply( + $function_default, \$self->{default_function}, + 'default_value for function default is correct' + ); + SKIP: { skip $self->{skip_rels}, 96 if $self->{skip_rels}; @@ -523,52 +595,46 @@ sub test_schema { } # from Chisel's tests... - SKIP: { - if($self->{vendor} =~ /sqlite/i) { - skip 'SQLite cannot do the advanced tests', 10; - } - - my $moniker10 = $monikers->{loader_test10}; - my $class10 = $classes->{loader_test10}; - my $rsobj10 = $conn->resultset($moniker10); + my $moniker10 = $monikers->{loader_test10}; + my $class10 = $classes->{loader_test10}; + my $rsobj10 = $conn->resultset($moniker10); - my $moniker11 = $monikers->{loader_test11}; - my $class11 = $classes->{loader_test11}; - my $rsobj11 = $conn->resultset($moniker11); + my $moniker11 = $monikers->{loader_test11}; + my $class11 = $classes->{loader_test11}; + my $rsobj11 = $conn->resultset($moniker11); - isa_ok( $rsobj10, "DBIx::Class::ResultSet" ); - isa_ok( $rsobj11, "DBIx::Class::ResultSet" ); + isa_ok( $rsobj10, "DBIx::Class::ResultSet" ); + isa_ok( $rsobj11, "DBIx::Class::ResultSet" ); - ok($class10->column_info('loader_test11')->{is_foreign_key}, 'Foreign key detected'); - ok($class11->column_info('loader_test10')->{is_foreign_key}, 'Foreign key detected'); + ok($class10->column_info('loader_test11')->{is_foreign_key}, 'Foreign key detected'); + ok($class11->column_info('loader_test10')->{is_foreign_key}, 'Foreign key detected'); - my $obj10 = $rsobj10->create({ subject => 'xyzzy' }); + my $obj10 = $rsobj10->create({ subject => 'xyzzy' }); - $obj10->update(); - ok( defined $obj10, 'Create row' ); + $obj10->update(); + ok( defined $obj10, 'Create row' ); - my $obj11 = $rsobj11->create({ loader_test10 => $obj10->id() }); - $obj11->update(); - ok( defined $obj11, 'Create related row' ); + my $obj11 = $rsobj11->create({ loader_test10 => $obj10->id() }); + $obj11->update(); + ok( defined $obj11, 'Create related row' ); - eval { - my $obj10_2 = $obj11->loader_test10; - $obj10_2->loader_test11( $obj11->id11() ); - $obj10_2->update(); - }; - ok(!$@, "Setting up circular relationship"); + eval { + my $obj10_2 = $obj11->loader_test10; + $obj10_2->loader_test11( $obj11->id11() ); + $obj10_2->update(); + }; + ok(!$@, "Setting up circular relationship"); - SKIP: { - skip 'Previous eval block failed', 3 if $@; - - my $results = $rsobj10->search({ subject => 'xyzzy' }); - is( $results->count(), 1, 'No duplicate row created' ); + SKIP: { + skip 'Previous eval block failed', 3 if $@; + + my $results = $rsobj10->search({ subject => 'xyzzy' }); + is( $results->count(), 1, 'No duplicate row created' ); - my $obj10_3 = $results->first(); - isa_ok( $obj10_3, $class10 ); - is( $obj10_3->loader_test11()->id(), $obj11->id(), - 'Circular rel leads back to same row' ); - } + my $obj10_3 = $results->first(); + isa_ok( $obj10_3, $class10 ); + is( $obj10_3->loader_test11()->id(), $obj11->id(), + 'Circular rel leads back to same row' ); } SKIP: { @@ -617,11 +683,8 @@ sub test_schema { } } - # rescan test + # rescan and norewrite test SKIP: { - skip $self->{skip_rels}, 4 if $self->{skip_rels}; - skip "Can't rescan dumped schema", 4 if $self->{dump}; - my @statements_rescan = ( qq{ CREATE TABLE loader_test30 ( @@ -634,15 +697,57 @@ sub test_schema { q{ INSERT INTO loader_test30 (id,loader_test2) VALUES(321, 2) }, ); + # get md5 + my $digest = Digest::MD5->new; + + my $find_cb = sub { + return if -d; + return if $_ eq 'LoaderTest30.pm'; + + open my $fh, '<', $_ or die "Could not open $_ for reading: $!"; + binmode $fh; + $digest->addfile($fh); + }; + + find $find_cb, $DUMP_DIR; + + my $before_digest = $digest->digest; + my $dbh = $self->dbconnect(1); - $dbh->do($_) for @statements_rescan; + + { + # Silence annoying but harmless postgres "NOTICE: CREATE TABLE..." + local $SIG{__WARN__} = sub { + my $msg = shift; + print STDERR $msg unless $msg =~ m{^NOTICE:\s+CREATE TABLE}; + }; + + $dbh->do($_) for @statements_rescan; + } + $dbh->disconnect; - my @new = $conn->rescan; + sleep 1; + + my @new = do { + # kill the 'Dumping manual schema' warnings + local $SIG{__WARN__} = sub {}; + $conn->rescan; + }; is_deeply(\@new, [ qw/LoaderTest30/ ], "Rescan"); + $digest = Digest::MD5->new; + find $find_cb, $DUMP_DIR; + my $after_digest = $digest->digest; + + is $before_digest, $after_digest, + 'dumped files are not rewritten when there is no modification'; + my $rsobj30 = $conn->resultset('LoaderTest30'); isa_ok($rsobj30, 'DBIx::Class::ResultSet'); + + skip 'no rels', 2 if $self->{skip_rels}; + my $obj30 = $rsobj30->find(123); isa_ok( $obj30->loader_test2, $class2); @@ -690,7 +795,7 @@ sub create { $self->{_created} = 1; my $make_auto_inc = $self->{auto_inc_cb} || sub {}; - my @statements = ( + @statements = ( qq{ CREATE TABLE loader_test1s ( id $self->{auto_inc_pk}, @@ -731,9 +836,19 @@ sub create { DaT VARCHAR(32) NOT NULL UNIQUE ) $self->{innodb} }, + + qq{ + CREATE TABLE loader_test35 ( + id INTEGER PRIMARY KEY, + a_varchar VARCHAR(100) DEFAULT 'foo', + an_int INTEGER DEFAULT 42, + a_double DOUBLE PRECISION DEFAULT 10.555, + a_function $self->{default_function_def} + ) $self->{innodb} + }, ); - my @statements_reltests = ( + @statements_reltests = ( qq{ CREATE TABLE loader_test3 ( id INTEGER NOT NULL PRIMARY KEY, @@ -992,7 +1107,7 @@ sub create { q{ INSERT INTO loader_test34 (id,rel1) VALUES (1,2) }, ); - my @statements_advanced = ( + @statements_advanced = ( qq{ CREATE TABLE loader_test10 ( id10 $self->{auto_inc_pk}, @@ -1017,7 +1132,30 @@ sub create { q{ REFERENCES loader_test11 (id11) }), ); - my @statements_inline_rels = ( + @statements_advanced_sqlite = ( + qq{ + CREATE TABLE loader_test10 ( + id10 $self->{auto_inc_pk}, + subject VARCHAR(8) + ) $self->{innodb} + }, + $make_auto_inc->(qw/loader_test10 id10/), + + qq{ + CREATE TABLE loader_test11 ( + id11 $self->{auto_inc_pk}, + message VARCHAR(8) DEFAULT 'foo', + loader_test10 INTEGER $self->{null}, + FOREIGN KEY (loader_test10) REFERENCES loader_test10 (id10) + ) $self->{innodb} + }, + $make_auto_inc->(qw/loader_test11 id11/), + + (q{ ALTER TABLE loader_test10 ADD COLUMN } . + q{ loader_test11 INTEGER REFERENCES loader_test11 (id11) }), + ); + + @statements_inline_rels = ( qq{ CREATE TABLE loader_test12 ( id INTEGER NOT NULL PRIMARY KEY, @@ -1041,7 +1179,7 @@ sub create { ); - my @statements_implicit_rels = ( + @statements_implicit_rels = ( qq{ CREATE TABLE loader_test14 ( id INTEGER NOT NULL PRIMARY KEY, @@ -1078,7 +1216,10 @@ sub create { # to test one for mysql, which works on everyone else... # this all needs to be refactored anyways. $dbh->do($_) for (@statements_reltests); - unless($self->{vendor} =~ /sqlite/i) { + if($self->{vendor} =~ /sqlite/i) { + $dbh->do($_) for (@statements_advanced_sqlite); + } + else { $dbh->do($_) for (@statements_advanced); } unless($self->{no_inline_rels}) { @@ -1101,6 +1242,7 @@ sub drop_tables { loader_test2 LOADER_TEST23 LoAdEr_test24 + loader_test35 /; my @tables_auto_inc = ( @@ -1170,25 +1312,23 @@ sub drop_tables { unless($self->{skip_rels}) { $dbh->do("DROP TABLE $_") for (@tables_reltests); - unless($self->{vendor} =~ /sqlite/i) { - if($self->{vendor} =~ /mysql/i) { - $dbh->do($drop_fk_mysql); - } - else { - $dbh->do($drop_fk); - } - $dbh->do("DROP TABLE $_") for (@tables_advanced); - $dbh->do($_) for map { $drop_auto_inc->(@$_) } @tables_advanced_auto_inc; + if($self->{vendor} =~ /mysql/i) { + $dbh->do($drop_fk_mysql); } + else { + $dbh->do($drop_fk); + } + $dbh->do("DROP TABLE $_") for (@tables_advanced); + $dbh->do($_) for map { $drop_auto_inc->(@$_) } @tables_advanced_auto_inc; + unless($self->{no_inline_rels}) { $dbh->do("DROP TABLE $_") for (@tables_inline_rels); } unless($self->{no_implicit_rels}) { $dbh->do("DROP TABLE $_") for (@tables_implicit_rels); } - $dbh->do("DROP TABLE $_") for (@tables_rescan); } - $dbh->do("DROP TABLE $_") for (@tables); + $dbh->do("DROP TABLE $_") for (@tables, @tables_rescan); $dbh->do($_) for map { $drop_auto_inc->(@$_) } @tables_auto_inc; $dbh->disconnect; }