package tests::ReportSpecTest;

use strict;

use base qw/ Lire::Test::TestCase tests::TestStoreFixture
             tests::ChartTypesFixture /;

use Lire::ReportSpec;
use Lire::DlfSchema;
use Lire::FilterExpr;
use Lire::Param;
use Lire::Group;
use Lire::GroupField;
use Lire::Aggregate;
use Lire::Report;
use Lire::Utils qw/tempdir create_file/;

use Lire::Config::XMLSpecListSpec;
use tests::MockAggregator;
use tests::MockAggregate;

use Lire::Report::ChartConfig;

use Lire::Test::Mock;

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

    $self->init();

    return $self;
}

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

    $self->set_up_test_store();

    $self->{'tmp_test_spec_dir'} = $self->{'tmpdir'} . "/test";
    mkdir $self->{'tmp_test_spec_dir'}
      or $self->error( "failed to make $self->{'tmp_test_spec_dir'}: $!\n" );

    $self->{'cfg'}{'lr_reports_path'} = [ $self->{'testdir'} . "/reports",
                                          $self->{'tmpdir'} ];

    $self->set_up_simple_report_spec();

    return;
}

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

    $self->SUPER::tear_down( @_ );

    return;
}

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


    my $spec = Lire::ReportSpec->load( "test", "top-files" );
    $self->assert_str_equals( "top-files", $spec->id() );
}

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

    my $spec = new Lire::ReportSpec();
    $spec->id( "test-report" );
    $spec->superservice( "test" );
    $spec->title( "Test Report Specification" );
    $spec->description( "<para>Test Report Specification</para>" );
    $spec->display_title( "Test Report" );
    $spec->param( "param_int", new Lire::Param( 'name' => "param_int",
                                                'type' => "int",
                                                'i18n_domain' => 'lire-test',
                                              ) );
    $spec->param( "param_int" )->default( 10 );
    $spec->param( "param_match", new Lire::Param( 'name' => "param_match",
                                                  'type' => "string",
                                                  'i18n_domain' => 'lire-test',
                                                ) );
    $spec->param( "param_match" )->default( ".*" );

    my $cfg = new Lire::Report::ChartConfig();
    $cfg->name( 'test-chart' );
    $cfg->title( 'Downloads Pie' );
    $cfg->get( 'case_var' )->set( 'file' );
    $cfg->type( Lire::PluginManager->get_plugin( 'chart_type', 'pie' ) );
    $cfg->type_properties()->get( 'values' )->set( 'downloads' );
    $spec->add_chart_config( $cfg );

    $spec->filter_spec( new Lire::FilterExpr::Match( 'container' => $spec,
                                                     'value' => '$file',
                                                     're' => '$param_match',
                                                   ) );

    my $group = new Lire::Group( 'report_spec' => $spec,
                                'limit' => '$param_int', );

    $group->group_fields( [ new Lire::GroupField( 'report_spec' => $spec,
                                                  'name' => "file",
                                                  'i18n_domain' => 'lire-test',
                                                ) ] );
    $group->ops( [ new Lire::Count( 'report_spec' => $spec,
                                    'parent' => $group,
                                    'name' => "downloads",
                                    'label' => "Downloads",
                                  ) ] );
    $group->sort_fields( [ "-downloads" ] );
    $spec->calc_spec( $group );

    return $spec;
}

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

    $self->{'simple_spec'} = new Lire::ReportSpec();
    $self->{'simple_spec'}->superservice( 'test' );
    $self->{'simple_spec'}->id( 'test-spec' );
    $self->{'simple_spec'}->subreport_id( "test-spec.i" );
    $self->{'simple_spec'}->param( 'param1',
                                   new Lire::Param( 'name' => 'param1',
                                                    'type' => 'int',
                                                    'i18n_domain' => 'lire-test',
                                                    'default' => 5 ) );
    $self->{'simple_spec'}->charttype( 'bars' );
    $self->{'simple_spec'}->display_title( 'Top $param1 report' );
    $self->{'simple_spec'}->display_description( '<para>$param1</para>' );
    my $aggr = 
      new_proxy Lire::Test::Mock( 'tests::MockAggregator',
                                  'report_spec' => $self->{'simple_spec'} );
    $aggr->set_result( 'create_entries' => sub {
                           # Create two empty entries
                           $_[1]->create_entry();
                           $_[1]->create_entry();
                       } );
    $aggr->ops( [ new tests::MockAggregate( 'report_spec' => $self->{'simple_spec'},
                                            'parent' => $aggr,
                                            'name' => 'aggr' ) ] );
    $self->{'simple_spec'}->calc_spec( $aggr );
    return;
}

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

    $self->set_up_chart_types();
    my $spec = $self->create_test_report_spec();
    my $specfile = "$self->{'tmp_test_spec_dir'}/test-report.xml";
    open my $fh, "> $specfile"
      or $self->error( "failed to open $specfile for writing: $!\n" );
    $spec->print( $fh );
    close $fh
      or $self->error( "close failed: $!\n" );

    my $spec2 = Lire::ReportSpec->load( $spec->superservice(), $spec->id() );
    $self->assert_deep_equals( $spec, $spec2 );

}

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

    $self->set_up_chart_types();
    my $subreport = $self->{'simple_spec'}->create_subreport();
    $self->assert_isa( 'Lire::Report::Subreport', $subreport );
    $self->assert_str_equals( 'test-spec', $subreport->type() );
    $self->assert_str_equals( 'test-spec.i', $subreport->id() );
    $self->assert_num_equals( 1, scalar @{$subreport->chart_configs()} );
    $self->assert_str_equals( 'Top 5 report', $subreport->title() );
    $self->assert_str_equals( '<para>5</para>', $subreport->description() );
    $self->assert_str_equals( 2, scalar $subreport->entries() );
    $self->assert_str_equals( 1, ($subreport->entries())[1]->row_idx() );
    $self->assert_isa( 'Lire::Report::TableInfo', $subreport->table_info() );
    $self->assert_num_equals( 1,
                              $subreport->table_info()->column_info_by_name( 'aggr' )->col_start() );

}

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

    my $spec = $self->{'simple_spec'};
    $spec->mark_missing( 'Bogus reason' );

    my $report = new Lire::Report();
    my $subreport = $spec->create_subreport( $report );
    $self->assert_isa( 'Lire::Report::Subreport', $subreport );
    $self->assert_str_equals( 'test-spec', $subreport->type() );
    $self->assert_str_equals( 'test-spec.i', $subreport->id() );
    $self->assert( $subreport->is_missing(),
                   'is_missing() should return true' );
    $self->assert_str_equals( 'Bogus reason', $subreport->missing_reason() );
}

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

    my $spec = new Lire::ReportSpec();
    $spec->id( 'test-spec' );
    $spec->{'superservice'} = 'test-extended';
    my $aggr = new tests::MockAggregator( 'report_spec' => $spec );
    $spec->calc_spec( $aggr );

    $self->assert_dies( qr/missing 'store' parameter/,
                        sub { $spec->set_store() } );
    $self->assert_dies( qr/'store' parameter should be a 'Lire::DlfStore' instance, not 'HASH/,
                        sub { $spec->set_store( {} ) } );
    $self->assert_dies( qr/store doesn't contain a 'test-extended' DLF stream/,
                        sub { $spec->set_store( $self->{'store'} ) }  );

    $spec->{'superservice'} = 'test';
    $spec->set_store( $self->{'store'} );
    $self->assert_equals( $self->{'store'}, $aggr->{'store'} );
}

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

    $self->{'cfg'}{'lr_reports_path'} = [ "$self->{'testdir'}/reports" ];
    $self->set_up_chart_types();

    my $e_spec = Lire::ReportSpec->load( 'test', 'top-dirs2' );
    $e_spec->subreport_id( 'my-top-dirs' );
    $e_spec->param( 'dirs_to_show' )->value( 10 );

    my $list_spec = new Lire::Config::XMLSpecListSpec( 'name' => 'test',
                                                       'type' => 'reports' );
    my $list = $list_spec->instance();
    my $spec = $list_spec->get( 'test:top-dirs2' )->instance();
    $spec->get( 'id' )->set( 'my-top-dirs' );
    $list->append( $spec );
    $e_spec->chart_configs()->[0]->spec()->summary( $spec->spec()->get( 'charts' )->get( 'chart' )->summary() );
    $e_spec->chart_configs()->[0]->spec()->description( $spec->spec()->get( 'charts' )->get( 'chart' )->description() );
    $self->assert_deep_equals( [ $e_spec ], $list->as_value() );

    $spec->get( 'title' )->set( 'My custom title' );
    $spec->get( 'dirs_to_show' )->set( 5 );
    $spec->get( 'charts' )->get( 0 )->get( 'title' )->set( 'My test chart' );
    $e_spec->display_title( 'My custom title' );
    $e_spec->param( 'dirs_to_show' )->value( 5 );
    $e_spec->chart_configs()->[0]->title( 'My test chart' );
    $self->assert_deep_equals( [ $e_spec ], $list->as_value() );
}

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

    my $spec = new Lire::ReportSpec();
    $self->assert_null( $spec->{'_chart_configs'}, '_chart_configs != undef' );
    $spec->superservice( 'test' );
    $spec->id( 'test-chart' );
    $spec->subreport_id( 'test-chart.0' );

    my $outer = new tests::MockAggregator( 'name' => 'outer',
                                           'report_spec' => $spec );
    my $inner = new tests::MockAggregator( 'name' => 'inner',
                                           'parent' => $outer,
                                           'report_spec' => $spec );
    $inner->ops( [ new tests::MockAggregate( 'name' => 'value1',
                                             'parent' => $inner,
                                             'report_spec' => $spec ),
                   new tests::MockAggregate( 'name' => 'value2',
                                             'parent' => $inner,
                                             'report_spec' => $spec ) ] );
    $outer->ops( [ $inner ] );
    $spec->calc_spec( $outer );

    $self->{'spec'} = $spec;
    return;
}

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

    $self->set_up_chart_types();
    $self->set_up_chart_report_spec();

    my $cfg = new Lire::Report::ChartConfig();
    $cfg->basename( 'test-chart.0' );
    $cfg->get( 'case_var' )->set( 'outer' );

    $self->{'spec'}->charttype( undef );
    $self->assert_null( $self->{'spec'}->default_chart_config(),
                        'default_chart_config != undef' );

    $self->{'spec'}->charttype( 'bars' );
    $cfg->type( Lire::PluginManager->get_plugin( 'chart_type', 'vbars' ) );
    $cfg->type_properties()->get( 'y' )->set( 'value1' );
    $self->assert_deep_equals( $cfg, $self->{'spec'}->default_chart_config() );

    $self->{'spec'}->charttype( 'histogram' );
    $self->assert_deep_equals( $cfg, $self->{'spec'}->default_chart_config() );

    $self->{'spec'}->charttype( 'lines' );
    $cfg->type( Lire::PluginManager->get_plugin( 'chart_type', 'lines' ) );
    $cfg->type_properties()->get( 'y' )->set( 'value1' );
    $self->assert_deep_equals( $cfg, $self->{'spec'}->default_chart_config() );

    $self->{'spec'}->charttype( 'pie' );
    $cfg->type( Lire::PluginManager->get_plugin( 'chart_type', 'pie' ) );
    $cfg->type_properties()->get( 'values' )->set( 'value1' );
    $self->assert_deep_equals( $cfg, $self->{'spec'}->default_chart_config() );
}

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

    $self->set_up_chart_types();
    $self->set_up_chart_report_spec();

    $self->{'spec'}->charttype( undef );
    $self->assert_deep_equals( [], $self->{'spec'}->chart_configs() );

    $self->{'spec'}->charttype( 'bars' );
    $self->assert_deep_equals( [ $self->{'spec'}->default_chart_config() ],
                               $self->{'spec'}->chart_configs() );

    $self->assert_null( $self->{'spec'}{'_chart_configs'} );

    my $cfg = new Lire::Report::ChartConfig();
    $self->{'spec'}->add_chart_config( $cfg );
    $self->assert_deep_equals( [ $cfg ], $self->{'spec'}{'_chart_configs'} );
    $self->assert_deep_equals( [ $cfg ], $self->{'spec'}->chart_configs() );
}

1;


syntax highlighted by Code2HTML, v. 0.9.1