Code-TidyAll

 view release on metacpan or  search on metacpan

t/lib/TestFor/Code/TidyAll/Git.pm  view on Meta::CPAN

sub test_git : Tests {
    my ($self) = @_;

    return unless $self->require_executable('git');

    my ( $temp_dir, $work_dir, $pushd ) = $self->_make_working_dir_and_repo;

    subtest 'add foo.txt', sub {
        $work_dir->child('foo.txt')->spew_raw("abc\n");
        cmp_deeply( [ git_files_to_commit($work_dir) ], [], 'no files to commit' );

        runx(qw( git add foo.txt ));
        cmp_deeply(
            [ map { $_->stringify } git_files_to_commit($work_dir) ],
            [ $work_dir->child('foo.txt')->stringify ], 'one file to commit'
        );
    };

    subtest 'attempt to commit untidy file', sub {
        my $output = capture_stderr { system(qw( git commit -q -m changed -a )) };
        like( $output, qr/1 file did not pass tidyall check/, '1 file did not pass tidyall check' );
        like( $output, qr/needs tidying/,                     'needs tidying' );
        $self->_assert_something_to_commit($work_dir);
    };

    subtest 'successfully commit tidied file', sub {
        $work_dir->child('foo.txt')->spew_raw("ABC\n");
        my $output = capture_stderr { runx(qw( git commit -q -m changed -a )) };
        like( $output, qr/\[checked\] foo\.txt/, 'checked foo.txt' );
        $self->_assert_nothing_to_commit($work_dir);
    };

    subtest 'add another file which is tidied', sub {
        $work_dir->child('bar.txt')->spew_raw('ABC');
        runx(qw( git add bar.txt ));
        runx(qw( git commit -q -m bar.txt ));

        $work_dir->child('bar.txt')->spew('def');
        cmp_deeply( [ git_files_to_commit($work_dir) ], [], 'no files to commit' );
        cmp_deeply(
            [ map { $_->stringify } git_modified_files($work_dir) ],
            ["$work_dir/bar.txt"],
            'one file was modified'
        );
    };

    my ( $shared_dir, $clone_dir );
    subtest 'create bare repo and clone it', sub {
        $shared_dir = $temp_dir->child('shared');
        $clone_dir  = $temp_dir->child('clone');

        runx( qw( git clone -q --bare ), map { _quote_for_win32($_) } $work_dir,   $shared_dir );
        runx( qw( git clone -q ),        map { _quote_for_win32($_) } $shared_dir, $clone_dir );
        chdir($clone_dir);
        $self->_assert_nothing_to_commit($work_dir);
    };

    my $prereceive_hook_file = $shared_dir->child(qw( hooks pre-receive ));
    my $prereceive_hook      = sprintf( $prereceive_hook_template, $self->_lib_dirs );
    $prereceive_hook_file->spew($prereceive_hook);
    $prereceive_hook_file->chmod(0775);

    subtest 'untidy file and attempt to commit it via commit -a', sub {
        $clone_dir->child('foo.txt')->spew_raw("def\n");
        runx(qw( git commit -q -m changed -a ));
        $self->_assert_nothing_to_commit($work_dir);
        $self->_assert_branch_is_ahead_of_origin;
    };

    subtest 'cannot push untidy file', sub {
        my $output = capture_stderr { system(qw( git push )) };
        like( $output, qr/master -> master/,                  'master -> master' );
        like( $output, qr/1 file did not pass tidyall check/, '1 file did not pass tidyall check' );
        like( $output, qr/needs tidying/,                     'needs tidying' );
        $self->_assert_branch_is_ahead_of_origin;
    };

    subtest 'can push tidied file', sub {
        $clone_dir->child('foo.txt')->spew_raw("DEF\n");
        capture_stderr { runx(qw( git commit -q -m changed -a )) };
        $self->_assert_nothing_to_commit($work_dir);
        my $output = capture_stderr { system(qw( git push )) };
        like( $output, qr/master -> master/, 'push succeeded' );
        $self->_assert_nothing_to_push;
    };

    subtest 'untidy file and commit it', sub {
        $clone_dir->child('foo.txt')->spew_raw("def\n");
        runx(qw( git commit -q -m changed -a ));
        $self->_assert_nothing_to_commit($work_dir);
        $self->_assert_branch_is_ahead_of_origin;
    };

    subtest 'cannot push when file is untidy', sub {
        $self->_assert_branch_is_ahead_of_origin;
        my $output = capture_stderr { system(qw( git push )) };
        like( $output, qr/needs tidying/, 'needs tidying' );
        $self->_assert_branch_is_ahead_of_origin;
    };

    subtest 'cannot push when file is untidy (2nd try)', sub {
        $self->_assert_branch_is_ahead_of_origin;
        my $output = capture_stderr { system(qw( git push )) };
        like( $output, qr/needs tidying/,               'needs tidying' );
        like( $output, qr/Identical push seen 2 times/, 'Identical push seen 2 times' );
        $self->_assert_branch_is_ahead_of_origin;
    };
}

