package tests::ConfigConfigFileTest;

use strict;

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

use Class::Inner;
use Lire::Config::ConfigFile;
use Lire::Config::TypeSpec;
use Lire::Config::Parser;
use Lire::Utils qw/tempfile/;

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

    $self->{'spec'} = new Lire::Config::ConfigSpec( 'label' => 'label_para' );
    $self->{'spec'}->add( new Lire::Config::StringSpec( 'name' => 'param1'));
    $self->{'spec'}->add( new Lire::Config::StringSpec( 'name' => 'param2'));
    $self->{'spec'}->add( new Lire::Config::StringSpec( 'name' => 'param3'));
    $self->{'spec'}->add( new Lire::Config::StringSpec( 'name' => 'label_para'));

    return $self;
}

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

    # We don't call SUPER::set_up() which uses the config
    # api.

    ( $self->{'fh'}, $self->{'filename'} ) =
      tempfile( 'config_XXXXXX', 'SUFFIX' => '.xml' );

    $self->{'config'} = 
      new Lire::Config::ConfigFile( 'spec' => $self->{'spec'},
                                    'filename' => $self->{'filename'},
                                  );
    return;
}

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

    unlink $self->{'filename'};

    return;
}

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

    $self->assert_died( sub { new Lire::Config::ConfigFile() },
                        qr/missing \'spec\' parameter/ );

    $self->assert_died( sub { new Lire::Config::ConfigFile( 'spec' => {} ) },
                        qr/\'spec\' parameter should be a \'Lire::Config::ConfigSpec\' instance, not \'HASH/ );

    $self->assert_died( sub { new Lire::Config::ConfigFile( 'spec' => $self->{'spec'} ) },
                        qr/missing 'filename' parameter/ );

    $self->assert_isa( 'Lire::Config::ConfigFile', $self->{'config'} );

    $self->assert_str_equals( $self->{'spec'}, $self->{'config'}{'spec'} );
    $self->assert_str_equals( $self->{'filename'},
                              $self->{'config'}{'filename'} );
    $self->assert_not_null( UNIVERSAL::isa( $self->{'config'}{'global'},
                                          'Lire::Config::Dictionary' ),
                            "'global' attribute should be initialized" );
}

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

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

    my $cfg = $spec->instance();
    my $string1 = $spec->get( 'param1' )->instance( 'value' => 'wawa value' );
    my $label = $spec->get( 'label_para' )->instance( 'value' => 'config label' );
    $cfg->set( $label );
    $cfg->set( $string1 );

    $self->assert_str_equals( 'wawa value', $string1->as_label() );
    $self->assert_str_equals( 'config label', $cfg->as_label() );

    $string1 = $spec->get( 'param1' )->instance( 'value' => '  wawa ' );
    $cfg->set( $string1 );
    $self->assert_str_equals( 'wawa', $string1->as_label() );

    $label = $spec->get( 'label_para' )->instance( 'value' => '' );
    $cfg->set( $label );
    $self->assert_str_equals( '-- unidentified --', $cfg->as_label() );
    $label = $spec->get( 'label_para' )->instance( 'value' => '   ' );
    $cfg->set( $label );
    $self->assert_str_equals( '-- unidentified --', $cfg->as_label() );
}

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

    $self->assert( UNIVERSAL::isa( $self->{'config'},
                                   'Lire::Config::Dictionary' ),
                   "expected Lire::Config::ConfigFile to support Lire::Config::Dictionary interface" );

    my $methods = {};
    foreach my $name (qw/as_value get is_set set/ ) {
        $methods->{$name} = sub { my $self = shift; $self->{$name} = \@_ };
    }

    my $mock_global =
      new Class::Inner( 'parent' => 'Lire::Config::Dictionary',
                        'args' => [ 'spec' => $self->{'spec'} ],
                        'methods' => $methods );
    $self->{'config'}{'global'} = $mock_global;

    $self->{'config'}->as_value();
    $self->assert_deep_equals( [], $mock_global->{'as_value'} );

    $self->{'config'}->is_set( 'param1' );
    $self->assert_deep_equals( [ 'param1' ], $mock_global->{'is_set'} );

    $self->{'config'}->get( 'param1' );
    $self->assert_deep_equals( [ 'param1' ], $mock_global->{'get'} );

    my $value = $self->{'spec'}->get( 'param1' )->instance();
    $self->{'config'}->set( $value );
    $self->assert_deep_equals( [ $value ], $mock_global->{'set'} );
}

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

    close $self->{'fh'}
      or die "close failed: $!\n";
    $self->assert_num_equals( 0, -s $self->{'filename'} );
    $self->{'config'}->save();
    $self->assert( -s $self->{'filename'},
                   "$self->{'filename'} shouldn't be empty" );
}

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

    $self->assert( ! $self->{'config'}->is_set( 'param1' ),
                   "param1 unexpectedly set" );

    print {$self->{'fh'}} <<EOC;
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE config PUBLIC
  "-//LogReport.ORG//DTD Lire Report Configuration Markup Language V1.0//EN"
  "http://www.logreport.org/LRCML/1.0/lrcml.dtd"[
<!ENTITY % LIRE.xmlns.pfx "">
<!ENTITY % xmlns.colon "">
]>
<config xmlns="http://www.logreport.org/LRCML/">
  <global>
    <param name="param1">A value</param>
  </global>
</config>
EOC
    close $self->{'fh'}
      or die "close failed: $!\n";
    $self->{'config'}->revert();

    $self->assert( $self->{'config'}->is_set( 'param1' ),
                   "param1 should have been initialized from the file" );
    $self->assert_str_equals( 'A value',
                              $self->{'config'}->get( 'param1' )->get() );
}

1;


syntax highlighted by Code2HTML, v. 0.9.1