#/usr/bin/env perl

use common::sense;
use warnings FATAL => q(all);
use English qw[-no_match_vars];
use List::Util qw[shuffle];
use Test::More;

my $class = q(App::BoolFindGrep::Bool);
use_ok($class) || say q(Bail out!);

my $obj = $class->new();

my @test = (
    [ q{a},     [ [ q(OPERAND), q(a), ] ], ],
    [ q{\(a\)}, [ [ q(OPERAND), q(\\(a\\)), ], ], ],
    [   q{(a)},
        [   [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{a AND b},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERAND),  q(b), ],
        ],
    ],
    [   q{a OR b},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERAND),  q(b), ],
        ],
    ],
    [   q{a AND NOT b},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERATOR), q(NOT), ],
            [ q(OPERAND),  q(b), ],
        ],
    ],
    [   q{a AND NOT b OR NOT c},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERATOR), q(NOT), ],
            [ q(OPERAND),  q(b), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERATOR), q(NOT), ],
            [ q(OPERAND),  q(c), ],
        ],
    ],
    [   q{a AND b AND c AND d},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERAND),  q(b), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERAND),  q(c), ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERAND),  q(d), ],
        ],
    ],
    [   q{a OR b OR c OR d},
        [   [ q(OPERAND),  q(a), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERAND),  q(b), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERAND),  q(c), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERAND),  q(d), ],
        ],
    ],
    [ q{NOT a}, [ [ q(OPERATOR), q(NOT), ], [ q(OPERAND), q(a), ], ], ],
    [   q{NOT (a AND b AND c)},
        [   [ q(OPERATOR),    q(NOT), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(c), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{NOT (a OR b OR c)},
        [   [ q(OPERATOR),    q(NOT), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(c), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{NOT NOT NOT a},
        [   [ q(OPERATOR), q(NOT), ],
            [ q(OPERATOR), q(NOT), ],
            [ q(OPERATOR), q(NOT), ],
            [ q(OPERAND),  q(a), ],
        ],
    ],
    [   q{(a AND b) OR c},
        [   [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(b), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(c), ],
        ],
    ],
    [   q{a AND (b OR c)},
        [   [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(c), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{(a OR b) AND c},
        [   [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(b), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(c), ],
        ],
    ],
    [   q{a OR (b AND c)},
        [   [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(c), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{(a AND b) OR (c AND d)},
        [   [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(b), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(OPERATOR),    q(OR), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(c), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(d), ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{a AND NOT ((b AND c) OR (d AND e))},
        [   [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERATOR),    q(NOT), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(c), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(OPERATOR),    q(OR), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(d), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERAND),     q(e), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(PARENTHESIS), q{)}, ]
        ],
    ],
    [   q{a AND NOT (b AND (c OR d))},
        [   [ q(OPERAND),     q(a), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(OPERATOR),    q(NOT), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(b), ],
            [ q(OPERATOR),    q(AND), ],
            [ q(PARENTHESIS), q{(}, ],
            [ q(OPERAND),     q(c), ],
            [ q(OPERATOR),    q(OR), ],
            [ q(OPERAND),     q(d), ],
            [ q(PARENTHESIS), q{)}, ],
            [ q(PARENTHESIS), q{)}, ],
        ],
    ],
    [   q{/a AND b\// OR /c AND NOT d/},
        [   [ q(OPERAND),  q(a AND b/), ],
            [ q(OPERATOR), q(OR), ],
            [ q(OPERAND),  q(c AND NOT d), ],
        ],
    ],
    [   q{/(a - b)^2/ AND /(c * d)/},
        [   [ q(OPERAND),  q{(a - b)^2}, ],
            [ q(OPERATOR), q(AND), ],
            [ q(OPERAND),  q{(c * d)}, ],
        ],
    ],
    [ q{()},       [ q(Syntax Error in expression), ], ],
    [ q{(())},     [ q(Syntax Error in expression), ], ],
    [ q{() ()},    [ q(Syntax Error in expression), ], ],
    [ q{a AND (b}, [ q(Syntax Error in expression), ], ],
    [ q{a) OR b},  [ q(Syntax Error in expression), ], ],
    [ q{//},       [ q(Syntax Error in expression), ], ],
    [ q{///},      [ q(Syntax Error in expression), ], ],
    [ q{////},     [ q(Syntax Error in expression), ], ],
    [ q{// //},    [ q(Syntax Error in expression), ], ],
    [ q{\/\/},     [ [ q(OPERAND), q(//) ] ] ]
);

my $method = q(parse_expr);
foreach my $test ( shuffle @test ) {
    my ( $input, $expected ) = @$test;
    my $testname = sprintf q(%s:'%s'), $method, $input;
    $obj->slash_as_delim(1);
    $obj->expression($input);
    local $EVAL_ERROR;
    eval { $obj->$method(); };
    my $output
        = $EVAL_ERROR
        ? [ ( split m{:}msx, $EVAL_ERROR )[0] ]
        : $obj->parse();
    is_deeply( $output, $expected, $testname );
}

done_testing();

# Local Variables:
# mode: perl
# coding: utf-8-unix
# End:
