From 6c525b8289142d189cd2578fb465cb13d2886a5a Mon Sep 17 00:00:00 2001 From: Graham Ollis Date: Mon, 23 Jun 2025 13:00:14 -0600 Subject: [PATCH 1/3] initial implementation --- README.md | 42 ++++++++++++++ lib/Test2/Require/ProgramInPath.pm | 48 +++++++++++++++- t/00_diag.t | 89 ++++++++++++++++++++++++++++++ t/test2_require_programinpath.t | 2 +- 4 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 README.md create mode 100644 t/00_diag.t diff --git a/README.md b/README.md new file mode 100644 index 0000000..71c6e1d --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Test2::Require::ProgramInPath ![static](https://github.com/uperl/Test2-Require-ProgramInPath/workflows/static/badge.svg) ![linux](https://github.com/uperl/Test2-Require-ProgramInPath/workflows/linux/badge.svg) + +Skip test unless a program exists in the PATH + +# SYNOPSIS + +```perl +use Test2::Require::ProgramInPath 'gcc'; +use Test2::V0; +use Test::Script qw( program_runs ); + +program_runs ['gcc', 'foo.c']; + +done_testing; +``` + +# DESCRIPTION + +This is skip unless a particular program can be found in the `PATH`. Under the covers [File::Which](https://metacpan.org/pod/File::Which) is used. This is a subclass of [Test2::Require](https://metacpan.org/pod/Test2::Require). + +# METHODS + +## skip + +Should not be invoked directly, but returns \`undef\` if the test should not be skipped and a string containing +the reason why the test was skipped. Currently \`This test only runs if $program is in the PATH\` is returned. + +# SEE ALSO + +- [File::Which](https://metacpan.org/pod/File::Which) +- [Test2::Require](https://metacpan.org/pod/Test2::Require) + +# AUTHOR + +Graham Ollis + +# COPYRIGHT AND LICENSE + +This software is copyright (c) 2025 by Graham Ollis. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. diff --git a/lib/Test2/Require/ProgramInPath.pm b/lib/Test2/Require/ProgramInPath.pm index 796be57..da83393 100644 --- a/lib/Test2/Require/ProgramInPath.pm +++ b/lib/Test2/Require/ProgramInPath.pm @@ -1,9 +1,55 @@ use warnings; use 5.020; -use experimental qw( postderef signatures ); +use experimental qw( signatures ); use true; package Test2::Require::ProgramInPath { # ABSTRACT: Skip test unless a program exists in the PATH + +=head1 SYNOPSIS + + use Test2::Require::ProgramInPath 'gcc'; + use Test2::V0; + use Test::Script qw( program_runs ); + + program_runs ['gcc', 'foo.c']; + + done_testing; + +=head1 DESCRIPTION + +This is skip unless a particular program can be found in the C. Under the covers L is used. This is a subclass of L. + +=head1 METHODS + +=head2 skip + +Should not be invoked directly, but returns `undef` if the test should not be skipped and a string containing +the reason why the test was skipped. Currently `This test only runs if $program is in the PATH` is returned. + +=cut + + use File::Which qw( which ); + use Carp qw( confess ); + use parent qw( Test2::Require ); + + sub skip ( $, $program = undef ) { + confess "no program specified" unless defined $program; + return undef if which $program; + return "This test only runs if $program is in the PATH"; + } } + + +=head1 SEE ALSO + +=over 4 + +=item L + +=item L + +=back + +=cut diff --git a/t/00_diag.t b/t/00_diag.t new file mode 100644 index 0000000..9c8f95e --- /dev/null +++ b/t/00_diag.t @@ -0,0 +1,89 @@ +use Test2::V0 -no_srand => 1; +use Config; + +eval { require 'Test/More.pm' }; + +# This .t file is generated. +# make changes instead to dist.ini + +my %modules; +my $post_diag; + +$modules{$_} = $_ for qw( + ExtUtils::MakeMaker + File::Which + Test2::Require + Test2::V0 + true +); + + + +my @modules = sort keys %modules; + +sub spacer () +{ + diag ''; + diag ''; + diag ''; +} + +pass 'okay'; + +my $max = 1; +$max = $_ > $max ? $_ : $max for map { length $_ } @modules; +our $format = "%-${max}s %s"; + +spacer; + +my @keys = sort grep /(MOJO|PERL|\A(LC|HARNESS)_|\A(SHELL|LANG)\Z)/i, keys %ENV; + +if(@keys > 0) +{ + diag "$_=$ENV{$_}" for @keys; + + if($ENV{PERL5LIB}) + { + spacer; + diag "PERL5LIB path"; + diag $_ for split $Config{path_sep}, $ENV{PERL5LIB}; + + } + elsif($ENV{PERLLIB}) + { + spacer; + diag "PERLLIB path"; + diag $_ for split $Config{path_sep}, $ENV{PERLLIB}; + } + + spacer; +} + +diag sprintf $format, 'perl', "$] $^O $Config{archname}"; + +foreach my $module (sort @modules) +{ + my $pm = "$module.pm"; + $pm =~ s{::}{/}g; + if(eval { require $pm; 1 }) + { + my $ver = eval { $module->VERSION }; + $ver = 'undef' unless defined $ver; + diag sprintf $format, $module, $ver; + } + else + { + diag sprintf $format, $module, '-'; + } +} + +if($post_diag) +{ + spacer; + $post_diag->(); +} + +spacer; + +done_testing; + diff --git a/t/test2_require_programinpath.t b/t/test2_require_programinpath.t index 7f5ae07..a68eb14 100644 --- a/t/test2_require_programinpath.t +++ b/t/test2_require_programinpath.t @@ -1,5 +1,5 @@ use Test2::V0 -no_srand => 1; -use Test2::Require::ProgramInPath; +use Test2::Require::ProgramInPath (); ok 1, 'todo'; From 6d84ad82777a36e0de9d547fce647cb24235d312 Mon Sep 17 00:00:00 2001 From: Graham Ollis Date: Mon, 23 Jun 2025 13:03:26 -0600 Subject: [PATCH 2/3] bump gha --- .github/workflows/linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 928e27f..6dd61a4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -34,7 +34,7 @@ jobs: CIP_TAG: ${{ matrix.cip_tag }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Bootstrap CIP run: | @@ -47,7 +47,7 @@ jobs: cip cache-key - name: Cache CPAN modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cip key: ${{ runner.os }}-build-${{ steps.cache-key.outputs.key }} From 7df6220b9bff17847fc63cb0945f10a256769b62 Mon Sep 17 00:00:00 2001 From: Graham Ollis Date: Mon, 23 Jun 2025 13:11:44 -0600 Subject: [PATCH 3/3] add test --- lib/Test2/Require/ProgramInPath.pm | 4 ++-- t/test2_require_programinpath.t | 32 +++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/Test2/Require/ProgramInPath.pm b/lib/Test2/Require/ProgramInPath.pm index da83393..4a637f5 100644 --- a/lib/Test2/Require/ProgramInPath.pm +++ b/lib/Test2/Require/ProgramInPath.pm @@ -30,13 +30,13 @@ the reason why the test was skipped. Currently `This test only runs if $program =cut - use File::Which qw( which ); + use File::Which (); use Carp qw( confess ); use parent qw( Test2::Require ); sub skip ( $, $program = undef ) { confess "no program specified" unless defined $program; - return undef if which $program; + return undef if File::Which::which $program; return "This test only runs if $program is in the PATH"; } } diff --git a/t/test2_require_programinpath.t b/t/test2_require_programinpath.t index a68eb14..3e47652 100644 --- a/t/test2_require_programinpath.t +++ b/t/test2_require_programinpath.t @@ -1,6 +1,36 @@ use Test2::V0 -no_srand => 1; use Test2::Require::ProgramInPath (); -ok 1, 'todo'; +subtest 'skip' => sub { + + plan 2; + + local *File::Which::which = sub { + is(\@_, ['foo']); + return undef; + }; + + is( + Test2::Require::ProgramInPath->skip('foo'), + 'This test only runs if foo is in the PATH', + ); + +}; + +subtest 'no skip' => sub { + + plan 2; + + local *File::Which::which = sub { + is(\@_, ['foo']); + return '/bin/foo'; + }; + + is( + Test2::Require::ProgramInPath->skip('foo'), + U(), + ); + +}; done_testing;