Skip to content

Commit

Permalink
remove deprecated "given-when" statement, use "FindBin" module instea…
Browse files Browse the repository at this point in the history
…d of ".proverc" for testers avoiding "prove"
  • Loading branch information
jsf116 committed Jul 23, 2023
1 parent 3e3e5a2 commit 51ee56d
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 95 deletions.
10 changes: 9 additions & 1 deletion Changes
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
Changelog for Test-Expander

2.1.1 2023-07-23
- Remove deprecated "given-when" statement.
- Use "FindBin" module instead of ".proverc" for testers avoiding "prove".

2.1.0 2023-07-22
- Implement "builtins" option.
- Support cascading usage of environment variables in .env files.

2.0.4 2023-07-14
- Fix PWD issue specific for MS Windows only.

2.0.3 2023-07-13
- Fix Kwalitee issues,
- Fix Kwalitee issues.

2.0.2 2023-07-11
- Increase required version of Path::Tiny to 0.125 to make possible the usage of mkdir.
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ t/Test/Expander/import.t
t/Test/Expander/is_deeply.t
t/Test/Expander/lives_ok.t
t/Test/Expander/new_ok.t
t/Test/Expander/NoCLASS/mock_builtin.t
t/Test/Expander/NoCLASS/MyModule.pm
t/Test/Expander/NoCLASS/NoMETHOD.t
t/Test/Expander/NoCLASS/NoMETHOD_only.t
t/Test/Expander/require_ok.t
Expand Down
7 changes: 4 additions & 3 deletions META.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@
},
"test" : {
"requires" : {
"FindBin" : "0",
"Test::Simple" : "0"
}
}
},
"provides" : {
"Test::Expander" : {
"file" : "lib/Test/Expander.pm",
"version" : "2.0.4"
"version" : "2.1.1"
},
"Test::Expander::Constants" : {
"file" : "lib/Test/Expander/Constants.pm",
"version" : "2.0.4"
"version" : "2.1.1"
}
},
"release_status" : "stable",
Expand All @@ -75,5 +76,5 @@
"web" : "https://github.com/jsf116/Test-Expander"
}
},
"version" : "2.0.4"
"version" : "2.1.1"
}
6 changes: 3 additions & 3 deletions META.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ no_index:
provides:
Test::Expander:
file: lib/Test/Expander.pm
version: '2.0.4'
version: '2.1.1'
Test::Expander::Constants:
file: lib/Test/Expander/Constants.pm
version: '2.0.4'
version: '2.1.1'
requires:
B: '0'
Const::Fast: '0'
Expand All @@ -39,4 +39,4 @@ requires:
resources:
bugtracker: https://github.com/jsf116/Test-Expander
repository: git://github.com/jsf116/Test-Expander.git
version: '2.0.4'
version: '2.1.1'
1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ WriteMakefile(
'Test2::V0' => 0,
},
TEST_REQUIRES => {
'FindBin' => 0,
'Test::Simple' => 0,
},
VERSION_FROM => 'lib/Test/Expander.pm',
Expand Down
84 changes: 47 additions & 37 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
**Test::Expander** - Expansion of test functionalities that appear to be frequently used while testing.

# SYNOPSIS

```perl
# Tries to automatically determine, which class / module and method / subroutine are to be tested,
# creates neither a temporary directory, nor a temporary file:
use Test::Expander;
Expand Down Expand Up @@ -41,6 +41,11 @@
],
-tempdir => {};

# Override the builtin 'close' in the name space of explicitly supplied class / module to be tested:
use Test::Expander
-builtins => { close => sub { CORE::close( shift ); 'successfully closed' } },
-target => 'My::Class';
```
# DESCRIPTION

The primary objective of **Test::Expander** is to provide additional convenience while testing based on
Expand All @@ -59,13 +64,13 @@ This, of course, can be stored in additional variables declared somewhere at the
a single change of path and / or base name of the corresponding test file.

An additional benefit of suggested approach is a better readability of tests, where chunks like

```perl
Foo::Bar->baz( $arg0, $arg1 )

```
now look like

```perl
$CLASS->$METHOD( $arg0, $arg1 )

```
and hence clearly manifest that this chunk is about the testee.

- The frequent necessity of introduction of temporary directory and / or temporary file usually leads to the usage of
Expand All @@ -74,9 +79,9 @@ providing the methods / funtions **tempdir** and **tempfile**.

This, however, can significantly be simplified (and the size of test file can be reduced) requesting such introduction
via the options supported by **Test::Expander**:

