package Fey::Test; use strict; use warnings; use DBI; use File::Temp (); use Fey 0.10; use Fey::Column; use Fey::FK; use Fey::Schema; use Fey::Table; use List::MoreUtils qw( all ); BEGIN { # This freaking module is reporting warnings from overload.pm, # which is calling can() as a method. $INC{'UNIVERSAL/can.pm'} = 1; } use Test::MockObject; our $VERSION = '0.06'; sub mock_test_schema { my $class = shift; my $schema = Fey::Schema->new( name => 'Test' ); $schema->add_table( _user_table() ); $schema->add_table( _group_table() ); $schema->add_table( _user_group_table() ); $schema->add_table( _message_table() ); return $schema; } sub mock_test_schema_with_fks { my $class = shift; my $schema = $class->mock_test_schema(@_); my $fk1 = Fey::FK->new ( source_columns => [ $schema->table('UserGroup')->column('user_id') ], target_columns => [ $schema->table('User')->column('user_id') ], ); my $fk2 = Fey::FK->new ( source_columns => [ $schema->table('UserGroup')->column('group_id') ], target_columns => [ $schema->table('Group')->column('group_id') ], ); my $fk3 = Fey::FK->new ( source_columns => [ $schema->table('Message')->column('parent_message_id') ], target_columns => [ $schema->table('Message')->column('message_id') ], ); my $fk4 = Fey::FK->new ( source_columns => [ $schema->table('Message')->column('user_id') ], target_columns => [ $schema->table('User')->column('user_id') ], ); $schema->add_foreign_key($_) for $fk1, $fk2, $fk3, $fk4; return $schema; } sub _user_table { my $t = Fey::Table->new( name => 'User' ); my $user_id = Fey::Column->new( name => 'user_id', type => 'integer', is_auto_increment => 1, ); my $username = Fey::Column->new( name => 'username', type => 'text', ); my $email = Fey::Column->new( name => 'email', type => 'text', is_nullable => 1, ); $t->add_column($_) for $user_id, $username, $email; $t->add_candidate_key($user_id); $t->add_candidate_key($username); return $t; } sub _group_table { my $t = Fey::Table->new( name => 'Group' ); my $group_id = Fey::Column->new( name => 'group_id', type => 'integer', is_auto_increment => 1, ); my $name = Fey::Column->new( name => 'name', type => 'text', ); $t->add_column($_) for $group_id, $name; $t->add_candidate_key($group_id); $t->add_candidate_key($name); return $t; } sub _user_group_table { my $t = Fey::Table->new( name => 'UserGroup' ); my $user_id = Fey::Column->new( name => 'user_id', type => 'integer', ); my $group_id = Fey::Column->new( name => 'group_id', type => 'integer', ); $t->add_column($_) for $user_id, $group_id; $t->add_candidate_key( $user_id, $group_id ); return $t; } sub _message_table { my $t = Fey::Table->new( name => 'Message' ); my $message_id = Fey::Column->new( name => 'message_id', type => 'integer', is_auto_increment => 1, ); my $message = Fey::Column->new( name => 'message', type => 'text', default => q{Some message '" text}, ); my $quality = Fey::Column->new( name => 'quality', type => 'float', length => 5, precision => 2, default => 2.3, ); my $message_date = Fey::Column->new( name => 'message_date', type => 'date', default => Fey::Literal::Function->new('NOW'), ); my $parent_message_id = Fey::Column->new( name => 'parent_message_id', type => 'integer', is_nullable => 1, ); my $user_id = Fey::Column->new( name => 'user_id', type => 'integer', ); $t->add_column($_) for $message_id, $message, $quality, $message_date, $parent_message_id, $user_id; $t->add_candidate_key($message_id); return $t; } sub mock_dbh { my $mock = Test::MockObject->new(); $mock->set_isa('DBI::db'); $mock->mock( 'get_info', \&_mock_get_info ); $mock->mock( 'quote_identifier', \&_mock_quote_identifier ); $mock->mock( 'quote', \&_mock_quote ); $mock->mock( 'table_info', \&_mock_table_info ); $mock->mock( 'column_info', \&_mock_column_info ); $mock->mock( 'primary_key_info', \&_mock_primary_key_info ); $mock->mock( 'statistics_info', \&_mock_statistics_info ); $mock->mock( 'foreign_key_info', \&_mock_foreign_key_info ); $mock->{Driver}{Name} = 'Mock'; $mock->{__schema__} = __PACKAGE__->mock_test_schema_with_fks(); $mock->{Name} = $mock->{__schema__}->name(); return $mock; } { my %Info = ( 29 => q{"}, 41 => q{.}, ); sub _mock_get_info { my $self = shift; my $num = shift; return $Info{$num} } } sub _mock_quote_identifier { shift; if ( @_ == 3 ) { return q{"} . $_[1] . q{"} . q{.} . q{"} . $_[2] . q{"} } else { return q{"} . $_[0] . q{"}; } } sub _mock_quote { my $self = shift; my $str = shift; my $q = q{'}; $str =~ s/$q/$q$q/g; return "$q$str$q"; } sub _mock_table_info { my $self = shift; unless ( $self->{__schema__}->table('TestView') ) { my $table = Fey::Table->new( name => 'TestView', is_view => 1, ); my $col = Fey::Column->new( name => 'user_id', type => 'integer', generic_type => 'integer', ); $table->add_column($col); $table->add_candidate_key($col); $self->{__schema__}->add_table($table); } my @tables; for my $table ( $self->{__schema__}->tables() ) { push @tables, { TABLE_NAME => $table->name(), TABLE_TYPE => ( $table->is_view() ? 'VIEW' : 'TABLE'), }; } return Fey::Test::MockSTH->new(\@tables); } sub _mock_column_info { my $self = shift; my $table_name = $_[2]; my $table = $self->{__schema__}->table($table_name); return Fey::Test::MockSTH->new() unless $table; my @columns; for my $col ( $table->columns() ) { my %col = ( COLUMN_NAME => $col->name(), TYPE_NAME => $col->type(), NULLABLE => $col->is_nullable(), ); $col{COLUMN_SIZE} = $col->length() if defined $col->length(); $col{DECIMAL_DIGITS} = $col->precision() if defined $col->precision(); $col{COLUMN_DEF} = $col->default()->sql($self) if $col->default(); push @columns, \%col; } return Fey::Test::MockSTH->new(\@columns); } sub _mock_primary_key_info { my $self = shift; my $table_name = $_[2]; my $table = $self->{__schema__}->table($table_name); my $x = 1; my @pk; for my $pk ( @{ $table->primary_key() } ) { push @pk, { COLUMN_NAME => $pk->name(), KEY_SEQ => $x++, }; } return Fey::Test::MockSTH->new(\@pk); } sub _mock_statistics_info { my $self = shift; my $table_name = $_[2]; my $table = $self->{__schema__}->table($table_name); my @ck; for my $ck ( @{ $table->candidate_keys() } ) { my $x = 1; for my $col ( @{ $ck } ) { push @ck, { INDEX_NAME => $table_name . $ck, COLUMN_NAME => $col->name(), ORDINAL_POSITION => $x++, }; } } return Fey::Test::MockSTH->new(\@ck); } sub _mock_foreign_key_info { my $self = shift; my $table_name = $_[2]; my $table = $self->{__schema__}->table($table_name); return unless $table; my @fk; my %pk = map { $_->name() => 1 } @{ $table->primary_key() }; for my $fk ( $self->{__schema__}->foreign_keys_for_table($table) ) { my @source = @{ $fk->source_columns() }; next if @source == keys %pk && all { $pk{ $_->name() } } @source; my @target = @{ $fk->target_columns() }; for ( my $x = 0; $x < @source; $x++ ) { push @fk, { ORDINAL_POSITION => $x + 1, UK_TABLE_NAME => $target[$x]->table()->name(), UK_COLUMN_NAME => $target[$x]->name(), FK_TABLE_NAME => $source[$x]->table()->name(), FK_COLUMN_NAME => $source[$x]->name(), FK_NAME => ( join '_', map { $_->name() } $source[$x]->table(), $source[$x], $target[$x]->table(), $target[$x], ) }; } } return Fey::Test::MockSTH->new(\@fk); } package # hide from PAUSE Fey::Test::MockSTH; sub new { my $class = shift; my $rows = shift || []; return bless $rows, $class; } sub fetchrow_hashref { my $self = shift; return unless @{$self}; return shift @{$self}; } 1; __END__ =head1 NAME Fey::Test - Test libraries for Fey distros =head1 SYNOPSIS # ... =head1 DESCRIPTION This distribution contains libraries used for testing various Fey distributions. =head1 AUTHOR Dave Rolsky, =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2006-2008 Dave Rolsky, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut