Git-Native

 view release on metacpan or  search on metacpan

t/60-config-snapshot.t  view on Meta::CPAN

# copy out of an existing handle - was never called, and neither was the
# writable/read-only distinction it creates. That distinction is the whole
# reason config_string goes through a snapshot, so it deserves a test.

my ( $repo, $tmp ) = TestRepo::new_repo();

my $live = $repo->config;
$live->set_string( 'user.name', 'First Name' );

subtest 'Config->snapshot makes a readable copy' => sub {
  my $snap = $live->snapshot;
  isa_ok $snap, ['Git::Native::Config'], 'snapshot returns a Config';
  is $snap->get_string('user.name'), 'First Name', 'the snapshot reads the value';
  is $snap->get_string('not.set'), undef, 'an unset key is undef on a snapshot';
};

subtest 'a snapshot is a point-in-time copy, not a live view' => sub {
  # This is why config_string takes a fresh snapshot on every call: an old
  # snapshot keeps answering with the value it was taken at.
  my $snap = $live->snapshot;
  $live->set_string( 'user.name', 'Second Name' );

  is $snap->get_string('user.name'), 'First Name',
    'the old snapshot still reports the value it was taken at';
  is $repo->config_string('user.name'), 'Second Name',
    'config_string takes a fresh snapshot and sees the new value';
  is $live->snapshot->get_string('user.name'), 'Second Name',
    'a newly taken snapshot sees the new value too';
};

subtest 'a snapshot refuses writes' => sub {
  # All backends in a snapshot are read-only; the failure has to come back
  # as a Git::Native::Error rather than silently doing nothing.
  #
  # The key is read before and after rather than asserted to be undef:
  # libgit2 1.5 ignores GIT_CONFIG_GLOBAL, so a developer's real
  # ~/.gitconfig can supply user.email here (see the TestRepo isolation
  # ticket). What must hold either way is that the refused write changed
  # nothing.
  my $before = $repo->config_string('user.email');

  my $snap = $live->snapshot;
  my $err  = dies { $snap->set_string( 'user.email', 'nope@example.invalid' ) };
  isa_ok $err, ['Git::Native::Error'], 'set_string on a snapshot throws';
  ok !$err->isa('Git::Libgit2::Error'), 'the low-level error does not leak';
  ok $err->code < 0, 'with a negative libgit2 code';
  like $err->message, qr/readonly/i, 'the message says the backends are read-only';

  is $repo->config_string('user.email'), $before,
    'and nothing was written';
  isnt $repo->config_string('user.email'), 'nope@example.invalid',
    'in particular the refused value did not land';
};

subtest 'set_string returns the config for chaining' => sub {
  ref_is $live->set_string( 'a.b', 'c' ), $live, 'set_string returns $self';
  is $repo->config_string('a.b'), 'c', 'the chained write took effect';
};

subtest 'a snapshot of a snapshot still reads' => sub {
  # snapshot() passes _owner along, so the repository stays alive behind a
  # nested snapshot; if that ownership were dropped this read would be a
  # use-after-free rather than a value.
  my $nested = $live->snapshot->snapshot;
  is $nested->get_string('a.b'), 'c', 'the nested snapshot reads the value';
};

done_testing;



( run in 2.653 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )