App-karr

 view release on metacpan or  search on metacpan

t/51-json-output.t  view on Meta::CPAN

    $@;
  };
  return ( $err, $out );
}

subtest 'Task->to_json_hash: frontmatter plus body only when body is set' => sub {
  my $with = App::karr::Task->new( id => 1, title => 'Alpha', body => 'hello' );
  my $h    = $with->to_json_hash;
  is( $h->{id},    1,       'id carried through from frontmatter' );
  is( $h->{title}, 'Alpha', 'title carried through from frontmatter' );
  is( $h->{body},  'hello', 'body key present when body is non-empty' );

  my $without = App::karr::Task->new( id => 2, title => 'Beta' );
  my $h2      = $without->to_json_hash;
  is( $h2->{id}, 2, 'frontmatter still built when body is empty' );
  ok( !exists $h2->{body}, 'body key absent when body is empty' );
};

subtest 'move --json: single id is a bare object, batch is an array' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Alpha', status => 'todo' );

  my $cmd = App::karr::Cmd::Move->new( store => $store, json => 1 );
  my ( $err, $out ) = _run_execute( $cmd, '1', 'done' );
  is( $err, '', 'move 1 done --json does not die' ) or diag $err;

  my $data = eval { decode_json($out) };
  is( ref $data, 'HASH', 'single move --json emits a bare JSON object' ) or diag $out;
  is( $data->{id},         1,      'object carries the moved id' );
  is( $data->{old_status}, 'todo', 'old_status reported' );
  is( $data->{new_status}, 'done', 'new_status reported' );

  my $store2 = _fresh_store();
  _save( $store2, id => 1, title => 'Alpha', status => 'todo' );
  _save( $store2, id => 2, title => 'Beta',  status => 'todo' );

  my $cmd2 = App::karr::Cmd::Move->new( store => $store2, json => 1 );
  my ( $err2, $out2 ) = _run_execute( $cmd2, '1,2', 'done' );
  is( $err2, '', 'move 1,2 done --json does not die' ) or diag $err2;

  my $arr = eval { decode_json($out2) };
  is( ref $arr,       'ARRAY', 'batch move --json emits a JSON array' ) or diag $out2;
  is( scalar @$arr,   2,       'one array entry per moved task' );
  is( $arr->[0]{id},  1,       'first entry is task 1' );
  is( $arr->[1]{id},  2,       'second entry is task 2' );
};

subtest 'move without --json: print_json_results is a no-op (guard)' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Alpha', status => 'todo' );

  my $cmd = App::karr::Cmd::Move->new( store => $store );
  my ( $err, $out ) = _run_execute( $cmd, '1', 'done' );
  is( $err, '', 'move without --json does not die' );
  like( $out, qr/Moved task 1/, 'human-readable line printed' );

  # A removed guard would leak the results object/array into plain output; the
  # human line itself carries no braces, so any brace means JSON leaked through.
  unlike( $out, qr/[{}]/, 'no JSON emitted when --json is absent' );

  my $decoded = eval { decode_json($out) };
  ok( !defined $decoded, 'plain output is not JSON-decodable' );
};

subtest 'edit --json: single id is a bare object with id and title' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Old title', status => 'todo' );

  my $cmd = App::karr::Cmd::Edit->new(
    store => $store,
    json  => 1,
    title => 'New title',
  );
  my ( $err, $out ) = _run_execute( $cmd, '1' );
  is( $err, '', 'edit 1 --json does not die' ) or diag $err;

  my $data = eval { decode_json($out) };
  is( ref $data,     'HASH',      'single edit --json emits a bare JSON object' ) or diag $out;
  is( $data->{id},    1,          'object carries the edited id' );
  is( $data->{title}, 'New title', 'edited title reflected in the payload' );
};

subtest 'show --json: explicit id renders frontmatter + body via to_json_hash' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Alpha', status => 'todo', body => 'Alpha body' );

  my $cmd = App::karr::Cmd::Show->new( store => $store, json => 1 );
  my ( $err, $out ) = _run_execute( $cmd, '1' );
  is( $err, '', 'show 1 --json does not die' ) or diag $err;

  my $data = eval { decode_json($out) };
  is( ref $data,      'HASH',       'explicit id --json stays a bare object' ) or diag $out;
  is( $data->{id},     1,           'id present' );
  is( $data->{title},  'Alpha',     'title present' );
  is( $data->{status}, 'todo',      'status present' );
  is( $data->{body},   'Alpha body', 'body included when present' );
};

subtest 'pick --json: picked task payload built via to_json_hash' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Alpha', status => 'todo', priority => 'high', body => 'Alpha body' );

  my $cmd = App::karr::Cmd::Pick->new(
    store => $store,
    claim => 'agent-test',
    json  => 1,
  );
  my ( $err, $out ) = _run_execute($cmd);
  is( $err, '', 'pick --json does not die' ) or diag $err;

  my $data = eval { decode_json($out) };
  is( ref $data,          'HASH',       'pick --json emits a bare JSON object' ) or diag $out;
  is( $data->{id},         1,           'picked id present' );
  is( $data->{claimed_by}, 'agent-test', 'claim reflected in payload' );
  is( $data->{body},       'Alpha body', 'body included' );
};

subtest 'handoff --json: review payload built via to_json_hash' => sub {
  my $store = _fresh_store();
  _save( $store, id => 1, title => 'Alpha', status => 'in-progress', body => 'Alpha body' );

  my $cmd = App::karr::Cmd::Handoff->new(



( run in 0.567 second using v1.01-cache-2.11-cpan-9581c071862 )