### ----------------------------------------------------
### -- Commands
### -- Licenses: Artistic-2.0
### -- Authors: Elizabeth Mattijsen
### -- File: t/01-basic.rakutest
### ----------------------------------------------------
use Test;
use Commands;

plan 36;

class Catcher {
    has @!seen;

    method print(*@parts --> True) { @!seen.push: @parts.Str.chomp }
    method seen() { @!seen.splice }
}

my $out := Catcher.new;
my $err := Catcher.new;
my $sys := Catcher.new;

my constant %help =
  quit  => "quit the editor",
  shout => "say input in capitals with exclamation mark",
;
sub help($_) {
    state $help = $*COMMANDS.extended-help-from-hash(%help);
    if .skip.join(" ") -> $deeper {
        $help.process($deeper)
    }
    else {
        .say for $*COMMANDS.primaries;
    }
}

my $commands = Commands.new:
  default => { note "default: '$*INPUT'" },
  commands => (
    quit          => { say $*INPUT },
    exit          => "quit",
    "release all" => { say "all released" },
    release       => { say "released $_.[1]" },
    red           => { say "save" },
    shout         => { say .skip.uc ~ "!" },
    ""            => { say "same" },
    &help,
  ),
  commandifier => *.split(";").map(*.trim),
  :$out, :$err, :$sys,
;

sub check(Str:D $input, **@expected) is test-assertion {

    $commands.process($input);

    subtest "command: '$input'" => {
        plan 3;

        my @out := @expected[0];
        my @err := @expected[1] // [];
        my @sys := @expected[2] // [];

        is-deeply $out.seen, @out, "out";
        is-deeply $err.seen, @err, "err";
        is-deeply $sys.seen, @sys, "sys";
    }
}

is-deeply $commands.primaries,
  <<exit help quit red release "release all" shout>>,
  'check primaries';
is-deeply $commands.aliases,
  (quit => [<exit>],).Map,
  'check aliases';

#- basic command tests ---------------------------------------------------------

check "", ["same"];

check "quit foo", ["quit foo"];
check "quit",     ["quit"];
check "qui",      ["qui"];
check "qu",       ["qu"];
check "q",        ["q"];

check "exit foo", ["exit foo"];
check "exit",     ["exit"];
check "exi",      ["exi"];
check "ex",       ["ex"];
check "e",        ["e"];

check "release   all", ["all released"];
check "r  all",        ["all released"];

check "release   42", ["released 42"];
check "rel  42",      ["released 42"];

check "red", ["save"];

check "shout hello  there", ["HELLO THERE!"];
check "s     hello  there", ["HELLO THERE!"];

#- help ------------------------------------------------------------------------

check "help", [
  "exit", "help", "quit", "red", "release", "release all", "shout"
];
check "help q", [
  "More information about: quit\n%help<quit>"
];
check "help exit", [
  "More information about: exit\n%help<quit>"
];
check "help shout", [
  "More information about: shout\n%help<shout>"
];
check "help foo bar", [
  "No extended help available for: foo bar"
];

#- default handling ------------------------------------------------------------

check Q|  foo  |,          [], ["default: 'foo'"];
check Q|my $a = 666|,      [], [Q|default: 'my $a = 666'|];
check Q|my $a = 666 ; $a|, [], [Q|default: 'my $a = 666'|, Q|default: '$a'|];

#- error handling --------------------------------------------------------------

check "r  foo  bar", [], [], [
  "Ambigous command 'r  foo  bar', matches:", "  red", "  release"
];

#- resolving commands ----------------------------------------------------------

for <s sh sho shou shout> {
    is $commands.resolve-command($_), "shout", "'$_' resolved to 'shout'";
}
is-deeply $commands.resolve-command('re'), Nil,
  "'re' did not resolve as it is ambiguous";
is-deeply $commands.resolve-command('xxx'), Nil,
  "'xxx' did not resolve as it is unknown";

# vim: expandtab shiftwidth=4


