App-karr
view release on metacpan or search on metacpan
t/49-config-skill-options-first.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use lib 't/lib';
use TestGit qw( require_git_c );
require_git_c();
use TestKarr qw( run_karr );
use File::Temp qw( tempdir );
use JSON::MaybeXS qw( decode_json );
# Regression tests for karr board ticket #17.
#
# BUG: `karr config` and `karr skill` read their action/key/value straight from
# raw argv ($args_ref->[0]/[1]/[2]). MooX::Options runs with protect_argv,
# so an option flag keeps its original position in argv; a flag placed
# before the action makes $args_ref->[0] the flag, not the action:
# karr config --json show -> "Unknown action: --json"
# karr skill --json check -> "Unknown action: --json"
# even though the action-first forms (`config show --json`) work. Same class
# as the already-fixed #13, whose option-aware extractor now lives in
# App::karr::Role::CliArgs.
#
# FIX: both commands read positionals through positional_args (option-aware) and
# enforce arity via check_positional_args. Config keeps action-dependent
# arity (show=1, get KEY=2, set KEY VALUE=3); skill takes exactly one
# positional (the action). `skill --agent NAME check` needs the real parser
# because --agent (format=s) swallows its value -- a naive dash-filter would
# read the agent value as the action.
#
# These subtests drive the real bin/karr via a subprocess, so they exercise the
# actual MooX::Cmd protect_argv argv echo that causes the bug (same harness as
# the #11/#13 regressions in t/43 and t/45). RED before the fix: every
# "options-first" subtest died with "Unknown action: --<flag>"; the surplus-arg
# subtests did not reject (config) / had no arity guard (skill).
#
# JSON equality is checked against the *decoded* structure, not raw bytes:
# print_json is not canonical, so two separate processes can emit the same
# config with different hash key order.
# In-process runner (t/lib/TestKarr.pm): same ($cwd, @argv) signature and
# { exit, stdout, stderr } return as the open3 helper this file used to carry,
# dispatched through the shared App::karr::Dispatch path. KARR_TEST_SUBPROC=1
# restores the old open3 path.
sub _run_karr { return run_karr(@_) }
sub _git_ok {
my (@cmd) = @_;
my $rc = system(@cmd);
is( $rc, 0, "@cmd" );
}
# Fresh isolated temp board per subtest, never the developer's real board.
sub _setup_config_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', 'Config-Options Board' );
is( $init->{exit}, 0, 'karr init succeeds' ) or diag $init->{stderr};
return $repo;
}
# ------------------------------------------------------------------ config ---
subtest 'config --json show: flag before action still runs show (RED, #17)' => sub {
my $repo = _setup_config_repo();
my $rv = _run_karr( $repo, 'config', '--json', 'show' );
is( $rv->{exit}, 0, 'exit 0' ) or diag $rv->{stderr};
unlike( $rv->{stderr}, qr/Unknown action/, 'no "Unknown action: --json" error' );
my $data = eval { decode_json( $rv->{stdout} ) };
ok( $data, 'stdout is valid JSON' )
or diag "stdout: $rv->{stdout}\nstderr: $rv->{stderr}";
is( ref $data, 'HASH', 'JSON is the whole-config object' );
is( $data->{board}{name}, 'Config-Options Board', 'JSON carries the board name' );
};
subtest 'config --json (bare, no action): defaults to show, still JSON (RED, #17)' => sub {
my $repo = _setup_config_repo();
my $rv = _run_karr( $repo, 'config', '--json' );
is( $rv->{exit}, 0, 'exit 0' ) or diag $rv->{stderr};
unlike( $rv->{stderr}, qr/Unknown action/, 'no "Unknown action: --json" error' );
my $data = eval { decode_json( $rv->{stdout} ) };
ok( $data, 'stdout is valid JSON' ) or diag "stdout: $rv->{stdout}";
is( $data->{board}{name}, 'Config-Options Board', 'bare --json defaults to the show output' );
};
subtest 'config --json show and config show --json behave identically (#17)' => sub {
my $repo = _setup_config_repo();
( run in 1.514 second using v1.01-cache-2.11-cpan-364913b4093 )