Skip to content

Commit

Permalink
Break the circular dependency between Util and Repo
Browse files Browse the repository at this point in the history
The high-level test functions test_autofixup() and
test_autofixup_strict() didn't really fit in Util.
  • Loading branch information
torbiak committed Oct 13, 2023
1 parent a4abf8e commit 37f0f4a
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 135 deletions.
56 changes: 28 additions & 28 deletions t/autofixup.t
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;

require './t/test.pl';
require './t/util.pl';
require './git-autofixup';

Util::check_test_deps();
plan tests => 43;

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "single-line change gets autofixed",
strict => [0..2],
topic_commits => [{a => "a1\n"}],
Expand All @@ -30,7 +30,7 @@ index da0f8ed..c1827f0 100644
EOF
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "adjacent change gets autofixed",
strict => [0..1],
upstream_commits => [{a => "a3\n"}],
Expand All @@ -51,7 +51,7 @@ index 76642d4..2cdcdb0 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "adjacent change doesn't get autofixed if strict=2",
upstream_commits => [{a => "a3\n"}],
topic_commits => [{a => "a1\na3\n"}],
Expand All @@ -61,7 +61,7 @@ Util::test_autofixup(
exit_code => 2,
);

Util::test_autofixup(
Test::autofixup(
name => 'fixups are created for additions surrounded by topic commit lines when strict=2',
topic_commits => [{a => "a1\na3\n", b => "b1\n", c => "c2\n"}],
unstaged => {a => "a1\na2\na3\n", b => "b1\nb2\n", c => "c1\nc2\n"},
Expand Down Expand Up @@ -95,7 +95,7 @@ index 16f9ec0..d0aaf97 100644
EOF
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "removed file doesn't get autofixed",
strict => [0..2],
topic_commits => [sub { Util::write_file(a => "a1\n"); }],
Expand All @@ -104,7 +104,7 @@ Util::test_autofixup_strict(
log_want => '',
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "re-added file doesn't get autofixed",
strict => [0..2],
topic_commits => [
Expand All @@ -116,7 +116,7 @@ Util::test_autofixup_strict(
log_want => '',
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "re-added line gets autofixed into the commit blamed for the adjacent context",
# During rebase the line will just get removed again by the next commit.
# --strict can be used to avoid creating a fixup in this case, where the
Expand Down Expand Up @@ -145,7 +145,7 @@ index da0f8ed..0016606 100644
EOF
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "removed lines get autofixed",
strict => [0..2],
topic_commits => [{a => "a1\n", b => "b1\nb2\n"}],
Expand All @@ -170,7 +170,7 @@ index 9b89cd5..e6bfff5 100644
EOF
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => 'no fixups are created for upstream commits',
strict => [0..2],
upstream_commits => [{a => "a1\n"}],
Expand All @@ -179,7 +179,7 @@ Util::test_autofixup_strict(
log_want => '',
);

Util::test_autofixup(
Test::autofixup(
name => 'fixups are created for hunks changing lines blamed by upstream if strict=0',
# This depends on the number of context lines kept when creating diffs. git
# keeps 3 by default.
Expand All @@ -203,7 +203,7 @@ index 125d560..cc1aa32 100644
+a3b
EOF
);
Util::test_autofixup_strict(
Test::autofixup_strict(
name => 'no fixups are created for hunks changing lines blamed by upstream if strict > 0',
# This depends on the number of context lines kept when creating diffs. git
# keeps 3 by default.
Expand All @@ -215,7 +215,7 @@ Util::test_autofixup_strict(
log_want => '',
);

Util::test_autofixup_strict(
Test::autofixup_strict(
name => "hunks blamed on a fixup! commit are assigned to that fixup's target",
strict => [0..2],
topic_commits => [
Expand All @@ -240,7 +240,7 @@ index c1827f0..b792f74 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "removed line gets autofixed when context=0",
topic_commits => [{a => "a1\na2\n"}],
unstaged => {a => "a1\n"},
Expand All @@ -259,7 +259,7 @@ index 0016606..da0f8ed 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "added line is ignored when context=0",
topic_commits => [{a => "a1\n"}],
unstaged => {a => "a1\na2\n"},
Expand All @@ -268,7 +268,7 @@ Util::test_autofixup(
log_want => '',
);

Util::test_autofixup(
Test::autofixup(
name => "ADJACENCY assignment is used as a fallback for multiple context targets",
topic_commits => [
{a => "a1\n"},
Expand All @@ -290,7 +290,7 @@ index 0016606..a0ef52c 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "Works when run in a subdir of the repo root",
topic_commits => [
sub {
Expand All @@ -314,7 +314,7 @@ index da0f8ed..0016606 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "file without newline at EOF gets autofixed",
topic_commits => [{a => "a1\na2"}],
unstaged => {'a' => "a1\na2\n"},
Expand All @@ -334,7 +334,7 @@ index c928c51..0016606 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "multiple hunks in the same file get autofixed",
topic_commits => [
{a => "a1.0\na2\na3\na4\na5\na6\na7\na8\na9.0\n"},
Expand Down Expand Up @@ -371,7 +371,7 @@ index 50de7e8..d9f44da 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "single-line change gets autofixed when mnemonic prefixes are enabled",
topic_commits => [{a => "a1\n"}],
unstaged => {a => "a2\n"},
Expand All @@ -390,7 +390,7 @@ index da0f8ed..c1827f0 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "single-line change gets autofixed when diff.external is set",
topic_commits => [{a => "a1\n"}],
unstaged => {a => "a2\n"},
Expand All @@ -409,7 +409,7 @@ index da0f8ed..c1827f0 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => 'exit code is 1 when some hunks are assigned',
upstream_commits => [{a => "a1\n"}],
topic_commits => [{b => "b1\n"}],
Expand All @@ -428,7 +428,7 @@ index c9c6af7..e6bfff5 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "multiple hunks to the same commit get autofixed",
topic_commits => [
{a => "a1.0\na2\na3\na4\na5\na6\na7\na8\na9.0\n"},
Expand Down Expand Up @@ -465,7 +465,7 @@ index 5d11004..0054137 100644
+a9.1
});

Util::test_autofixup(
Test::autofixup(
name => "only staged hunks get autofixed",
topic_commits => [{a => "a1\n", b => "b1\n"}],
staged => {a => "a2\n"},
Expand Down Expand Up @@ -493,7 +493,7 @@ index c9c6af7..e6bfff5 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "staged hunks that aren't autofixed remain in index",
upstream_commits => [{b => "b1\n"}],
topic_commits => [{a => "a1\n", , c => "c1\n"}],
Expand Down Expand Up @@ -538,7 +538,7 @@ index c9c6af7..e6bfff5 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "filename with spaces",
topic_commits => [{"filename with spaces" => "a1\n"}],
unstaged => {"filename with spaces" => "a2\n"},
Expand All @@ -556,7 +556,7 @@ index da0f8ed..c1827f0 100644
EOF
);

Util::test_autofixup(
Test::autofixup(
name => "filename with unusual characters",
topic_commits => [{"ff\f nak\025 dq\" fei飞.txt" => "a1\n"}],
unstaged => {"ff\f nak\025 dq\" fei飞.txt" => "a2\n"},
Expand All @@ -576,7 +576,7 @@ EOF

SKIP: {
skip "can't put backslashes in filenames on windows" if $OSNAME eq 'cygwin';
Util::test_autofixup(
Test::autofixup(
name => "filename with backslash",
topic_commits => [{"hack\\.txt" => "a1\n"}],
unstaged => {"hack\\.txt" => "a2\n"},
Expand Down
119 changes: 119 additions & 0 deletions t/test.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Long test functions that could conceivably be used in multiple .t files.

package Test;

use strict;
use warnings FATAL => 'all';

use Carp qw(croak);
use Cwd;
use Test::More;

require './t/util.pl';
require './t/repo.pl';

# Run autofixup() with each of the given strictness levels.
sub autofixup_strict {
my %args = @_;
my $strict_levels = $args{strict} or croak "strictness levels not given";
delete $args{strict};
my $autofixup_opts = $args{autofixup_opts} || [];
if (grep /^(--strict|-s)/, @{$autofixup_opts}) {
croak "strict option already given";
}
my $name = $args{name} || croak "name not given";
for my $strict (@{$strict_levels}) {
$args{name} = "$name, strict=$strict";
$args{autofixup_opts} = ['-s' => $strict, @{$autofixup_opts}];
autofixup(%args);
}
}

# autofixup initializes a git repo in a tempdir, creates given "upstream" and
# "topic" commits, applies changes to the working directory, runs autofixup,
# and compares wanted `git log` and `git diff` outputs to actual ones.
#
# Arguments are given as a hash:
# name: test name or description
# upstream_commits: sub or hash refs that must not be fixed up
# topic_commits: sub or hash refs representing commits that can be fixed up
# unstaged: sub or hashref of working directory changes
# staged: sub or hashref of index changes
# log_want: expected log output for new fixup commited
# staged_want: expected log output for the staging area
# unstaged_want: expected diff output for the working tree
# autofixup_opts: command-line options to pass thru to autofixup
# git_config: hashref of git config key/value pairs
#
# The upstream_commits and topic_commits arguments are heterogeneous lists of
# sub and hash refs. Hash refs are interpreted as being maps of filenames to
# contents to be written. If more flexibility is needed a subref can be given
# to manipulate the working directory.
sub autofixup {
my %args = @_;
my $name = defined($args{name}) ? $args{name}
: croak "no test name given";
my $upstream_commits = $args{upstream_commits} || [];
my $topic_commits = $args{topic_commits} || [];
my $unstaged = defined($args{unstaged}) ? $args{unstaged}
: croak "no unstaged changes given";
my $staged = $args{staged};
my $log_want = defined($args{log_want}) ? $args{log_want}
: croak "wanted log output not given";
my $staged_want = $args{staged_want};
my $unstaged_want = $args{unstaged_want};
my $exit_code_want = $args{exit_code};
my $autofixup_opts = $args{autofixup_opts} || [];
push @{$autofixup_opts}, '--exit-code';
my $git_config = $args{git_config} || {};
if (!$upstream_commits && !$topic_commits) {
croak "no upstream or topic commits given";
}
if (exists $args{strict}) {
croak "strict key given; use test_autofixup_strict instead";
}

local $ENV{GIT_CONFIG_COUNT} = scalar keys %$git_config;
my $git_config_env = Util::git_config_env_vars($git_config);
local (@ENV{keys %$git_config_env});
for my $k (keys %$git_config_env) {
$ENV{$k} = $git_config_env->{$k};
}

eval {
my $repo = Repo->new();

$repo->create_commits(@$upstream_commits);
my $upstream_rev = $repo->current_commit_sha();

$repo->create_commits(@$topic_commits);
my $pre_fixup_rev = $repo->current_commit_sha();

if (defined($staged)) {
$repo->write_change($staged);
# We're at the repo root, so using -A will change everything even
# in pre-v2 versions of git. See git commit 808d3d717e8.
Util::run(qw(git add -A));
}

$repo->write_change($unstaged);

Util::run('git', '--no-pager', 'log', "--format='%h %s'", "${upstream_rev}..");
my $exit_code_got = $repo->autofixup(@{$autofixup_opts}, $upstream_rev);

my $ok = Util::exit_code_ok(want => $exit_code_want, got => $exit_code_got);
my $wants = {
fixup_log => $log_want,
staged => $staged_want,
unstaged => $unstaged_want,
};
$ok &&= Util::repo_state_ok($repo, $pre_fixup_rev, $wants);
ok($ok, $name);
};
if ($@) {
diag($@);
fail($name);
}
return;
}

Loading

0 comments on commit 37f0f4a

Please sign in to comment.