package tests::ExtendedSchemaTest;

use strict;

use base qw/ Lire::Test::TestCase /;

use Lire::DlfSchema;
use Lire::ExtendedSchema;
use Lire::DerivedSchema;
use Lire::Field;
use Lire::DlfStore;
use Lire::Utils qw/tempdir/;
use File::Basename qw/dirname/;
use Cwd qw/realpath/;

sub new {
    my $self = shift()->SUPER::new( @_ );

    $self->{'tmpdir'} = tempdir( __PACKAGE__ . "XXXXXX",
                               'TMPDIR' => 1, CLEANUP => 1 );

    return $self;
}

sub set_up {
    my $self = $_[0];
    $self->SUPER::set_up();

    $self->{'old_cache'} = { %Lire::DlfSchema::SCHEMA_CACHE };
    %Lire::DlfSchema::SCHEMA_CACHE = ();

    # Make sure the Lire::DlfSchema can find our test schemas.
    $self->{'cfg'}{'lr_schemas_path'} =
      [ realpath( dirname(__FILE__) . "/schemas" ) ];
    $self->{'schema'} = Lire::DlfSchema::load_schema( "test-extended" );

    $self->{'cfg'}{'_lr_config_spec'} = $self->lire_default_config_spec();

    # We don't open the store in new() because we need to
    # change the configuration before
    $self->{'store'} = Lire::DlfStore->open( "$self->{'tmpdir'}/store", 1 )
      unless defined $self->{'store'};

    return;
}

sub tear_down {
    my $self = $_[0];
    $self->SUPER::tear_down();

    $self->{'store'}->_dbh()->rollback();

    %Lire::DlfSchema::SCHEMA_CACHE = %{$self->{'old_cache'}};

    return;
}

sub test_new {
    my $self = $_[0];

    $self->assert_dies( qr/cannot find superservice in id: test_extended/,
                        sub { new Lire::ExtendedSchema( 'id' => 'test_extended' ) } );

    $self->assert_dies( qr/base schema cannot be an extended schema: test-extended/,
                        sub { new Lire::ExtendedSchema( 'id' => 'test-another',
                                                        'base-schema' => 'test-extended' ) } );

    my $schema = new Lire::ExtendedSchema( 'id' => 'test-extended',
                                           'module' => 'MyModule',
                                           'base-schema' => 'test' );
    $self->assert_isa( 'Lire::ExtendedSchema', $schema );
    $self->assert_str_equals( 'test-extended', $schema->{'id'} );
    $self->assert_str_equals( 'test', $schema->{'superservice'} );

    my $base = Lire::DlfSchema::load_schema( 'test' );
    $self->assert_str_equals( $base, $schema->{'base'} );
    $self->assert_deep_equals( [ $base->fields() ],
                               $schema->{'fields_by_pos'} );
    $self->assert_deep_equals( $base->{'fields_by_name'},
                               $schema->{'fields_by_name'} );

    $self->assert_num_equals( 11, $schema->{'extended_start_idx'} );

}

sub test_id {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    $self->assert_str_equals( "test-extended", $self->{'schema'}->id() );
}

sub test_superservice {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    $self->assert_str_equals( "test", $self->{'schema'}->superservice() );
}

sub test_base {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );

    my $base = $self->{'schema'}->base();
    $self->assert_isa( 'Lire::DlfSchema', $base );
    $self->assert_str_equals( "test", $base->id() );
}

sub test_extended_fields {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    my $mockfield = bless { 'name'	   => 'dirname',
                            'type'	   => 'filename',
                            'pos'	   => 11,
                            'description'  => "\n   <para>Contains the file's directory.</para>\n  ",
                            'label'	   => 'Directory',
                            'i18n_domain'  => 'lire-test',
                          }, 'Lire::Field';

    $self->assert_deep_equals( [ $mockfield ],
                               $self->{'schema'}->extended_fields() );
}

sub test_can_join_schema {
    my $self = $_[0];

    my $test = new Lire::DlfSchema( 'superservice' => 'test',
                                    'timestamp' => 'time' );
    $test->add_field( new Lire::Field( 'name' => 'time',
                                       'type' => 'timestamp' ) );

    $Lire::DlfSchema::SCHEMA_CACHE{'test'} = $test;

    my $test2 = new Lire::DlfSchema( 'superservice' => 'test2',
                                     'timestamp' => 'time' );
    $test2->add_field( new Lire::Field( 'name' => 'time',
                                        'type' => 'timestamp' ) );
    $Lire::DlfSchema::SCHEMA_CACHE{'test2'} = $test2;

    my $ext1 = new Lire::ExtendedSchema( 'id' => 'test-ext1',
                                         'base-schema' => 'test',
                                         'module' => 'MyModule' );
    my $ext2 = new Lire::ExtendedSchema( 'id' => 'test2-ext2',
                                         'base-schema' => 'test2',
                                         'module' => 'MyModule'  );
    my $ext3 = new Lire::ExtendedSchema( 'id' => 'test-ext3',
                                         'base-schema' => 'test',
                                         'module' => 'MyModule' );

    my $derived = new Lire::DerivedSchema( 'id' => 'test-derived',
                                           'base-schema' => 'test',
                                           'timestamp' => 'time',
                                           'module' => 'MyModule'  );
    $self->assert( $ext1->can_join_schema( $ext3 ) );
    $self->assert( ! $ext1->can_join_schema( $test ) );
    $self->assert( ! $ext1->can_join_schema( $ext1 ) );
    $self->assert( ! $ext1->can_join_schema( $ext2 ) );
    $self->assert( ! $ext1->can_join_schema( $test2 ) );
    $self->assert( ! $ext1->can_join_schema( $derived ) );
}

sub test_sql_insert_query {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    my $e_sql = q{INSERT INTO "dlf_test-extended" (dlf_id, dlf_source, dirname) VALUES (?,?,?)};
    $self->assert_str_equals( $e_sql, $self->{'schema'}->sql_insert_query() );
}

sub test_create_sql_schema {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );

    $self->{'schema'}->create_sql_schema( $self->{'store'} );
    my $sql_def = $self->{'schema'}->_sql_fields_def();
    chomp $sql_def; # Trailing newline removed by SQLite

    my $dbh = $self->{'store'}->_dbh();
    my $table = $dbh->selectrow_hashref( "SELECT * FROM sqlite_master WHERE name = 'dlf_test-extended'" );
    $self->assert_not_null( $table, "table dlf_test wasn't created" );
    $self->assert_matches( qr/\Q$sql_def\E/, $table->{'sql'} );

    my $index = $dbh->selectrow_hashref( "SELECT * FROM sqlite_master WHERE name = 'dlf_test-extended_time_start_idx'" );
    $self->assert_null( $index, "index shouldn't exists"  );

    my $trigger = $dbh->selectrow_hashref( q{SELECT * FROM sqlite_master WHERE name = 'dlf_test-extended_delete_trigger'} );
    $self->assert_not_null( $trigger, "trigger dlf_test-extended_delete_trigger wasn't created"  );
    $self->assert_str_equals( "trigger", $trigger->{'type'} );
    my $trigger_sql = <<EOS;
CREATE TRIGGER "dlf_test-extended_delete_trigger" AFTER DELETE ON dlf_test
BEGIN
    DELETE FROM "dlf_test-extended" WHERE dlf_id = old.dlf_id;
END
EOS
    chomp $trigger_sql;

    $self->assert_str_equals( $trigger_sql, $trigger->{'sql'} );

}

sub test_sql_clean_query {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    $self->assert_str_equals( 'DELETE FROM "dlf_test-extended"',
                              $self->{'schema'}->sql_clean_query() );
    $self->{'schema'}{'timestamp_field'} = 'time-start';
    $self->assert_str_equals( 'DELETE FROM "dlf_test-extended" WHERE dlf_id IN ( SELECT e.dlf_id FROM dlf_test b, "dlf_test-extended" e WHERE b.dlf_id = e.dlf_id AND "b.time-start" < ? )',
                              $self->{'schema'}->sql_clean_query( 1 ) );
}

sub test_sql_clean_period_query {
    my $self = $_[0];

    $self->assert_isa( 'Lire::ExtendedSchema', $self->{'schema'} );
    $self->{'schema'}{'timestamp_field'} = 'time-start';
    $self->assert_str_equals( 'DELETE FROM "dlf_test-extended" WHERE dlf_id IN ( SELECT e.dlf_id FROM dlf_test b, "dlf_test-extended" e WHERE b.dlf_id = e.dlf_id AND "b.time-start" >= ? AND "b.time-start" < ? )',
                              $self->{'schema'}->sql_clean_period_query );
}

sub test_dlf_query {
    my $self = $_[0];

    my $query = $self->{'schema'}->dlf_query( 'time_start' );
    $self->assert_isa( 'Lire::DlfQuery', $query );

    $self->assert( $query->has_field( 'dlf_id' ), 'missing dlf_id' );
    $self->assert_str_equals( '"dlf_test-extended".dlf_id',
                              $query->field_def( 'dlf_id' ) );
    $self->assert( $query->has_field( 'dlf_source' ), 'missing dlf_source' );;
    $self->assert_str_equals( '"dlf_test-extended".dlf_source',
                              $query->field_def( 'dlf_source' ) );
    $self->assert( $query->has_field( 'dirname' ), 'missing dirname' );

    $self->assert_str_equals( 'time_start', $query->sort_spec() );
    return;
}

1;





syntax highlighted by Code2HTML, v. 0.9.1