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( "Test Report Specification" );
$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( '$param1' );
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( '5', $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;