App-karr
view release on metacpan or search on metacpan
t/45-options-before-positionals.t view on Meta::CPAN
require_git_c();
use File::Temp qw( tempdir );
use Cwd qw( abs_path getcwd );
use IPC::Open3 qw( open3 );
use Symbol qw( gensym );
use JSON::MaybeXS qw( decode_json );
# Regression tests for karr board ticket #13.
#
# BUG: options placed before (or interleaved around) positional arguments
# break arg parsing, sometimes opaquely: `karr archive --json 1` crashes
# ($args_ref->[0] is "--json", parse_ids/find_task choke on it), `karr
# handoff --claim X 1` treats "--claim" itself as the ID. MooX::Cmd
# echoes parsed option flags AND their consumed values back into argv, so
# every id-taking command that reads $args_ref->[0]/[1] directly (rather
# than through an extractor that understands which tokens are option
# values) is exposed to this.
#
# DESIGN (recorded on ticket #13 after sondation, `karr show 13`): cobra
# parity instead of reject -- flags may appear before, between, or after
# positionals. A central extractor (landing in Role::BoardAccess, using
# MooX::Options' _options_data: format=s options consume the following
# token as a value unless given as --opt=value; flag-only options consume
# nothing) yields the real positionals. The seven #11 commands (show,
# archive, delete, edit, handoff, move, create) read positionals only via
# that extractor; check_positional_args (also from #11/t43) then counts
# real positionals instead of the leading dash-free run. Config/SetRefs/
# GetRefs keep their own arg shapes and are out of scope.
#
# None of this is implemented yet (no lib/ changes accompany this test).
#
# Expected colour map, confirmed by hand against the current tree (VERSION
# 0.304, pre-#13-fix) before writing the assertions below:
#
# RED (must turn GREEN once #13 lands):
# - all five "options-first" subtests in section (a)
# - the "--opt=value" subtest in section (b) -- `handoff --claim=tester 1`
# *also* currently dies ("Task --claim=tester not found"): MooX::Cmd
# echoes the unsplit "--claim=tester" token verbatim, it is never
# recognised as an option at all today.
# - two of the four "Bestandsgarantien" bullets named on the ticket are
# NOT actually green on the current tree, contrary to the ticket text
# (verified by direct CLI probing, see subtests below for detail):
# * `show --last 2` dies today ("Task --last not found") -- Show
# unconditionally reads $args_ref->[0] as the id positional even
# though there are zero real positionals here.
# * `archive --json 1 99` does not reject 99 today (no
# "unexpected extra argument" diagnostic fires at all -- it never
# reaches check_positional_args' reject path); AND
# `archive 1 --json 99` actively regresses -- it exits 0 and
# archives task 1, *silently dropping* the extra "99", because
# today's leading-dash-free-run count stops at "--json" and never
# sees the trailing "99". Both are pinned here as the desired
# post-#13 contract (reject, no side effect), not as already-green.
# These are reported honestly below rather than soft-pedalled to match
# the ticket's colour claims; only `move 1 --next --claim tester` and
# `create --title T` / `create T Extra` were confirmed genuinely green
# on the current tree.
#
# GREEN today (must stay green -- true "Bestandspins"):
# - `edit 1 --append-body "--weird"` (value that looks like a flag)
# - `move 1 --next --claim tester`
# - `create --title T` / `create T Extra`
#
# STDERR assertions for the extra-args-rejection subtests use the same
# `qr/\bTOKEN\b|usage/i` shape as t/43 (mentions the offending token, or a
# usage-style message).
my $ROOT = abs_path('.');
my $BIN = "$ROOT/bin/karr";
sub _run_karr {
my ( $cwd, @argv ) = @_;
my $old = getcwd();
chdir $cwd or die "chdir $cwd: $!";
my $stderr = gensym;
my $pid = open3(
undef,
my $stdout_fh,
$stderr,
$^X,
"-I$ROOT/lib",
$BIN,
@argv,
);
my $stdout = do { local $/; <$stdout_fh> };
my $stderr_text = do { local $/; <$stderr> };
waitpid( $pid, 0 );
my $exit = $? >> 8;
chdir $old or die "chdir $old: $!";
return {
exit => $exit,
stdout => defined $stdout ? $stdout : '',
stderr => defined $stderr_text ? $stderr_text : '',
};
}
sub _git_ok {
my (@cmd) = @_;
my $rc = system(@cmd);
is( $rc, 0, "@cmd" );
}
# Fresh isolated temp repo per subtest, never the developer's real board.
sub _setup_repo {
my $repo = tempdir( CLEANUP => 1 );
_git_ok( 'git', 'init', '-q', $repo );
_git_ok( 'git', '-C', $repo, 'config', 'user.email', 'test@example.com' );
_git_ok( 'git', '-C', $repo, 'config', 'user.name', 'Test User' );
my $init = _run_karr( $repo, 'init', '--name', 'Options-Before-Positionals Board' );
is( $init->{exit}, 0, 'karr init succeeds' ) or diag $init->{stderr};
return $repo;
}
# Seeds tasks 1..$n, titled "Task 1".."Task $n", all in the given status
( run in 0.945 second using v1.01-cache-2.11-cpan-6aa56a78535 )