package tests::ReportParserLaTeXWriterTest; use strict; use base qw/Lire::Test::TestCase tests::TestStoreFixture tests::ChartTypesFixture /; use Lire::ReportParser::LaTeXWriter; use Lire::ReportParser::ReportBuilder; use Lire::Utils qw/tempdir create_file file_content/; use File::Path qw/rmtree/; use Lire::Config::ConfigSpec; use Lire::DlfSchema; use Lire::Field; use Lire::Report; use Lire::Report::Section; use Lire::Report::Subreport; use Lire::Report::TableInfo; use Lire::Report::ChartConfig; use Lire::ChartType; use Lire::PluginManager; use Lire::Test::Mock; use IO::Scalar; use Time::Local; sub set_up { my $self = $_[0]; $self->SUPER::set_up(); $self->{'tmpdir'} = tempdir( $self->name() . "_XXXXXX" ); $self->{'writer'} = new_proxy Lire::Test::Mock( 'Lire::ReportParser::LaTeXWriter' ); $self->{'writer'}{'_fh'} = new IO::Scalar(); $self->{'keep_tmpdir'} = 0; return; } sub tear_down { my $self = $_[0]; $self->SUPER::tear_down(); rmtree( $self->{'tmpdir'}, 0 ) unless $self->{'keep_tmpdir'}; return; } sub test_write_report { my $self = $_[0]; my $report = new Lire::Report(); $report->add_section( new Lire::Report::Section( 'Section 1' ) ); $report->add_section( new Lire::Report::Section( 'Section 2' ) ); create_file( "$self->{'tmpdir'}/font.tex", '' ); $self->{'writer'}->set_result( 'write_header', '' ); $self->{'writer'}->set_result( 'write_titlepage', '' ); $self->{'writer'}->set_result( 'write_section', '' ); $self->{'writer'}->set_result( 'write_appendix', '' ); $self->{'writer'}->set_result( 'process_latex', '' ); $self->{'writer'}{'_fh'} = undef; $self->{'writer'}->write_report( $report, "$self->{'tmpdir'}/report.pdf", 'pdf', "$self->{'tmpdir'}/font.tex" ); $self->assert_str_equals( 'pdf', $self->{'writer'}{'_format'} ); $self->assert_str_equals( "$self->{'tmpdir'}/report.pdf", $self->{'writer'}{'_outputfile'}, ); $self->assert_str_equals( $self->{'tmpdir'}, $self->{'writer'}{'_outputdir'} ); $self->assert_str_equals( "$self->{'tmpdir'}/report", $self->{'writer'}{'_outputbase'}, ); $self->assert_str_equals( "$self->{'tmpdir'}/font.tex", $self->{'writer'}{'_preamble'}, ); $self->assert_not_null( $self->{'writer'}{'_fh'}, "missing _fh attribute" ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_header' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_titlepage' ) ); $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_section' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_appendix' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'process_latex' ) ); } sub test_write_header { my $self = $_[0]; $self->{'cfg'}{'unicode.tex'} = '/usr/share/lire/tex/unicode.tex'; $self->{'writer'}{'_preamble'} = 'font.tex'; $self->{'writer'}{'_format'} = 'pdf'; $self->{'writer'}->write_header(); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->assert_str_equals( <title( '{My report}' ); my $start = timelocal( 0, 0, 0, 1, 0, 2004 ); my $time = timelocal( 15, 15, 3, 2, 0, 2004 ); $report->timespan_start( $start ); $report->timespan_end( $start + 86400); $report->date( $time ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_titlepage( $report ); $self->assert_str_equals( <<'EOF', $$buf ); \title{\{My report\}} \author{} \date{Report for 2004-01-01 00:00 -- 2004-01-02 00:00\\ Report generated 2004-01-02 03:15} \maketitle \tableofcontents EOF } sub test_write_section { my $self = $_[0]; my $section = new Lire::Report::Section( '{Section title}' ); $section->description( 'Section description' ); my $sub1 = new Lire::Report::Subreport( 'test', 'test1' ); $sub1->id( 'test-test1' ); $section->add_subreport( $sub1 ); my $sub2 = new_missing Lire::Report::Subreport( 'test', 'test2', 'No good reason' ); $sub2->id( 'test-test2' ); $section->add_subreport( $sub2 ); $self->{'writer'}->set_result( 'write_subreport', '' ); $self->{'writer'}->set_result( 'write_missing_subreport', '' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_section( $section ); $self->assert_str_equals( <<'EOF', $$buf ); \chapter{\{Section title\}} Section description EOF $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_subreport' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_missing_subreport' ) ); } sub test_write_missing_subreport { my $self = $_[0]; my $sub = new_missing Lire::Report::Subreport( 'test', 'test1', '{No good reason}' ); $sub->title( '{My subreport}' ); $sub->description( 'Description' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_missing_subreport( $sub ); $self->assert_str_equals( <<'EOF', $$buf ); \section{\{My subreport\}} \emph{This report is missing: \{No good reason\}} EOF } sub set_up_chart_configs { my $self = $_[0]; $self->{'cfg'}{'_lr_config_spec'} = new Lire::Config::ConfigSpec(); $self->set_up_plugin_mgr(); my $type = new_proxy Lire::Test::Mock( 'Lire::ChartType' ); $type->set_result( 'name' => 'mock_chart', 'write_chart' => sub { return '/tmp/chart.eps' } ); Lire::PluginManager->register_plugin( $type ); $self->{'mock_chart'} = $type; $self->{'cfg'}{'lr_chart_font'} = ''; $self->{'chart1'} = new Lire::Report::ChartConfig(); $self->{'chart1'}->type( $type ); $self->{'chart2'} = new Lire::Report::ChartConfig(); $self->{'chart2'}->type( $type ); return; } sub test_write_subreport { my $self = $_[0]; $self->set_up_chart_configs(); my $subreport = new Lire::Report::Subreport( 'test', 'test1' ); $subreport->title( "{Subreport's Title}" ); $subreport->description( "Subreport's description" ); $subreport->add_chart_config( $self->{'chart1'} ); $subreport->add_chart_config( $self->{'chart2'} ); $self->{'writer'}->set_result( 'write_chart', '' ); $self->{'writer'}->set_result( 'write_table_header', '' ); $self->{'writer'}->set_result( 'write_table_entries', '' ); $self->{'writer'}->set_result( 'write_table_footer', '' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_subreport( $subreport ); $self->assert_str_equals( <<'EOF', $$buf ); \section{\{Subreport's Title\}} Subreport's description EOF $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_chart' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_header' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_entries' ) ); $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_footer' ) ); } sub test_write_chart { my $self = $_[0]; $self->set_up_chart_configs(); my $subreport = new Lire::Report::Subreport( 'test', 'test1' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}{'_outputdir'} = $self->{'tmpdir'}; $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} ); $self->assert_str_equals( <<'EOF', $$buf ); \begin{center} \includegraphics{chart.eps} \end{center} EOF $self->assert_deep_equals( [ $self->{'mock_chart'}, $self->{'chart1'}, $subreport, 'outputdir', $self->{'tmpdir'}, 'format', 'eps', 'font', '/Helvetica', ], $self->{'mock_chart'}->get_invocation( 'write_chart' ) ); $self->assert_deep_equals( [ '/tmp/chart.eps' ], $self->{'writer'}{'_chart_files'} ); $self->{'cfg'}{'lr_chart_font'} = '/Times-New-Roman'; $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} ); $self->assert_deep_equals( [ $self->{'mock_chart'}, $self->{'chart1'}, $subreport, 'outputdir', $self->{'tmpdir'}, 'format', 'eps', 'font', '/Times-New-Roman', ], $self->{'mock_chart'}->get_invocation( 'write_chart', 1 ) ); $self->{'mock_chart'}->set_result( 'write_chart', sub { die "An error occured\n" } ); $$buf = ''; $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} ); $self->assert_str_equals( <<'EOF', $$buf ); \emph{An error occured while generating the chart: An error occured } EOF $self->{'mock_chart'}->set_result( 'write_chart', sub { return undef } ); $$buf = ''; $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} ); $self->assert_str_equals( '', $$buf ); return; } sub set_up_subreport { my $self = $_[0]; my $subreport = new Lire::Report::Subreport( 'test', 'test1' ); my $table_info = new Lire::Report::TableInfo(); $table_info->create_column_info( 'user', 'categorical', 'string', '{User}' ); my $group = $table_info->create_group_info( 'group1' ); $group->create_column_info( 'file', 'categorical', 'string', '{File}' ); $group->create_column_info( 'count', 'numerical', 'int', 'Downloads' ); $group->create_column_info( 'size', 'numerical', 'bytes', 'Size' ); $table_info->compute_group_layout(); $subreport->table_info( $table_info ); $subreport->schemas( 'test' ); $self->{'subreport'} = $subreport; return; } sub test_write_table_header { my $self = $_[0]; $self->init(); $self->set_up_test_schema(); $self->set_up_subreport(); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_table_header( $self->{'subreport'} ); $self->assert_str_equals( <<'EOF', $$buf ); \begin{longtable}{|llrr|} \hline \multicolumn{2}{|l}{\bfseries \hyperlink{test:user}{\{User\}}} & \bfseries Downloads & \bfseries Size\\ & \bfseries \hyperlink{test:file}{\{File\}} & & \\ \hline \endhead EOF return; } sub test_write_table_footer { my $self = $_[0]; $self->set_up_subreport(); $self->{'subreport'}->nrecords( 100 ); $self->{'subreport'}->set_summary_value( 'count', 'content' => '356' ); $self->{'subreport'}->set_summary_value( 'size', 'value' => 1024 * 1024, 'content' => '1$' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_table_footer( $self->{'subreport'} ); $self->assert_str_equals( <<'EOF', $$buf ); \hline \multicolumn{4}{r}{\emph{continued on next page}} \endfoot \hline \multicolumn{2}{|l}{\emph{Total for 100 records}} & 356 & 1\$\\ \hline \endlastfoot EOF } sub set_up_subreport_data { my $self = $_[0]; my $data = [ [ 'flacoste', undef, 9, 53 ], [ undef, 'page1.html', 5, 50 ], [ undef, 'page2.html', 4, 3 ], [ '{wsourdeau}', undef, 5, 10 ], [ undef, 'page3.html$', 3, 6 ], [ undef, 'page2.html', 1, 2 ], [ undef, 'page4.html', 1, 2 ] ]; my $group; foreach my $r ( @$data ) { my ( $user, $page, $count, $size ) = @$r; if ( $user ) { my $entry = $self->{'subreport'}->create_entry(); $entry->add_name( $user ); $group = $entry->create_group(); $group->set_summary_value( 'count', 'content' => $count ); $group->set_summary_value( 'size', 'content' => $size ); } else { my $entry = $group->create_entry(); $entry->add_name( $page ); $entry->add_value( 'content' => $count ); $entry->add_value( 'content' => $size ); } } $self->{'subreport'}->finalize(); } sub test_write_table_entries { my $self = $_[0]; $self->set_up_subreport(); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_table_entries( $self->{'subreport'} ); $self->assert_str_equals( <<'EOF', $$buf ); \multicolumn{4}{|l|}{\emph{There is no entries in this table.}}\\ \end{longtable} EOF $self->set_up_subreport_data(); $$buf = ''; $self->{'writer'}->write_table_entries( $self->{'subreport'} ); $self->assert_str_equals( <<'EOF', $$buf ); \multicolumn{2}{|l}{flacoste} & 9 & 53\\ & page1.html & 5 & 50\\ & page2.html & 4 & 3\\ \multicolumn{2}{|l}{\{wsourdeau\}} & 5 & 10\\ & page3.html\$ & 3 & 6\\ & page2.html & 1 & 2\\ & page4.html & 1 & 2\\ \end{longtable} EOF } sub test_write_appendix { my $self = $_[0]; my $report = new Lire::Report(); my $sect = new Lire::Report::Section( 'Title' ); $report->add_section( $sect ); my $sub = new Lire::Report::Subreport( 'test', 'top-dirs' ); $sub->id( 'top-dirs.0' ); $sub->schemas( 'test', 'test-extended' ); $sect->add_subreport( $sub ); $self->{'writer'}->set_result( 'write_schema', '' ); my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_appendix( $report ); $self->assert_str_equals( "\\appendix\n", $$buf ); $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_schema' ) ); } sub test_write_schema { my $self = $_[0]; my $test_schema = new Lire::DlfSchema( 'superservice' => 'test', 'timestamp' => 'time' ); $test_schema->title( '{A title}' ); $test_schema->description( 'A description.' ); $test_schema->add_field( new Lire::Field( 'name' => 'time', 'type' => 'timestamp', 'label' => '{Time}', 'description' => 'The time field.' ) ); $test_schema->add_field( new Lire::Field( 'name' => 'field_1', 'type' => 'string', 'label' => 'Field 1', 'description' => 'The first field.' ) ); local $Lire::DlfSchema::SCHEMA_CACHE{'test'} = $test_schema; my $buf = $self->{'writer'}{'_fh'}->sref(); $self->{'writer'}->write_schema( 'test' ); $self->assert_str_equals( <<'EOF', $$buf ); \chapter{\{A title\}} A description. \begin{description} \item[\hypertarget{test:time}{\{Time\}}] The time field. \item[\hypertarget{test:field_1}{Field 1}] The first field. \end{description} EOF } sub set_up_write_report { my $self = $_[0]; $self->init(); $self->set_up_test_schema(); $self->set_up_chart_types(); $self->{'keep_tmpdir'} = $ENV{'KEEP_LATEX'}; my $spec = $self->{'cfg'}{'_lr_config_spec'}; $self->{'cfg'}{'unicode.tex'} = "$self->{'testdir'}/../../../extras/unicode.tex"; $self->{'cfg'}{'lambda_path'} = $spec->get( 'lambda_path' )->default()->as_value(); $self->{'cfg'}{'odvips_path'} = $spec->get( 'odvips_path' )->default()->as_value(); $self->{'cfg'}{'ps2pdf_path'} = $spec->get( 'ps2pdf_path' )->default()->as_value(); my $parser = new Lire::ReportParser::ReportBuilder(); $self->{'report'} = $parser->parsefile( "$self->{'testdir'}/data/TestReport_daily_jan25_2003.xml" ); $self->{'writer'} = new Lire::ReportParser::LaTeXWriter(); } sub test_write_report_latex { my $self = $_[0]; $self->set_up_write_report(); $self->{'writer'}->write_report( $self->{'report'}, "$self->{'tmpdir'}/report.tex", 'latex' ); $self->assert( -s "$self->{'tmpdir'}/report.tex", "missing '$self->{'tmpdir'}/report.tex'" ); print "\nLaTeX report generated in $self->{'tmpdir'}/report.tex\n" if $self->{'keep_tmpdir'}; } sub test_write_report_dvi { my $self = $_[0]; $self->set_up_write_report(); $self->assert( $self->{'cfg'}{'lambda_path'}, "Can't test without lambda" ); $self->{'writer'}->write_report( $self->{'report'}, "$self->{'tmpdir'}/report.dvi", 'dvi' ); $self->assert( -s "$self->{'tmpdir'}/report.dvi", "missing '$self->{'tmpdir'}/report.dvi'" ); $self->assert( ! -f "$self->{'tmpdir'}/report.tex", "file $self->{'tmpdir'}/report.tex wasn't removed" ); $self->assert( ! -f "$self->{'tmpdir'}/report.log", "temporary $self->{'tmpdir'}/report.log wasn't removed" ); $self->assert( ! -f "$self->{'tmpdir'}/report.aux", "temporary $self->{'tmpdir'}/report.aux wasn't removed" ); print "\nDVI report generated in $self->{'tmpdir'}/report.dvi\n" if $self->{'keep_tmpdir'}; } sub test_write_report_ps { my $self = $_[0]; $self->set_up_write_report(); $self->assert( $self->{'cfg'}{'lambda_path'}, "Can't test without lambda" ); $self->assert( $self->{'cfg'}{'odvips_path'}, "Can't test without odvips" ); $self->{'writer'}->write_report( $self->{'report'}, "$self->{'tmpdir'}/report.ps", 'ps' ); $self->assert( -s "$self->{'tmpdir'}/report.ps", "missing '$self->{'tmpdir'}/report.ps'" ); $self->assert( ! -f "$self->{'tmpdir'}/report.dvi", "temporary $self->{'tmpdir'}/report.dvi wasn't removed" ); print "\nPS report generated in $self->{'tmpdir'}/report.ps\n" if $self->{'keep_tmpdir'}; } sub test_write_report_pdf { my $self = $_[0]; $self->set_up_write_report(); $self->assert( $self->{'cfg'}{'lambda_path'}, "Can't test without lambda" ); $self->assert( $self->{'cfg'}{'odvips_path'}, "Can't test without odvips" ); $self->assert( $self->{'cfg'}{'ps2pdf_path'}, "Can't test without ps2pdf" ); $self->{'writer'}->write_report( $self->{'report'}, "$self->{'tmpdir'}/report.pdf", 'pdf' ); $self->assert( -s "$self->{'tmpdir'}/report.pdf", "missing '$self->{'tmpdir'}/report.pdf'" ); $self->assert( ! -f "$self->{'tmpdir'}/report.ps", "temporary $self->{'tmpdir'}/report.ps wasn't removed" ); print "\nPDF report generated in $self->{'tmpdir'}/report.pdf\n" if $self->{'keep_tmpdir'}; } 1;