#!/usr/bin/perl -w

use strict;

use Test::More tests => 65;

use HTML::Widgets::NavMenu::Predicate;

# Spec for this test suite:
# 1. Test the individual components. (bool, re, and cb)
# 2. Test them as non-hashrefed values.
# 3. Test precedence within a hash-ref.

# Test the bool == 0 predicate
{
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 'bool' => 0, },
        );

    # TEST
    ok(!$pred->evaluate(
        'path_info' => "Hoola/Yoola", 
        'current_host' => "default",
    ), "bool==0 test 1");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "bool==0 test 2");
}

# Test the bool == 1 predicate
{
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 'bool' => 1, },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "Hoola/Yoola", 
        'current_host' => "default",
    ), "bool==1 test 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "bool==1 test 2");
}

# Test the regexp evaluation.
{
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 're' => "^hello/(world|good)/", },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/", 
        'current_host' => "default",
    ), "regexp 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/", 
        'current_host' => "default",
    ), "regexp 2");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/some/more/components.html", 
        'current_host' => "default",
    ), "regexp 3");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/other/comps/", 
        'current_host' => "default",
    ), "regexp 4");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "regexp 5 - should be false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/something-else/",
        'current_host' => "default",
    ), "regexp 6 - close, but not enough");
}

# Another regex test - this time without anchors
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 're' => "start(mid|center)+finish", },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/startmidfinish/", 
        'current_host' => "default",
    ), "non-anchored regexp 1");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/good/", 
        'current_host' => "default",
    ), "non-anchored regexp 2");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/startmidcentermidfinish/", 
        'current_host' => "default",
    ), "non-anchored regexp 3");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "startfinish/", 
        'current_host' => "default",
    ), "non-anchored regexp 4");
}

sub predicate_cb1
{
    my %args = (@_);
    my $host = $args{'current_host'};
    my $path = $args{'path_info'};
    return (($host eq "true") && ($path eq "mypath/"));
}

# Test the 'cb' argument
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 'cb' => \&predicate_cb1, },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "true",
    ), "cb 1 - true");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "false",
    ), "cb 2 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/", 
        'current_host' => "true",
    ), "cb 3 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "anuba/", 
        'current_host' => "false",
    ), "cb 4 - both false");
}

# Now testing the non-hashrefed values.

# Test the bool == 0 predicate
{
    # TEST*2*4
    foreach my $false_value (qw(0 no false False))
    {
        my $pred = 
            HTML::Widgets::NavMenu::Predicate->new(
                'spec' => $false_value,
            );

        ok(!$pred->evaluate(
            'path_info' => "Hoola/Yoola",
            'current_host' => "default",
        ), "bool==0 test 1");
        ok(!$pred->evaluate(
            'path_info' => "Shragah/Spinoza/",
            'current_host' => "majesty",
        ), "bool==0 test 2");
    }
}

# Test the bool == 1 predicate
{
    # TEST*2*4
    for my $true_value (qw(1 yes true True))
    {
        my $pred = 
            HTML::Widgets::NavMenu::Predicate->new(
                'spec' => +{ 'bool' => 1, },
            );

        ok($pred->evaluate(
            'path_info' => "Hoola/Yoola", 
            'current_host' => "default",
        ), "bool==1 test 1");
        ok($pred->evaluate(
            'path_info' => "Shragah/Spinoza/",
            'current_host' => "majesty",
        ), "bool==1 test 2");
    }
}

# Test the regexp evaluation.
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => "^hello/(world|good)/",
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/", 
        'current_host' => "default",
    ), "implicit regexp 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/", 
        'current_host' => "default",
    ), "implicit regexp 2");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/some/more/components.html", 
        'current_host' => "default",
    ), "implicit regexp 3");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/other/comps/", 
        'current_host' => "default",
    ), "implicit regexp 4");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "implicit regexp 5 - should be false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/something-else/",
        'current_host' => "default",
    ), "implicit regexp 6 - close, but not enough");
}

# Test the implicit 'cb' argument
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => \&predicate_cb1,
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "true",
    ), "ipmlicit cb 1 - true");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "false",
    ), "ipmlicit cb 2 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/", 
        'current_host' => "true",
    ), "ipmlicit cb 3 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "anuba/", 
        'current_host' => "false",
    ), "ipmlicit cb 4 - both false");
}

##############

# Precendence tests.

# 're' precedes 'bool'
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => 
                +{ 
                    're' => "^hello/(world|good)/", 
                    'bool' => 0,
                },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/", 
        'current_host' => "default",
    ), "re precedes bool 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/", 
        'current_host' => "default",
    ), "re precedes bool 2");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/world/some/more/components.html", 
        'current_host' => "default",
    ), "re precedes bool 3");
    # TEST
    ok($pred->evaluate(
        'path_info' => "hello/good/other/comps/", 
        'current_host' => "default",
    ), "re precedes bool 4");
}

# 'cb' precedes 're'
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => 
                +{ 
                    're' => "^hello/(world|good)/", 
                    'cb' => \&predicate_cb1,
                },
        );

    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/world/",
        'current_host' => "default",
    ), "cb precedes re 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "true",
    ), "cb precedes re 2");
}

# 'cb' precedes 'bool'
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => 
                +{ 
                    'cb' => \&predicate_cb1, 
                    'bool' => 1,
                },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "true",
    ), "cb precedes bool 1 - true");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "false",
    ), "cb precedes bool  2 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/", 
        'current_host' => "true",
    ), "cb precedes bool  3 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "anuba/", 
        'current_host' => "false",
    ), "cb precedes bool 4 - both false");
}

# 'cb' precedes both 'bool' and 're'

{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => 
                +{ 
                    'cb' => \&predicate_cb1, 
                    'bool' => 1,
                    're' => "anuba",
                },
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "true",
    ), "cb precedes bool and re 1 - true");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "mypath/", 
        'current_host' => "false",
    ), "cb precedes bool and re 2 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "hello/", 
        'current_host' => "true",
    ), "cb precedes bool and re 3 - false");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "anuba/", 
        'current_host' => "false",
    ), "cb precedes bool and re 4 - both false");
}

# Test the regexp evaluation when 're' is empty.
{
    my $pred =
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => +{ 're' => "", },
        );

    my $string = "Yowza Cowza Nowza";
    $string =~ s!Yowza!!;

    # TEST
    ok($pred->evaluate(
        'path_info' => "/nothing/here", 
        'current_host' => "default",
    ), "regexp 1");
}

# Test the implicit bool predicate
{
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => 1,
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "Hoola/Yoola", 
        'current_host' => "default",
    ), "bool==1 test 1");
    # TEST
    ok($pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "bool==1 test 2");
}

# Test the implicit regexp predicate
{
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => "^Hoola",
        );

    # TEST
    ok($pred->evaluate(
        'path_info' => "Hoola/Yoola", 
        'current_host' => "default",
    ), "bool==1 test 1");
    # TEST
    ok(!$pred->evaluate(
        'path_info' => "Shragah/Spinoza/",
        'current_host' => "majesty",
    ), "bool==1 test 2");
}

# Test the implicit regexp predicate
{
    eval {
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => { 'hoalsdkasldk' => 1},
        );
    };

    # TEST
    like($@, qr{^Neither}, 
        "Exception should be thrown.");
}

# Test an incorrect spec
{
    eval {
    my $pred = 
        HTML::Widgets::NavMenu::Predicate->new(
            'spec' => [],
        );
    };

    # TEST
    like($@, qr{^Unknown spec type}, 
        "Exception should be thrown.");
}

