package tests::ConfigParserTest;

use strict;

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

use Lire::Config::Value;
use Lire::Config::Parser;
use Lire::Config::TypeSpec;
use Lire::Config::Dictionary;
use Lire::Config::Plugin;
use Lire::Utils qw/tempdir create_file /;
use Lire::Test::Mock;

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

    $self->{'tmpdir'} = tempdir( "config_XXXXXX", 'CLEANUP' => 1 );

    my $spec = $self->{'other_spec'} = new Lire::Config::ConfigSpec();
    my $plugin = new Lire::Config::PluginSpec( 'name' => 'plugin' );
    $spec->add( $plugin );
    $plugin->add( new Lire::Config::OptionSpec( 'name' => 'option_1' ) );
    $spec->add( new Lire::Config::RecordSpec( 'name' => 'option_1_properties') );

    return $self;
}

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

    my $spec = $self->{'config_spec'} = new Lire::Config::ConfigSpec();

    $spec->add( new Lire::Config::BooleanSpec( 'name' => 'bool_param' ) );
    $spec->add( new Lire::Config::IntegerSpec( 'name' => 'int_param' ) );
    $spec->add( new Lire::Config::DirectorySpec( 'name' => 'dir_param' ) );
    $spec->get( 'dir_param' )->default( $spec->get( 'dir_param' )->instance( 'value' => '/a_dir' ) );
    $spec->add( new Lire::Config::ExecutableSpec( 'name' => 'executable_param' ) );
    $spec->add( new Lire::Config::FileSpec( 'name' => 'file_param' ) );

    $spec->add( new Lire::Config::SelectSpec( 'name' => 'select_param' ) );
    my $select_param = $spec->get( 'select_param' );
    $select_param->add( new Lire::Config::OptionSpec( 'name' => 'option_1' ) );
    $select_param->add( new Lire::Config::OptionSpec( 'name' => 'option_2' ) );

    $spec->add( new Lire::Config::ListSpec( 'name' => 'list_param' ) );
    $spec->get( 'list_param' )->add( new Lire::Config::StringSpec( 'name' => 'string_param' ) );
    # Make sure that value overrides the default
    my $list_default = $spec->get( 'list_param' )->instance();
    $list_default->append( $list_default->spec()->get( 'string_param' )->instance( 'value' => 'Default' ) );
    $spec->get( 'list_param' )->default( $list_default );

    $spec->add( new Lire::Config::PluginSpec( 'name' => 'plugin_param' ) );
    my $plugin_param = $spec->get( 'plugin_param' );
    $plugin_param->add( new Lire::Config::OptionSpec( 'name' => 'option_1' ) );
    $plugin_param->add( new Lire::Config::OptionSpec( 'name' => 'option_2' ) );

    $spec->add( new Lire::Config::RecordSpec( 'name' => 'option_2_properties' ) );
    $spec->get( 'option_2_properties' )->add( new Lire::Config::IntegerSpec( 'name' => 'option_2_int' ) );
}

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

    $self->{'config_file'} = "$self->{'tmpdir'}/config.xml";
    create_file( $self->{'config_file'}, <<CONFIG );
<config xmlns="http://www.logreport.org/LRCML/">
 <global>
  <param name="bool_param">yes</param>
  <param name="int_param" value="10"/>
  <param name="file_param">$self->{'config_file'}</param>
  <param name="dir_param">$self->{'tmpdir'}</param>
  <param name="executable_param">/bin/sh</param>

  <param name="list_param">
   <param name="string_param">string1</param>
   <param name="string_param">string2 &lt; a long string with an entity</param>
  </param>

  <param name="select_param">option_2</param>
  <param name="plugin_param" value="option_2">
    <param name="option_2_int" value="10"/>
  </param>
 </global>
</config>
CONFIG
}


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

    my $spec = $self->{'config_spec'};
    my $cfg = new Lire::Config::ConfigFile( 'spec'     => $spec,
                                            'filename' => $self->{'config_file'},
                                          );
    my $global = $self->{'config_spec'}->instance();
    $cfg->global( $global );

    $global->set( $spec->get( "bool_param" )->instance( 'value' => "yes" ));
    $global->set( $spec->get( "int_param" )->instance( 'value' => 10 ));
    $global->set( $spec->get( "dir_param" )->instance( 'value' => $self->{'tmpdir'} ));
    $global->set( $spec->get( "file_param" )->instance( 'value' => $self->{'config_file'} ));
    $global->set( $spec->get( "executable_param" )->instance( 'value' => "/bin/sh" ));
    $global->set( $spec->get( "select_param" )->instance( 'value' => "option_2" ));
    my $list_spec = $spec->get( 'list_param' );
    my $list = $list_spec->instance();
    $list->clear();
    $global->set( $list );
    $list->append( $list_spec->get( "string_param" )->instance( 'value' => "string1" ));
    $list->append( $list_spec->get( "string_param" )->instance( 'value' => "string2 < a long string with an entity" ));

    $global->set( $spec->get( "plugin_param" )->instance( 'value' => "option_2" ));
    $global->get( 'plugin_param' )->set_plugin( 'option_2' );
    $global->get( 'plugin_param' )->set( $spec->get( 'option_2_properties' )->get( 'option_2_int' )->instance( 'value' => 10 ));

    return $cfg;
}

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

    $self->{'cfg'}{'_lr_config_spec'} = $self->{'other_spec'};

    return;
}

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

    return;
}

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

    my $spec = new Lire::Config::ConfigSpec();
    my $parser = new Lire::Config::Parser( 'spec' => $spec );
    $self->assert_isa( 'Lire::Config::Parser', $parser );
    $self->assert_str_equals( $spec, $parser->{'spec'} );
}

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

    $self->set_up_config_spec();
    $self->{'cfg'}{'_lr_config_spec'} = $self->{'config_spec'};
    $self->set_up_config();

    my $parser = new Lire::Config::Parser( 'spec' => $self->{'config_spec'} );
    my $conf = $parser->load_config_file( "$self->{'config_file'}" );
    $self->assert_not_null( $conf,
                            "load_config_file() returned undef" );

    $self->assert_deep_equals( $self->_build_expected_config(), $conf );
}

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

    my $parser =
      new_proxy Lire::Test::Mock( 'Lire::Config::Parser',
                                  'spec' => $self->{'other_spec'} );
    $parser->set_result( 'depth', 0 );
    $parser->init_stack( 'config_spec' );
    $parser->init_stack( 'config_value' );
    $parser->stack_push( 'config_value', $self->{'other_spec'}->instance() );
    $parser->stack_push( 'config_spec', $self->{'other_spec'} );

    $parser->param_start( 'param', { 'name' => 'plugin' ,
                                     'value' => 'option_1' } );
    $self->assert_str_equals( $self->{'other_spec'}->get( 'option_1_properties' ),
                              $parser->stack_peek( 'config_spec' ) );
    $self->assert_deep_equals( $self->{'other_spec'}->get( 'plugin' )->instance( 'value' => 'option_1' ),
                               $parser->stack_peek( 'config_value' ) );
}

1;


syntax highlighted by Code2HTML, v. 0.9.1