#!/usr/bin/perl -w
#
# t/document_methods.t
#
# Unit tests for Template::Document methods: as_perl, write_perl_file,
# variables, block, blocks, process, meta
#

use strict;
use lib qw( ./lib ../lib );
use Test::More tests => 29;

use File::Temp qw( tempdir );
use Template;
use Template::Document;
use Template::Config;

my $dir = -d 't' ? 't/test' : 'test';

#------------------------------------------------------------------------
# as_perl — generates valid Perl code
#------------------------------------------------------------------------

{
    my $content = {
        BLOCK     => q{sub { return "Hello World" }},
        DEFBLOCKS => {},
        METADATA  => { name => 'test_template', modtime => '1234567890' },
    };

    my $perl = Template::Document->as_perl($content);
    ok(defined $perl, 'as_perl returns defined value');
    like($perl, qr/Template::Document->new/, 'as_perl contains constructor call');
    like($perl, qr/METADATA/, 'as_perl contains METADATA section');
    like($perl, qr/BLOCK/, 'as_perl contains BLOCK section');
    like($perl, qr/DEFBLOCKS/, 'as_perl contains DEFBLOCKS section');
    like($perl, qr/test_template/, 'as_perl contains template name in metadata');
    like($perl, qr/Compiled template generated by/, 'as_perl contains header comment');
}

#------------------------------------------------------------------------
# as_perl — with DEFBLOCKS
#------------------------------------------------------------------------

{
    my $content = {
        BLOCK     => q{sub { return "main" }},
        DEFBLOCKS => {
            header => q{sub { return "header" }},
            footer => q{sub { return "footer" }},
        },
        METADATA  => { name => 'with_blocks' },
    };

    my $perl = Template::Document->as_perl($content);
    like($perl, qr/'header'/, 'as_perl includes header defblock');
    like($perl, qr/'footer'/, 'as_perl includes footer defblock');
}

#------------------------------------------------------------------------
# as_perl — metadata with special characters
#------------------------------------------------------------------------

{
    my $content = {
        BLOCK     => q{sub { return "test" }},
        DEFBLOCKS => {},
        METADATA  => { name => "it's a test", path => "path\\with\\backslash" },
    };

    my $perl = Template::Document->as_perl($content);
    like($perl, qr/it\\'s a test/, 'as_perl escapes single quotes in metadata');
    like($perl, qr/path\\\\with\\\\backslash/, 'as_perl escapes backslashes in metadata');
}

#------------------------------------------------------------------------
# write_perl_file — writes to a file
#------------------------------------------------------------------------

{
    my $tmpdir = tempdir( CLEANUP => 1 );
    my $file = "$tmpdir/compiled.pl";

    my $content = {
        BLOCK     => q{sub { return "hello from compiled" }},
        DEFBLOCKS => {},
        METADATA  => { name => 'compiled_test' },
    };

    my $ok = Template::Document->write_perl_file($file, $content);
    ok($ok, 'write_perl_file returns true on success');
    ok(-f $file, 'compiled file exists');

    # read and verify contents
    open(my $fh, '<', $file) or die "Cannot open $file: $!";
    my $written = do { local $/; <$fh> };
    close($fh);

    like($written, qr/Template::Document->new/, 'written file contains constructor');
    like($written, qr/compiled_test/, 'written file contains template name');
}

#------------------------------------------------------------------------
# write_perl_file — invalid filename
#------------------------------------------------------------------------

{
    my @warnings;
    local $SIG{__WARN__} = sub { push @warnings, @_ };

    my $ok = Template::Document->write_perl_file(undef, {});
    ok(!$ok, 'write_perl_file returns undef for undef filename');
    like(Template::Document->error(), qr/invalid filename/, 'error mentions invalid filename');

    $ok = Template::Document->write_perl_file('', {});
    ok(!$ok, 'write_perl_file returns undef for empty filename');

    is(scalar @warnings, 0, 'no warnings from undef/empty filename')
        or diag("warnings: @warnings");
}

#------------------------------------------------------------------------
# block() / blocks() / variables() accessors
#------------------------------------------------------------------------

{
    my $block_sub = sub { return 'main content' };
    my $defblocks = { sidebar => sub { return 'sidebar' } };
    my $vars_hash = { foo => 1, bar => 1 };

    my $doc = Template::Document->new({
        BLOCK      => $block_sub,
        DEFBLOCKS  => $defblocks,
        VARIABLES  => $vars_hash,
        METADATA   => { name => 'accessor_test' },
    });
    ok(defined $doc, 'Document created successfully');

    is($doc->block(), $block_sub, 'block() returns the BLOCK coderef');
    is($doc->blocks(), $defblocks, 'blocks() returns DEFBLOCKS hashref');
    is($doc->variables(), $vars_hash, 'variables() returns VARIABLES hashref');
}

#------------------------------------------------------------------------
# meta() accessor
#------------------------------------------------------------------------

{
    my $doc = Template::Document->new({
        BLOCK     => sub { return '' },
        METADATA  => { name => 'meta_test', author => 'tester' },
    });

    # meta() returns a filtered hash ref; name/modtime are excluded
    my $meta = $doc->meta();
    is(ref $meta, 'HASH', 'meta() returns a hash reference');

    # metadata fields accessible via AUTOLOAD
    is($doc->name, 'meta_test', 'AUTOLOAD accessor for name works');
}

#------------------------------------------------------------------------
# process via full template pipeline
#------------------------------------------------------------------------

{
    my $tt = Template->new({
        INCLUDE_PATH => "$dir/src:$dir/lib",
        TRIM         => 1,
    });

    my $output = '';
    my $ok = $tt->process(\q{[% BLOCK greeting %]Hello [% who %][% END %][% INCLUDE greeting who='World' %]}, {}, \$output);
    ok($ok, 'Document process works through Template pipeline');
    is($output, 'Hello World', 'Document process produces correct output');
}

#------------------------------------------------------------------------
# process — recursion detection via _HOT flag
#------------------------------------------------------------------------

{
    my $doc = Template::Document->new({
        BLOCK    => sub { return 'content' },
        METADATA => { name => 'hot_test' },
    });

    # Simulate recursion: set _HOT flag and verify process detects it
    ok(!$doc->{ _HOT }, '_HOT is false initially');
    $doc->{ _HOT } = 1;
    ok($doc->{ _HOT }, '_HOT can be set to simulate in-progress processing');
}