sub test_copied_status : Tests {
    my ($self) = @_;

    return unless $self->require_executable('git');

    my ( $temp_dir, $work_dir, $pushd ) = $self->_make_working_dir_and_repo;

    my $foo_file = $work_dir->child('foo.txt');

    # If the file isn't long enough the new file doesn't end up with the
    # "copied" status.
    $foo_file->spew_raw( "ABC\n" x 500 );

t/lib/TestFor/Code/TidyAll/Git.pm  view on Meta::CPAN

    $work_dir->child('file1.txt')->spew("A\nB\n");
    $work_dir->child('file2.txt')->spew("A\nB\n");
    runx(qw( git add file1.txt file2.txt ));
    runx( qw( git commit -m ), 'Add files in master' );

    $work_dir->child('file1.txt')->append("C\n");
    $work_dir->child('file2.txt')->append("C\n");
    runx( qw( git commit -a -m ), 'Update files in master' );

    runx(qw( git checkout -b my-branch ));
    runx(qw( git reset --hard HEAD~1 ));

    $work_dir->child('file1.txt')->append("D\n");
    $work_dir->child('file2.txt')->append("C\n");
    runx(qw( git add file1.txt file2.txt ));
    runx( qw( git commit  -m ), 'Update files in my-branch' );

    # This will exit with 1 because of the conflict.
    runx( [1], qw( git merge master ) );

    like(
        $work_dir->child(qw( .git MERGE_MSG ))->slurp,
        qr/Conflicts:.+file1\.txt/s,
        'merge produced a conflict with file.txt'
    );

    $work_dir->child('file1.txt')->spew("A\nB\nD\n");

    # We need a change that will be stashed to trigger the bug.
    $work_dir->child('file2.txt')->append("E\n");
    runx(qw( git add file1.txt ));
    runx( qw( git commit -m ), 'Add file1.txt in my-branch for real' );
    my $output = capturex(qw( git log -n 1 ));
    like( $output, qr/Merge: [0-9a-f]+ [0-9a-f]+/, 'last commit was a merge commit' );
}

sub _make_working_dir_and_repo {
    my $self = shift;

    my $temp_dir  = tempdir_simple;
    my $work_dir  = $temp_dir->child('work');
    my $hooks_dir = $work_dir->child(qw( .git hooks ));

    runx( qw( git init -q ), _quote_for_win32($work_dir) );

    # This dir doesn't exist unless there's a git dir template that includes
    # the hooks subdir.
    $hooks_dir->mkpath( { verbose => 0, mode => 0755 } );
    ok( -d $_, "$_ exists" ) for ( $work_dir, $hooks_dir );

    my $pushd = pushd($work_dir);

    $work_dir->child('tidyall.ini')->spew($tidyall_ini_template);
    $work_dir->child('.gitignore')->spew('.tidyall.d');
    runx(qw( git add tidyall.ini .gitignore ));
    runx(qw( git commit -q -m added tidyall.ini .gitignore ));

    my $precommit_hook_file = $hooks_dir->child('pre-commit');
    my $precommit_hook      = sprintf( $precommit_hook_template, $self->_lib_dirs );
    $precommit_hook_file->spew($precommit_hook);
    $precommit_hook_file->chmod(0755);

    return ( $temp_dir, $work_dir, $pushd );
}

sub _quote_for_win32 {

    # The docs for IPC::System::Simple lie about how it works on Windows. On
    # Windows it _always_ invokes a shell, so we need to quote a path with
    # spaces.
    return $_[0] unless IS_WIN32 && $_[0] =~ / /;
    return qq{"$_[0]"};
}

sub _lib_dirs {
    my %dirs = map { $_ => 1 } map { path($Bin)->parent->child($_) } qw( lib t/lib );
    if ( $ENV{PERL5LIB} ) {
        my $sep = $^O eq 'MSWin32' ? q{;} : q{:};
        $dirs{$_} = 1 for split /\Q$sep/, $ENV{PERL5LIB};
    }
    return join q{ }, sort keys %dirs;
}

sub _assert_nothing_to_commit {
    shift;
    my @files = git_files_to_commit(shift);
    is( scalar @files, 0, 'there are no files to commit' )
        or diag("@files");
}

sub _assert_something_to_commit {
    shift;
    my @files = git_files_to_commit(shift);
    cmp_ok( scalar @files, '>=', 0, 'there are files to commit' );
}

sub _assert_nothing_to_push {
    unlike(
        capturex( 'git', 'status' ),
        qr/Your branch is ahead/,
        'branch is up to date with origin'
    );
}

sub _assert_branch_is_ahead_of_origin {
    like( capturex( 'git', 'status' ), qr/Your branch is ahead/, 'branch is ahead of origin' );
}

$precommit_hook_template = '#!' . $^X . "\n" . <<'EOF';
use lib qw(%s);
use Code::TidyAll::Git::Precommit;
use strict;
use warnings;

Code::TidyAll::Git::Precommit->check(
    tidyall_options => { verbose => 1 }
);
EOF

$prereceive_hook_template = '#!' . $^X . "\n" . <<'EOF';
use lib qw(%s);



( run in 0.666 second using v1.01-cache-2.11-cpan-39bf76dae61 )