```perl
use Test::Expander -tempdir => {}, -tempfile => {};

```
- Another fuctionality frequently used in tests relates to the work with files and directories:
reading, writing, creation, etc. Because almost all features required in such cases are provided by
[Path::Tiny](https://metacpan.org/pod/Path::Tiny), some functions of this module is also exported from
Expand Down Expand Up @@ -114,6 +119,9 @@ there is no need to hard-code this in the test itself.
The following options are accepted:

- Options specific for this module only are always expected to have values and their meaning is:
- **-builtins** - override builtins in the name space of class / module to be tested.
The expected value is a hash reference, where keys are the names of builtins and
the values are code references overriding default behavior.
- **-lib** - prepend directory list used by the Perl interpreter for search of modules to be loaded
(i.e. the **@INC** array) with values supplied in form of array reference.
Each element of this array is evaluated using [string eval](https://perldoc.perl.org/functions/eval) so that
Expand Down Expand Up @@ -155,34 +163,36 @@ The known exceptions are:

- When another module is used, which in turn is based on [Test::Builder](https://metacpan.org/pod/Test::Builder) e.g.
[Test::Output](https://metacpan.org/pod/Test::Output):

```perl
use Test::Output;
use Test::Expander;

```
- When some actions performed on the module level (e.g. determination of constants)
rely upon results of other actions (e.g. mocking of built-ins).

To explain this let us assume that your test file should mock the built-in **close**
To explain this let us assume that your test file should globally mock the built-in **close**
(if this is only required in the name space of class / module to be tested,
the option **builtin** should be used instead!)
to verify if the testee properly reacts both on its success and failure.
For this purpose a reasonable implementation might look as follows:

```perl
my $closeSuccess = 1;
BEGIN {
*CORE::GLOBAL::close = sub (*) { return $closeSuccess ? CORE::close($_[0]) : 0 }
*CORE::GLOBAL::close = sub (*) { return $closeSuccess ? CORE::close( $_[ 0 ] ) : 0 }
}

use Test::Expander;

```
The automated recognition of name of class / module to be tested can only work
if the test file is located in the corresponding subdirectory.
For instance, if the class / module to be tested is _Foo::Bar::Baz_, then the folder with test files
related to this class / module should be **t/**_Foo_**/**_Bar_**/**_Baz_ or **xt/**_Foo_**/**_Bar_**/**_Baz_
(the name of the top-level directory in this relative name - **t**, or **xt**, or **my\_test** is not important) -
otherwise the module name cannot be put into the exported variable **$CLASS** and, if you want to use this variable,
should be supplied as the value of **-target**:

```perl
use Test::Expander -target => 'Foo::Bar::Baz';

```
This recognition can explicitly be deactivated if the value of **-target** is **undef**, so that no class / module
will be loaded and, correspondingly, the variables **$CLASS**, **$METHOD**, and **$METHOD\_REF** will not be exported.

Expand All @@ -194,9 +204,9 @@ to be tested and its reference, correspondingly, otherwise both variables are ne

Also in this case evaluation and export of the variables **$METHOD** and **$METHOD\_REF** can be prevented
by passing of **undef** as value of the option **-method**:

```perl
use Test::Expander -target => undef;

```
Finally, **Test::Expander** supports testing inside of a clean environment containing only some clearly
specified environment variables required for the particular test.
Names and values of these environment variables should be configured in files,
Expand Down Expand Up @@ -234,35 +244,35 @@ All remaining elements of the **%ENV** hash gets emptied (without localization)
character after the equal sign until end of the line;
if this value is omitted, the corresponding environment variable remains unchanged as it originally was in the **%ENV**
hash (if it existed there, of course);
- during the evaluation of current line environment variables defined in above lines of the same file can be used.
For example if such **.env** file contains

VAR1 = 'ABC'
VAR2 = lc( $ENV{ VAR1 } )
- the cascading definition of environment variables can be used, which means that
- during the evaluation of current line environment variables defined in the same file above can be applied.
For example if such **.env** file contains

and neither **VAR1** nor **VAR2** will be overwritten during the evaluation of subsequent lines in the same or other
**.env** files, the **%ENV** hash will contain at least the following entries:
VAR1 = 'ABC'
VAR2 = lc( $ENV{ VAR1 } )

VAR1 => 'ABC'
VAR2 => 'abc'
and neither **VAR1** nor **VAR2** will be overwritten during the evaluation of subsequent lines in the same or other
**.env** files, the **%ENV** hash will contain at least the following entries:

- during the evaluation of current line also environment variables defined in a higher-level **.env** file can be used.
For example if **t/Foo/Bar/Baz.env** contains
VAR1 => 'ABC'
VAR2 => 'abc'

VAR0 = 'XYZ '
- during the evaluation of current line also environment variables defined in a higher-level **.env** file can be used.
For example if **t/Foo/Bar/Baz.env** contains

and **t/Foo/Bar/Baz/myMethod.env** contains
VAR0 = 'XYZ '

VAR1 = 'ABC'
VAR2 = lc( $ENV{ VAR0 } . $ENV{ VAR1 } )
and **t/Foo/Bar/Baz/myMethod.env** contains

and neither **VAR0**, nor **VAR1**, nor **VAR2** will be overwritten during the evaluation of subsequent lines in the same
or other **.env** files, the **%ENV** hash will contain at least the following entries:
VAR1 = 'ABC'
VAR2 = lc( $ENV{ VAR0 } . $ENV{ VAR1 } )

VAR0 => 'XYZ '
VAR1 => 'ABC'
VAR2 => 'xyz abc'
and neither **VAR0**, nor **VAR1**, nor **VAR2** will be overwritten during the evaluation of subsequent lines in the same
or other **.env** files, the **%ENV** hash will contain at least the following entries:

VAR0 => 'XYZ '
VAR1 => 'ABC'
VAR2 => 'xyz abc'
- the value of the environment variable (if provided) is evaluated by the
[string eval](https://perldoc.perl.org/functions/eval) so that
- constant values must be quoted;
Expand Down
79 changes: 34 additions & 45 deletions lib/Test/Expander.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
package Test::Expander;

# The versioning is conform with https://semver.org
our $VERSION = '2.0.4'; ## no critic (RequireUseStrict, RequireUseWarnings)
our $VERSION = '2.1.1'; ## no critic (RequireUseStrict, RequireUseWarnings)

use strict;
use warnings
FATAL => qw( all ),
NONFATAL => qw( deprecated exec internal malloc newline portable recursion );
use feature qw( switch );
no if ( $] >= 5.018 ),
warnings => qw( experimental );
FATAL => qw( all ),
NONFATAL => qw( deprecated exec internal malloc newline portable recursion );

use Const::Fast;
use File::chdir;
Expand Down Expand Up @@ -235,46 +232,38 @@ sub _parse_options {

my $options = {};
while ( my $option_name = shift( @$exports ) ) {
given ( $option_name ) {
when ( '-builtins' ) {
my $option_value = shift( @$exports );
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
while ( my ( $sub_name, $sub_ref ) = each( %$option_value ) ) {
$DIE->( $FMT_INVALID_VALUE, $option_name . "->{ $sub_name }", $sub_ref ) if ref( $sub_ref ) ne 'CODE';
}
$options->{ -builtins } = $option_value;
}
when ( '-lib' ) {
my $option_value = shift( @$exports );
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'ARRAY';
$options->{ -lib } = $option_value;
}
when ( '-method' ) {
my $option_value = shift( @$exports );
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value );
$METHOD = $options->{ -method } = $option_value;
}
when ( '-target' ) {
my $option_value = shift( @$exports ); # Do not load module only if its name is undef
$options->{ -target } = $option_value if defined( $option_value );
}
when ( '-tempdir' ) {
my $option_value = shift( @$exports );
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
$TEMP_DIR = tempdir( CLEANUP => 1, %$option_value );
}
when ( '-tempfile' ) {
my $option_value = shift( @$exports );
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
my $file_handle;
( $file_handle, $TEMP_FILE ) = tempfile( UNLINK => 1, %$option_value );
}
when ( /^-\w/ ) {
$options->{ $option_name } = shift( @$exports );
}
default {
$DIE->( $FMT_UNKNOWN_OPTION, $option_name, shift( @$exports ) // '' );
$DIE->( $FMT_UNKNOWN_OPTION, $option_name, shift( @$exports ) // '' ) if $option_name !~ /^-\w/;

my $option_value = shift( @$exports );
if ( $option_name eq '-builtins' ) { ## no critic (ProhibitCascadingIfElse)
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
while ( my ( $sub_name, $sub_ref ) = each( %$option_value ) ) {
$DIE->( $FMT_INVALID_VALUE, $option_name . "->{ $sub_name }", $sub_ref ) if ref( $sub_ref ) ne 'CODE';
}
$options->{ $option_name } = $option_value;
}
elsif ( $option_name eq '-lib' ) {
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'ARRAY';
$options->{ $option_name } = $option_value;
}
elsif ( $option_name eq '-method' ) {
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value );
$METHOD = $options->{ $option_name } = $option_value;
}
elsif ( $option_name eq '-target' ) { # Do not load module only if its name is undef
$options->{ $option_name } = $option_value if defined( $option_value );
}
elsif ( $option_name eq '-tempdir' ) {
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
$TEMP_DIR = tempdir( CLEANUP => 1, %$option_value );
}
elsif ( $option_name eq '-tempfile' ) {
$DIE->( $FMT_INVALID_VALUE, $option_name, $option_value ) if ref( $option_value ) ne 'HASH';
my $file_handle;
( $file_handle, $TEMP_FILE ) = tempfile( UNLINK => 1, %$option_value );
}
else {
$options->{ $option_name } = $option_value;
}
}

Expand Down
Loading

0 comments on commit 51ee56d

Please sign in to comment.