| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- #!/usr/bin/perl
- #
- # This file is part of GNU Stow.
- #
- # GNU Stow is free software: you can redistribute it and/or modify it
- # under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # GNU Stow is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see https://www.gnu.org/licenses/.
- #
- # Utilities shared by test scripts
- #
- package testutil;
- use strict;
- use warnings;
- use Carp qw(croak);
- use File::Basename;
- use File::Path qw(make_path remove_tree);
- use File::Spec;
- use IO::Scalar;
- use Test::More;
- use Stow;
- use Stow::Util qw(parent canon_path);
- use base qw(Exporter);
- our @EXPORT = qw(
- $ABS_TEST_DIR
- $TEST_DIR
- $stderr
- init_test_dirs
- cd
- new_Stow new_compat_Stow
- make_path make_link make_invalid_link make_file
- remove_dir remove_file remove_link
- cat_file
- is_link is_dir_not_symlink is_nonexistent_path
- capture_stderr uncapture_stderr
- );
- our $TEST_DIR = 'tmp-testing-trees';
- our $ABS_TEST_DIR = File::Spec->rel2abs('tmp-testing-trees');
- our $stderr;
- my $tied_err;
- sub capture_stderr {
- undef $stderr;
- $tied_err = tie *STDERR, 'IO::Scalar', \$stderr;
- }
- sub uncapture_stderr {
- undef $tied_err;
- untie *STDERR;
- }
- sub init_test_dirs {
- # Create a run_from/ subdirectory for tests which want to run
- # from a separate directory outside the Stow directory or
- # target directory.
- for my $dir ("target", "stow", "run_from") {
- my $path = "$TEST_DIR/$dir";
- -d $path and remove_tree($path);
- make_path($path);
- }
- # Don't let user's ~/.stow-global-ignore affect test results
- $ENV{HOME} = $ABS_TEST_DIR;
- }
- sub new_Stow {
- my %opts = @_;
- $opts{dir} ||= '../stow';
- $opts{target} ||= '.';
- $opts{test_mode} = 1;
- return new Stow(%opts);
- }
- sub new_compat_Stow {
- my %opts = @_;
- $opts{compat} = 1;
- return new_Stow(%opts);
- }
- #===== SUBROUTINE ===========================================================
- # Name : make_link()
- # Purpose : safely create a link
- # Parameters: $target => path to the link
- # : $source => where the new link should point
- # : $invalid => true iff $source refers to non-existent file
- # Returns : n/a
- # Throws : fatal error if the link can not be safely created
- # Comments : checks for existing nodes
- #============================================================================
- sub make_link {
- my ($target, $source, $invalid) = @_;
- if (-l $target) {
- my $old_source = readlink join('/', parent($target), $source)
- or die "$target is already a link but could not read link $target/$source";
- if ($old_source ne $source) {
- die "$target already exists but points elsewhere\n";
- }
- }
- die "$target already exists and is not a link\n" if -e $target;
- my $abs_target = File::Spec->rel2abs($target);
- my $target_container = dirname($abs_target);
- my $abs_source = File::Spec->rel2abs($source, $target_container);
- #warn "t $target c $target_container as $abs_source";
- if (-e $abs_source) {
- croak "Won't make invalid link pointing to existing $abs_target"
- if $invalid;
- }
- else {
- croak "Won't make link pointing to non-existent $abs_target"
- unless $invalid;
- }
- symlink $source, $target
- or die "could not create link $target => $source ($!)\n";
- }
- #===== SUBROUTINE ===========================================================
- # Name : make_invalid_link()
- # Purpose : safely create an invalid link
- # Parameters: $target => path to the link
- # : $source => the non-existent source where the new link should point
- # Returns : n/a
- # Throws : fatal error if the link can not be safely created
- # Comments : checks for existing nodes
- #============================================================================
- sub make_invalid_link {
- my ($target, $source, $allow_invalid) = @_;
- make_link($target, $source, 1);
- }
- #===== SUBROUTINE ===========================================================
- # Name : create_file()
- # Purpose : create an empty file
- # Parameters: $path => proposed path to the file
- # : $contents => (optional) contents to write to file
- # Returns : n/a
- # Throws : fatal error if the file could not be created
- # Comments : detects clash with an existing non-file
- #============================================================================
- sub make_file {
- my ($path, $contents) = @_;
- if (-e $path and ! -f $path) {
- die "a non-file already exists at $path\n";
- }
- open my $FILE ,'>', $path
- or die "could not create file: $path ($!)\n";
- print $FILE $contents if defined $contents;
- close $FILE;
- }
- #===== SUBROUTINE ===========================================================
- # Name : remove_link()
- # Purpose : remove an esiting symbolic link
- # Parameters: $path => path to the symbolic link
- # Returns : n/a
- # Throws : fatal error if the operation fails or if passed the path to a
- # : non-link
- # Comments : none
- #============================================================================
- sub remove_link {
- my ($path) = @_;
- if (not -l $path) {
- die qq(remove_link() called with a non-link: $path);
- }
- unlink $path or die "could not remove link: $path ($!)\n";
- return;
- }
- #===== SUBROUTINE ===========================================================
- # Name : remove_file()
- # Purpose : remove an existing empty file
- # Parameters: $path => the path to the empty file
- # Returns : n/a
- # Throws : fatal error if given file is non-empty or the operation fails
- # Comments : none
- #============================================================================
- sub remove_file {
- my ($path) = @_;
- if (-z $path) {
- die "file at $path is non-empty\n";
- }
- unlink $path or die "could not remove empty file: $path ($!)\n";
- return;
- }
- #===== SUBROUTINE ===========================================================
- # Name : remove_dir()
- # Purpose : safely remove a tree of test files
- # Parameters: $dir => path to the top of the tree
- # Returns : n/a
- # Throws : fatal error if the tree contains a non-link or non-empty file
- # Comments : recursively removes directories containing softlinks empty files
- #============================================================================
- sub remove_dir {
- my ($dir) = @_;
- if (not -d $dir) {
- die "$dir is not a directory";
- }
- opendir my $DIR, $dir or die "cannot read directory: $dir ($!)\n";
- my @listing = readdir $DIR;
- closedir $DIR;
- NODE:
- for my $node (@listing) {
- next NODE if $node eq '.';
- next NODE if $node eq '..';
- my $path = "$dir/$node";
- if (-l $path or (-f $path and -z $path) or $node eq $Stow::LOCAL_IGNORE_FILE) {
- unlink $path or die "cannot unlink $path ($!)\n";
- }
- elsif (-d "$path") {
- remove_dir($path);
- }
- else {
- die "$path is not a link, directory, or empty file\n";
- }
- }
- rmdir $dir or die "cannot rmdir $dir ($!)\n";
- return;
- }
- #===== SUBROUTINE ===========================================================
- # Name : cd()
- # Purpose : wrapper around chdir
- # Parameters: $dir => path to chdir to
- # Returns : n/a
- # Throws : fatal error if the chdir fails
- # Comments : none
- #============================================================================
- sub cd {
- my ($dir) = @_;
- chdir $dir or die "Failed to chdir($dir): $!\n";
- }
- #===== SUBROUTINE ===========================================================
- # Name : cat_file()
- # Purpose : return file contents
- # Parameters: $file => file to read
- # Returns : n/a
- # Throws : fatal error if the open fails
- # Comments : none
- #============================================================================
- sub cat_file {
- my ($file) = @_;
- open F, $file or die "Failed to open($file): $!\n";
- my $contents = join '', <F>;
- close(F);
- return $contents;
- }
- #===== SUBROUTINE ===========================================================
- # Name : is_link()
- # Purpose : assert path is a symlink
- # Parameters: $path => path to check
- # : $dest => target symlink should point to
- #============================================================================
- sub is_link {
- my ($path, $dest) = @_;
- ok(-l $path => "$path should be symlink");
- is(readlink $path, $dest => "$path symlinks to $dest");
- }
- #===== SUBROUTINE ===========================================================
- # Name : is_dir_not_symlink()
- # Purpose : assert path is a directory not a symlink
- # Parameters: $path => path to check
- #============================================================================
- sub is_dir_not_symlink {
- my ($path) = @_;
- ok(! -l $path => "$path should not be symlink");
- ok(-d _ => "$path should be a directory");
- }
- #===== SUBROUTINE ===========================================================
- # Name : is_nonexistent_path()
- # Purpose : assert path does not exist
- # Parameters: $path => path to check
- #============================================================================
- sub is_nonexistent_path {
- my ($path) = @_;
- ok(! -l $path => "$path should not be symlink");
- ok(! -e _ => "$path should not exist");
- }
- 1;
- # Local variables:
- # mode: perl
- # cperl-indent-level: 4
- # end:
- # vim: ft=perl
|