@@ -1,70 +0,0 @@
-## HOW TO CONTRIBUTE
-
-Thank you for considering contributing to this distribution. This file
-contains instructions that will help you work with the source code.
-
-The distribution is managed with Dist::Zilla. This means than many of the
-usual files you might expect are not in the repository, but are generated
-at release time (e.g. Makefile.PL).
-
-### Getting dependencies
-
-See the included `cpanfile` file for a list of dependencies. If you have
-App::cpanminus 1.6 or later installed, you can use `cpanm` to satisfy
-dependencies like this:
-
- $ cpanm --installdeps .
-
-Otherwise, you can install Module::CPANfile 1.0002 or later and then satisfy
-dependencies with the regular `cpan` client and `cpanfile-dump`:
-
- $ cpan `cpanfile-dump`
-
-### Running tests
-
-You can run tests directly using the `prove` tool:
-
- $ prove -l
- $ prove -lv t/some_test_file.t
-
-For most distributions, `prove` is entirely sufficent for you to test any
-patches you have.
-
-### Code style and tidying
-
-Please try to match any existing coding style. If there is a `.perltidyrc`
-file, please install Perl::Tidy and use perltidy before submitting patches.
-
-If there is a `tidyall.ini` file, you can also install Code::TidyAll and run
-`tidyall` on a file or `tidyall -a` to tidy all files.
-
-### Patching documentation
-
-Much of the documentation Pod is generated at release time.
-Depending on the distribution, some documentation may be written in a Pod
-dialect called WikiDoc. (See Pod::WikiDoc on CPAN.)
-
-If you would like to submit a documentation edit, please limit yourself to the
-documentation you see.
-
-If you see typos or documentation issues in the generated docs, please
-email or open a bug ticket instead of patching.
-
-### Learning Dist::Zilla
-
-Dist::Zilla is a very powerful authoring tool, but requires a number of
-author-specific plugins. If you would like to use it for contributing,
-install it from CPAN, then run one of the following commands, depending on
-your CPAN client:
-
- $ cpan `dzil authordeps`
- $ dzil authordeps | cpanm
-
-Once installed, here are some dzil commands you might try:
-
- $ dzil build
- $ dzil test
- $ dzil xtest
-
-You can learn more about Dist::Zilla at http://dzil.org/
-
@@ -0,0 +1,87 @@
+## HOW TO CONTRIBUTE
+
+Thank you for considering contributing to this distribution. This file
+contains instructions that will help you work with the source code.
+
+The distribution is managed with Dist::Zilla. This means than many of the
+usual files you might expect are not in the repository, but are generated at
+release time, as is much of the documentation. Some generated files are
+kept in the repository as a convenience (e.g. Makefile.PL or cpanfile).
+
+Generally, **you do not need Dist::Zilla to contribute patches**. You do need
+Dist::Zilla to create a tarball. See below for guidance.
+
+### Getting dependencies
+
+If you have App::cpanminus 1.6 or later installed, you can use `cpanm` to
+satisfy dependencies like this:
+
+ $ cpanm --installdeps .
+
+Otherwise, look for either a `Makefile.PL` or `cpanfile` file for
+a list of dependencies to satisfy.
+
+### Running tests
+
+You can run tests directly using the `prove` tool:
+
+ $ prove -l
+ $ prove -lv t/some_test_file.t
+
+For most of my distributions, `prove` is entirely sufficient for you to test any
+patches you have. I use `prove` for 99% of my testing during development.
+
+### Code style and tidying
+
+Please try to match any existing coding style. If there is a `.perltidyrc`
+file, please install Perl::Tidy and use perltidy before submitting patches.
+
+If there is a `tidyall.ini` file, you can also install Code::TidyAll and run
+`tidyall` on a file or `tidyall -a` to tidy all files.
+
+### Patching documentation
+
+Much of the documentation Pod is generated at release time. Some is
+generated boilerplate; other documentation is built from pseudo-POD
+directives in the source like C<=method> or C<=func>.
+
+If you would like to submit a documentation edit, please limit yourself to
+the documentation you see.
+
+If you see typos or documentation issues in the generated docs, please
+email or open a bug ticket instead of patching.
+
+### Installing and using Dist::Zilla
+
+Dist::Zilla is a very powerful authoring tool, optimized for maintaining a
+large number of distributions with a high degree of automation, but it has a
+large dependency chain, a bit of a learning curve and requires a number of
+author-specific plugins.
+
+To install it from CPAN, I recommend one of the following approaches for
+the quickest installation:
+
+ # using CPAN.pm, but bypassing non-functional pod tests
+ $ cpan TAP::Harness::Restricted
+ $ PERL_MM_USE_DEFAULT=1 HARNESS_CLASS=TAP::Harness::Restricted cpan Dist::Zilla
+
+ # using cpanm, bypassing *all* tests
+ $ cpanm -n Dist::Zilla
+
+In either case, it's probably going to take about 10 minutes. Go for a walk,
+go get a cup of your favorite beverage, take a bathroom break, or whatever.
+When you get back, Dist::Zilla should be ready for you.
+
+Then you need to install any plugins specific to this distribution:
+
+ $ cpan `dzil authordeps`
+ $ dzil authordeps | cpanm
+
+Once installed, here are some dzil commands you might try:
+
+ $ dzil build
+ $ dzil test
+ $ dzil xtest
+
+You can learn more about Dist::Zilla at http://dzil.org/
+
@@ -1,5 +1,14 @@
Revision history for Perl module Test::Number::Delta
+1.05 2014-11-24 11:08:11-05:00 America/New_York
+
+ [Fixed]
+
+ - relative comparison of array reference elements now works as intended
+
+ - diagnostics of delta_not_ok and delta_not_within clarified under
+ relative comparison
+
1.04 2013-11-20 18:43:32 America/New_York
- Modernized distribution metadata and licensing
@@ -1,4 +1,4 @@
-This software is Copyright (c) 2013 by David Golden.
+This software is Copyright (c) 2014 by David Golden.
This is free software, licensed under:
@@ -1,4 +1,5 @@
-CONTRIBUTING
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.025.
+CONTRIBUTING.mkdn
Changes
LICENSE
MANIFEST
@@ -10,6 +11,7 @@ cpanfile
dist.ini
lib/Test/Number/Delta.pm
perlcritic.rc
+t/00-report-prereqs.dd
t/00-report-prereqs.t
t/01-module-basics.t
t/02-delta.t
@@ -4,7 +4,7 @@
"David Golden <dagolden@cpan.org>"
],
"dynamic_config" : 0,
- "generated_by" : "Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830",
+ "generated_by" : "Dist::Zilla version 5.025, CPAN::Meta::Converter version 2.142690",
"license" : [
"apache_2_0"
],
@@ -27,13 +27,14 @@
"prereqs" : {
"configure" : {
"requires" : {
- "ExtUtils::MakeMaker" : "6.17"
+ "ExtUtils::MakeMaker" : "6.17",
+ "perl" : "5.006"
}
},
"develop" : {
"requires" : {
- "Dist::Zilla" : "5.006",
- "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.059",
+ "Dist::Zilla" : "5",
+ "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
"File::Spec" : "0",
"File::Temp" : "0",
"IO::Handle" : "0",
@@ -42,7 +43,9 @@
"Test::CPAN::Meta" : "0",
"Test::More" : "0",
"Test::Pod" : "1.41",
- "Test::Pod::Coverage" : "1.08"
+ "Test::Pod::Coverage" : "1.08",
+ "Test::Spelling" : "0.12",
+ "Test::Version" : "1"
}
},
"runtime" : {
@@ -58,22 +61,21 @@
},
"test" : {
"recommends" : {
- "CPAN::Meta" : "0",
- "CPAN::Meta::Requirements" : "0"
+ "CPAN::Meta" : "2.120900"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
- "File::Spec::Functions" : "0",
- "List::Util" : "0",
+ "File::Spec" : "0",
"Test::Builder::Tester" : "1.02",
- "Test::More" : "0"
+ "Test::More" : "0",
+ "perl" : "5.006"
}
}
},
"provides" : {
"Test::Number::Delta" : {
"file" : "lib/Test/Number/Delta.pm",
- "version" : "1.04"
+ "version" : "1.05"
}
},
"release_status" : "stable",
@@ -88,7 +90,7 @@
"web" : "https://github.com/dagolden/Test-Number-Delta"
}
},
- "version" : "1.04",
+ "version" : "1.05",
"x_authority" : "cpan:DAGOLDEN"
}
@@ -3,19 +3,20 @@ abstract: 'Compare the difference between numbers against a given tolerance'
author:
- 'David Golden <dagolden@cpan.org>'
build_requires:
- ExtUtils::MakeMaker: 0
- File::Spec::Functions: 0
- List::Util: 0
- Test::Builder::Tester: 1.02
- Test::More: 0
+ ExtUtils::MakeMaker: '0'
+ File::Spec: '0'
+ Test::Builder::Tester: '1.02'
+ Test::More: '0'
+ perl: '5.006'
configure_requires:
- ExtUtils::MakeMaker: 6.17
+ ExtUtils::MakeMaker: '6.17'
+ perl: '5.006'
dynamic_config: 0
-generated_by: 'Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830'
+generated_by: 'Dist::Zilla version 5.025, CPAN::Meta::Converter version 2.142690'
license: apache
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
+ version: '1.4'
name: Test-Number-Delta
no_index:
directory:
@@ -28,18 +29,18 @@ no_index:
provides:
Test::Number::Delta:
file: lib/Test/Number/Delta.pm
- version: 1.04
+ version: '1.05'
requires:
- Carp: 0
- Exporter: 0
- Test::Builder: 0
- perl: 5.006
- strict: 0
- vars: 0
- warnings: 0
+ Carp: '0'
+ Exporter: '0'
+ Test::Builder: '0'
+ perl: '5.006'
+ strict: '0'
+ vars: '0'
+ warnings: '0'
resources:
bugtracker: https://github.com/dagolden/Test-Number-Delta/issues
homepage: https://github.com/dagolden/Test-Number-Delta
repository: https://github.com/dagolden/Test-Number-Delta.git
-version: 1.04
+version: '1.05'
x_authority: cpan:DAGOLDEN
@@ -1,4 +1,5 @@
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.025.
use strict;
use warnings;
@@ -11,13 +12,13 @@ use ExtUtils::MakeMaker 6.17;
my %WriteMakefileArgs = (
"ABSTRACT" => "Compare the difference between numbers against a given tolerance",
"AUTHOR" => "David Golden <dagolden\@cpan.org>",
- "BUILD_REQUIRES" => {},
"CONFIGURE_REQUIRES" => {
"ExtUtils::MakeMaker" => "6.17"
},
"DISTNAME" => "Test-Number-Delta",
"EXE_FILES" => [],
"LICENSE" => "apache",
+ "MIN_PERL_VERSION" => "5.006",
"NAME" => "Test::Number::Delta",
"PREREQ_PM" => {
"Carp" => 0,
@@ -29,12 +30,11 @@ my %WriteMakefileArgs = (
},
"TEST_REQUIRES" => {
"ExtUtils::MakeMaker" => 0,
- "File::Spec::Functions" => 0,
- "List::Util" => 0,
+ "File::Spec" => 0,
"Test::Builder::Tester" => "1.02",
"Test::More" => 0
},
- "VERSION" => "1.04",
+ "VERSION" => "1.05",
"test" => {
"TESTS" => "t/*.t"
}
@@ -44,9 +44,8 @@ my %WriteMakefileArgs = (
my %FallbackPrereqs = (
"Carp" => 0,
"Exporter" => 0,
- "ExtUtils::MakeMaker" => 0,
- "File::Spec::Functions" => 0,
- "List::Util" => 0,
+ "ExtUtils::MakeMaker" => "6.17",
+ "File::Spec" => 0,
"Test::Builder" => 0,
"Test::Builder::Tester" => "1.02",
"Test::More" => 0,
@@ -3,7 +3,7 @@ NAME
given tolerance
VERSION
- version 1.04
+ version 1.05
SYNOPSIS
# Import test functions
@@ -170,7 +170,7 @@ AUTHOR
David Golden <dagolden@cpan.org>
COPYRIGHT AND LICENSE
- This software is Copyright (c) 2013 by David Golden.
+ This software is Copyright (c) 2014 by David Golden.
This is free software, licensed under:
@@ -8,24 +8,24 @@ requires "warnings" => "0";
on 'test' => sub {
requires "ExtUtils::MakeMaker" => "0";
- requires "File::Spec::Functions" => "0";
- requires "List::Util" => "0";
+ requires "File::Spec" => "0";
requires "Test::Builder::Tester" => "1.02";
requires "Test::More" => "0";
+ requires "perl" => "5.006";
};
on 'test' => sub {
- recommends "CPAN::Meta" => "0";
- recommends "CPAN::Meta::Requirements" => "0";
+ recommends "CPAN::Meta" => "2.120900";
};
on 'configure' => sub {
requires "ExtUtils::MakeMaker" => "6.17";
+ requires "perl" => "5.006";
};
on 'develop' => sub {
- requires "Dist::Zilla" => "5.006";
- requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.059";
+ requires "Dist::Zilla" => "5";
+ requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.072";
requires "File::Spec" => "0";
requires "File::Temp" => "0";
requires "IO::Handle" => "0";
@@ -35,4 +35,6 @@ on 'develop' => sub {
requires "Test::More" => "0";
requires "Test::Pod" => "1.41";
requires "Test::Pod::Coverage" => "1.08";
+ requires "Test::Spelling" => "0.12";
+ requires "Test::Version" => "1";
};
@@ -4,4 +4,4 @@ license = Apache_2_0
copyright_holder = David Golden
[@DAGOLDEN]
-:version = 0.059
+:version = 0.072
@@ -3,7 +3,8 @@ use warnings;
package Test::Number::Delta;
# ABSTRACT: Compare the difference between numbers against a given tolerance
-our $VERSION = '1.04'; # VERSION
+
+our $VERSION = '1.05';
use vars qw (@EXPORT @ISA);
@@ -15,6 +16,103 @@ use Exporter;
@ISA = qw( Exporter );
@EXPORT = qw( delta_not_ok delta_ok delta_within delta_not_within );
+#pod =head1 SYNOPSIS
+#pod
+#pod # Import test functions
+#pod use Test::Number::Delta;
+#pod
+#pod # Equality test with default tolerance
+#pod delta_ok( 1e-5, 2e-5, 'values within 1e-6');
+#pod
+#pod # Inequality test with default tolerance
+#pod delta_not_ok( 1e-5, 2e-5, 'values not within 1e-6');
+#pod
+#pod # Provide specific tolerance
+#pod delta_within( 1e-3, 2e-3, 1e-4, 'values within 1e-4');
+#pod delta_not_within( 1e-3, 2e-3, 1e-4, 'values not within 1e-4');
+#pod
+#pod # Compare arrays or matrices
+#pod @a = ( 3.14, 1.41 );
+#pod @b = ( 3.15, 1.41 );
+#pod delta_ok( \@a, \@b, 'compare @a and @b' );
+#pod
+#pod # Set a different default tolerance
+#pod use Test::Number::Delta within => 1e-5;
+#pod delta_ok( 1.1e-5, 2e-5, 'values within 1e-5'); # ok
+#pod
+#pod # Set a relative tolerance
+#pod use Test::Number::Delta relative => 1e-3;
+#pod delta_ok( 1.01, 1.0099, 'values within 1.01e-3');
+#pod
+#pod
+#pod =head1 DESCRIPTION
+#pod
+#pod At some point or another, most programmers find they need to compare
+#pod floating-point numbers for equality. The typical idiom is to test
+#pod if the absolute value of the difference of the numbers is within a desired
+#pod tolerance, usually called epsilon. This module provides such a function for use
+#pod with L<Test::More>. Usage is similar to other test functions described in
+#pod L<Test::More>. Semantically, the C<delta_within> function replaces this kind
+#pod of construct:
+#pod
+#pod ok ( abs($p - $q) < $epsilon, '$p is equal to $q' ) or
+#pod diag "$p is not equal to $q to within $epsilon";
+#pod
+#pod While there's nothing wrong with that construct, it's painful to type it
+#pod repeatedly in a test script. This module does the same thing with a single
+#pod function call. The C<delta_ok> function is similar, but either uses a global
+#pod default value for epsilon or else calculates a 'relative' epsilon on
+#pod the fly so that epsilon is scaled automatically to the size of the arguments to
+#pod C<delta_ok>. Both functions are exported automatically.
+#pod
+#pod Because checking floating-point equality is not always reliable, it is not
+#pod possible to check the 'equal to' boundary of 'less than or equal to
+#pod epsilon'. Therefore, Test::Number::Delta only compares if the absolute value
+#pod of the difference is B<less than> epsilon (for equality tests) or
+#pod B<greater than> epsilon (for inequality tests).
+#pod
+#pod =head1 USAGE
+#pod
+#pod =head2 use Test::Number::Delta;
+#pod
+#pod With no arguments, epsilon defaults to 1e-6. (An arbitrary choice on the
+#pod author's part.)
+#pod
+#pod =head2 use Test::Number::Delta within => 1e-9;
+#pod
+#pod To specify a different default value for epsilon, provide a C<within> parameter
+#pod when importing the module. The value must be non-zero.
+#pod
+#pod =head2 use Test::Number::Delta relative => 1e-3;
+#pod
+#pod As an alternative to using a fixed value for epsilon, provide a C<relative>
+#pod parameter when importing the module. This signals that C<delta_ok> should
+#pod test equality with an epsilon that is scaled to the size of the arguments.
+#pod Epsilon is calculated as the relative value times the absolute value
+#pod of the argument with the greatest magnitude. Mathematically, for arguments
+#pod 'x' and 'y':
+#pod
+#pod epsilon = relative * max( abs(x), abs(y) )
+#pod
+#pod For example, a relative value of "0.01" would mean that the arguments are equal
+#pod if they differ by less than 1% of the larger of the two values. A relative
+#pod value of 1e-6 means that the arguments must differ by less than 1 millionth
+#pod of the larger value. The relative value must be non-zero.
+#pod
+#pod =head2 Combining with a test plan
+#pod
+#pod use Test::Number::Delta 'no_plan';
+#pod
+#pod # or
+#pod
+#pod use Test::Number::Delta within => 1e-9, tests => 1;
+#pod
+#pod If a test plan has not already been specified, the optional
+#pod parameter for Test::Number::Delta may be followed with a test plan (see
+#pod L<Test::More> for details). If a parameter for Test::Number::Delta is
+#pod given, it must come first.
+#pod
+#pod =cut
my $Test = Test::Builder->new;
my $Epsilon = 1e-6;
@@ -50,14 +148,26 @@ sub import {
#--------------------------------------------------------------------------#
sub _check {
- my ( $p, $q, $epsilon, $name, @indices ) = @_;
+ my ( $p, $q, $e, $name, @indices ) = @_;
+ my $epsilon;
+
+ if ( !defined $e ) {
+ $epsilon =
+ $Relative
+ ? $Relative * ( abs($p) > abs($q) ? abs($p) : abs($q) )
+ : $Epsilon;
+ }
+ else {
+ $epsilon = abs($e);
+ }
+
my ( $ok, $diag ) = ( 1, q{} ); # assume true
if ( ref $p eq 'ARRAY' || ref $q eq 'ARRAY' ) {
if ( @$p == @$q ) {
for my $i ( 0 .. $#{$p} ) {
my @new_indices;
- ( $ok, $diag, @new_indices ) = _check( $p->[$i], $q->[$i], $epsilon, $name,
- scalar @indices ? @indices : (), $i, );
+ ( $ok, $diag, @new_indices ) =
+ _check( $p->[$i], $q->[$i], $e, $name, scalar @indices ? @indices : (), $i, );
if ( not $ok ) {
@indices = @new_indices;
last;
@@ -85,24 +195,78 @@ sub _check {
}
sub _ep_dp {
- my $epsilon = shift;
+ my $epsilon = shift
+ or return;
+ $epsilon = abs($epsilon);
my ($exp) = sprintf( "%e", $epsilon ) =~ m/e(.+)/;
my $ep = $exp < 0 ? -$exp : 1;
my $dp = $ep + 1;
return ( $ep, $dp );
}
+sub _diag_default {
+ my ($ep) = _ep_dp( abs( $Relative || $Epsilon ) );
+ my $diag = "Arguments are equal to within ";
+ $diag .=
+ $Relative
+ ? sprintf( "relative tolerance %.${ep}f", abs($Relative) )
+ : sprintf( "%.${ep}f", abs($Epsilon) );
+ return $diag;
+}
+
+#pod =head1 FUNCTIONS
+#pod
+#pod =cut
#--------------------------------------------------------------------------#
# delta_within()
#--------------------------------------------------------------------------#
+#pod =head2 delta_within
+#pod
+#pod delta_within( $p, $q, $epsilon, '$p and $q are equal within $epsilon' );
+#pod delta_within( \@p, \@q, $epsilon, '@p and @q are equal within $epsilon' );
+#pod
+#pod This function tests for equality within a given value of epsilon. The test is
+#pod true if the absolute value of the difference between $p and $q is B<less than>
+#pod epsilon. If the test is true, it prints an "OK" statement for use in testing.
+#pod If the test is not true, this function prints a failure report and diagnostic.
+#pod Epsilon must be non-zero.
+#pod
+#pod The values to compare may be scalars or references to arrays. If the values
+#pod are references to arrays, the comparison is done pairwise for each index value
+#pod of the array. The pairwise comparison is recursive, so matrices may
+#pod be compared as well.
+#pod
+#pod For example, this code sample compares two matrices:
+#pod
+#pod my @a = ( [ 3.14, 6.28 ],
+#pod [ 1.41, 2.84 ] );
+#pod
+#pod my @b = ( [ 3.14, 6.28 ],
+#pod [ 1.42, 2.84 ] );
+#pod
+#pod delta_within( \@a, \@b, 1e-6, 'compare @a and @b' );
+#pod
+#pod The sample prints the following:
+#pod
+#pod not ok 1 - compare @a and @b
+#pod # At [1][0]: 1.4100000 and 1.4200000 are not equal to within 0.000001
+#pod
+#pod =cut
sub delta_within($$$;$) { ## no critic
my ( $p, $q, $epsilon, $name ) = @_;
croak "Value of epsilon to delta_within must be non-zero"
- if $epsilon == 0;
- $epsilon = abs($epsilon);
+ if !defined($epsilon) || $epsilon == 0;
+ {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ _delta_within( $p, $q, $epsilon, $name );
+ }
+}
+
+sub _delta_within {
+ my ( $p, $q, $epsilon, $name ) = @_;
my ( $ok, $diag, @indices ) = _check( $p, $q, $epsilon, $name );
if (@indices) {
$diag = "At [" . join( "][", @indices ) . "]: $diag";
@@ -114,16 +278,22 @@ sub delta_within($$$;$) { ## no critic
# delta_ok()
#--------------------------------------------------------------------------#
+#pod =head2 delta_ok
+#pod
+#pod delta_ok( $p, $q, '$p and $q are close enough to equal' );
+#pod delta_ok( \@p, \@q, '@p and @q are close enough to equal' );
+#pod
+#pod This function tests for equality within a default epsilon value. See L</USAGE>
+#pod for details on changing the default. Otherwise, this function works the same
+#pod as C<delta_within>.
+#pod
+#pod =cut
sub delta_ok($$;$) { ## no critic
my ( $p, $q, $name ) = @_;
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
- my $e =
- $Relative
- ? $Relative * ( abs($p) > abs($q) ? abs($p) : abs($q) )
- : $Epsilon;
- delta_within( $p, $q, $e, $name );
+ _delta_within( $p, $q, undef, $name );
}
}
@@ -131,29 +301,57 @@ sub delta_ok($$;$) { ## no critic
# delta_not_ok()
#--------------------------------------------------------------------------#
+#pod =head2 delta_not_within
+#pod
+#pod delta_not_within( $p, $q, '$p and $q are different' );
+#pod delta_not_within( \@p, \@q, $epsilon, '@p and @q are different' );
+#pod
+#pod This test compares inequality in excess of a given value of epsilon. The test
+#pod is true if the absolute value of the difference between $p and $q is B<greater
+#pod than> epsilon. For array or matrix comparisons, the test is true if I<any>
+#pod pair of values differs by more than epsilon. Otherwise, this function works
+#pod the same as C<delta_within>.
+#pod
+#pod =cut
sub delta_not_within($$$;$) { ## no critic
my ( $p, $q, $epsilon, $name ) = @_;
croak "Value of epsilon to delta_not_within must be non-zero"
- if $epsilon == 0;
- $epsilon = abs($epsilon);
+ if !defined($epsilon) || $epsilon == 0;
+ {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ _delta_not_within( $p, $q, $epsilon, $name );
+ }
+}
+
+sub _delta_not_within($$$;$) { ## no critic
+ my ( $p, $q, $epsilon, $name ) = @_;
my ( $ok, undef, @indices ) = _check( $p, $q, $epsilon, $name );
$ok = !$ok;
my ( $ep, $dp ) = _ep_dp($epsilon);
- my $diag = sprintf( "Arguments are equal to within %.${ep}f", $epsilon );
+ my $diag =
+ defined($epsilon)
+ ? sprintf( "Arguments are equal to within %.${ep}f", abs($epsilon) )
+ : _diag_default();
return $Test->ok( $ok, $name ) || $Test->diag($diag);
}
+#pod =head2 delta_not_ok
+#pod
+#pod delta_not_ok( $p, $q, '$p and $q are different' );
+#pod delta_not_ok( \@p, \@q, '@p and @q are different' );
+#pod
+#pod This function tests for inequality in excess of a default epsilon value. See
+#pod L</USAGE> for details on changing the default. Otherwise, this function works
+#pod the same as C<delta_not_within>.
+#pod
+#pod =cut
sub delta_not_ok($$;$) { ## no critic
my ( $p, $q, $name ) = @_;
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
- my $e =
- $Relative
- ? $Relative * ( abs($p) > abs($q) ? abs($p) : abs($q) )
- : $Epsilon;
- delta_not_within( $p, $q, $e, $name );
+ _delta_not_within( $p, $q, undef, $name );
}
}
@@ -171,7 +369,7 @@ Test::Number::Delta - Compare the difference between numbers against a given tol
=head1 VERSION
-version 1.04
+version 1.05
=head1 SYNOPSIS
@@ -355,7 +553,7 @@ David Golden <dagolden@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is Copyright (c) 2013 by David Golden.
+This software is Copyright (c) 2014 by David Golden.
This is free software, licensed under:
@@ -7,6 +7,9 @@ allow = $@ $!
[TestingAndDebugging::ProhibitNoStrict]
allow = refs
+[Variables::ProhibitEvilVariables]
+variables = $DB::single
+
# Turn these off
[-BuiltinFunctions::ProhibitStringyEval]
[-ControlStructures::ProhibitPostfixControls]
@@ -0,0 +1,50 @@
+do { my $x = {
+ 'configure' => {
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '6.17',
+ 'perl' => '5.006'
+ }
+ },
+ 'develop' => {
+ 'requires' => {
+ 'Dist::Zilla' => '5',
+ 'Dist::Zilla::PluginBundle::DAGOLDEN' => '0.072',
+ 'File::Spec' => '0',
+ 'File::Temp' => '0',
+ 'IO::Handle' => '0',
+ 'IPC::Open3' => '0',
+ 'Pod::Coverage::TrustPod' => '0',
+ 'Test::CPAN::Meta' => '0',
+ 'Test::More' => '0',
+ 'Test::Pod' => '1.41',
+ 'Test::Pod::Coverage' => '1.08',
+ 'Test::Spelling' => '0.12',
+ 'Test::Version' => '1'
+ }
+ },
+ 'runtime' => {
+ 'requires' => {
+ 'Carp' => '0',
+ 'Exporter' => '0',
+ 'Test::Builder' => '0',
+ 'perl' => '5.006',
+ 'strict' => '0',
+ 'vars' => '0',
+ 'warnings' => '0'
+ }
+ },
+ 'test' => {
+ 'recommends' => {
+ 'CPAN::Meta' => '2.120900'
+ },
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '0',
+ 'File::Spec' => '0',
+ 'Test::Builder::Tester' => '1.02',
+ 'Test::More' => '0',
+ 'perl' => '5.006'
+ }
+ }
+ };
+ $x;
+ }
\ No newline at end of file
@@ -3,125 +3,174 @@
use strict;
use warnings;
-# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.010
+# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.019
use Test::More tests => 1;
use ExtUtils::MakeMaker;
-use File::Spec::Functions;
-use List::Util qw/max/;
-
-my @modules = qw(
- CPAN::Meta
- CPAN::Meta::Requirements
- Carp
- Exporter
- ExtUtils::MakeMaker
- File::Spec::Functions
- List::Util
- Test::Builder
- Test::Builder::Tester
- Test::More
- perl
- strict
- vars
- warnings
+use File::Spec;
+
+# from $version::LAX
+my $lax_version_re =
+ qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )?
+ |
+ (?:\.[0-9]+) (?:_[0-9]+)?
+ ) | (?:
+ v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )?
+ |
+ (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)?
+ )
+ )/x;
+
+# hide optional CPAN::Meta modules from prereq scanner
+# and check if they are available
+my $cpan_meta = "CPAN::Meta";
+my $cpan_meta_pre = "CPAN::Meta::Prereqs";
+my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic
+
+# Verify requirements?
+my $DO_VERIFY_PREREQS = 1;
+
+sub _max {
+ my $max = shift;
+ $max = ( $_ > $max ) ? $_ : $max for @_;
+ return $max;
+}
+
+sub _merge_prereqs {
+ my ($collector, $prereqs) = @_;
+
+ # CPAN::Meta::Prereqs object
+ if (ref $collector eq $cpan_meta_pre) {
+ return $collector->with_merged_prereqs(
+ CPAN::Meta::Prereqs->new( $prereqs )
+ );
+ }
+
+ # Raw hashrefs
+ for my $phase ( keys %$prereqs ) {
+ for my $type ( keys %{ $prereqs->{$phase} } ) {
+ for my $module ( keys %{ $prereqs->{$phase}{$type} } ) {
+ $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module};
+ }
+ }
+ }
+
+ return $collector;
+}
+
+my @include = qw(
+
);
-my %exclude = map {; $_ => 1 } qw(
+my @exclude = qw(
);
-my ($source) = grep { -f $_ } qw/MYMETA.json MYMETA.yml META.json/;
-$source = "META.yml" unless defined $source;
+# Add static prereqs to the included modules list
+my $static_prereqs = do 't/00-report-prereqs.dd';
-# replace modules with dynamic results from MYMETA.json if we can
-# (hide CPAN::Meta from prereq scanner)
-my $cpan_meta = "CPAN::Meta";
-my $cpan_meta_req = "CPAN::Meta::Requirements";
-my $all_requires;
-if ( -f $source && eval "require $cpan_meta" ) { ## no critic
- if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
-
- # Get ALL modules mentioned in META (any phase/type)
- my $prereqs = $meta->prereqs;
- delete $prereqs->{develop} if not $ENV{AUTHOR_TESTING};
- my %uniq = map {$_ => 1} map { keys %$_ } map { values %$_ } values %$prereqs;
- $uniq{$_} = 1 for @modules; # don't lose any static ones
- @modules = sort grep { ! $exclude{$_} } keys %uniq;
-
- # If verifying, merge 'requires' only for major phases
- if ( 1 ) {
- $prereqs = $meta->effective_prereqs; # get the object, not the hash
- if (eval "require $cpan_meta_req; 1") { ## no critic
- $all_requires = $cpan_meta_req->new;
- for my $phase ( qw/configure build test runtime/ ) {
- $all_requires->add_requirements(
- $prereqs->requirements_for($phase, 'requires')
- );
- }
- }
+# Merge all prereqs (either with ::Prereqs or a hashref)
+my $full_prereqs = _merge_prereqs(
+ ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ),
+ $static_prereqs
+);
+
+# Add dynamic prereqs to the included modules list (if we can)
+my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
+if ( $source && $HAS_CPAN_META ) {
+ if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
+ $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs);
}
- }
+}
+else {
+ $source = 'static metadata';
}
-my @reports = [qw/Version Module/];
+my @full_reports;
my @dep_errors;
-my $req_hash = defined($all_requires) ? $all_requires->as_string_hash : {};
-
-for my $mod ( @modules ) {
- next if $mod eq 'perl';
- my $file = $mod;
- $file =~ s{::}{/}g;
- $file .= ".pm";
- my ($prefix) = grep { -e catfile($_, $file) } @INC;
- if ( $prefix ) {
- my $ver = MM->parse_version( catfile($prefix, $file) );
- $ver = "undef" unless defined $ver; # Newer MM should do this anyway
- push @reports, [$ver, $mod];
-
- if ( 1 && $all_requires ) {
- my $req = $req_hash->{$mod};
- if ( defined $req && length $req ) {
- if ( ! defined eval { version->parse($ver) } ) {
- push @dep_errors, "$mod version '$ver' cannot be parsed (version '$req' required)";
- }
- elsif ( ! $all_requires->accepts_module( $mod => $ver ) ) {
- push @dep_errors, "$mod version '$ver' is not in required range '$req'";
+my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs;
+
+# Add static includes into a fake section
+for my $mod (@include) {
+ $req_hash->{other}{modules}{$mod} = 0;
+}
+
+for my $phase ( qw(configure build test runtime develop other) ) {
+ next unless $req_hash->{$phase};
+ next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING});
+
+ for my $type ( qw(requires recommends suggests conflicts modules) ) {
+ next unless $req_hash->{$phase}{$type};
+
+ my $title = ucfirst($phase).' '.ucfirst($type);
+ my @reports = [qw/Module Want Have/];
+
+ for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) {
+ next if $mod eq 'perl';
+ next if grep { $_ eq $mod } @exclude;
+
+ my $file = $mod;
+ $file =~ s{::}{/}g;
+ $file .= ".pm";
+ my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC;
+
+ my $want = $req_hash->{$phase}{$type}{$mod};
+ $want = "undef" unless defined $want;
+ $want = "any" if !$want && $want == 0;
+
+ my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required";
+
+ if ($prefix) {
+ my $have = MM->parse_version( File::Spec->catfile($prefix, $file) );
+ $have = "undef" unless defined $have;
+ push @reports, [$mod, $want, $have];
+
+ if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) {
+ if ( $have !~ /\A$lax_version_re\z/ ) {
+ push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)";
+ }
+ elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) {
+ push @dep_errors, "$mod version '$have' is not in required range '$want'";
+ }
+ }
+ }
+ else {
+ push @reports, [$mod, $want, "missing"];
+
+ if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) {
+ push @dep_errors, "$mod is not installed ($req_string)";
+ }
+ }
}
- }
- }
- }
- else {
- push @reports, ["missing", $mod];
+ if ( @reports ) {
+ push @full_reports, "=== $title ===\n\n";
+
+ my $ml = _max( map { length $_->[0] } @reports );
+ my $wl = _max( map { length $_->[1] } @reports );
+ my $hl = _max( map { length $_->[2] } @reports );
+ splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl];
- if ( 1 && $all_requires ) {
- my $req = $req_hash->{$mod};
- if ( defined $req && length $req ) {
- push @dep_errors, "$mod is not installed (version '$req' required)";
- }
+ push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports;
+ push @full_reports, "\n";
+ }
}
- }
}
-if ( @reports ) {
- my $vl = max map { length $_->[0] } @reports;
- my $ml = max map { length $_->[1] } @reports;
- splice @reports, 1, 0, ["-" x $vl, "-" x $ml];
- diag "\nVersions for all modules listed in $source (including optional ones):\n",
- map {sprintf(" %*s %*s\n",$vl,$_->[0],-$ml,$_->[1])} @reports;
+if ( @full_reports ) {
+ diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports;
}
if ( @dep_errors ) {
- diag join("\n",
- "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n",
- "The following REQUIRED prerequisites were not satisfied:\n",
- @dep_errors,
- "\n"
- );
+ diag join("\n",
+ "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n",
+ "The following REQUIRED prerequisites were not satisfied:\n",
+ @dep_errors,
+ "\n"
+ );
}
pass;
-# vim: ts=2 sts=2 sw=2 et:
+# vim: ts=4 sts=4 sw=4 et:
@@ -1,6 +1,6 @@
use strict;
-use Test::Builder::Tester tests => 12;
+use Test::Builder::Tester tests => 14;
use Test::Number::Delta relative => 1e-2;
#--------------------------------------------------------------------------#
@@ -19,6 +19,12 @@ test_diag("-50.00 and -49.40 are not equal to within 0.5");
delta_ok( -50, -49.4, "foo" );
test_test("delta_ok fail works");
+test_out("not ok 1 - foo");
+test_fail(+2);
+test_diag("At [0]: -50.00 and -49.40 are not equal to within 0.5");
+delta_ok( [-50], [-49.4], "foo" );
+test_test("delta_ok fail works");
+
test_out("ok 1 - foo");
delta_ok( 10e-5, 9.91e-5, "foo" );
test_test("delta_ok works");
@@ -41,16 +47,22 @@ test_test("delta_ok works");
test_out("not ok 1 - foo");
test_fail(+2);
-test_diag("Arguments are equal to within 0.00001");
+test_diag("Arguments are equal to within relative tolerance 0.01");
delta_not_ok( 1e-3, 9.91e-4, "foo" );
test_test("delta_not_ok fail works");
test_out("not ok 1 - foo");
test_fail(+2);
-test_diag("Arguments are equal to within 0.5");
+test_diag("Arguments are equal to within relative tolerance 0.01");
delta_not_ok( -50, -49.6, "foo" );
test_test("delta_no_ok fail works");
+test_out("not ok 1 - foo");
+test_fail(+2);
+test_diag("Arguments are equal to within relative tolerance 0.01");
+delta_not_ok( [-50], [-49.6], "foo" );
+test_test("delta_no_ok fail works");
+
test_out("ok 1 - foo");
delta_not_ok( 10e-5, 9.89e-5, "foo" );
test_test("delta_not_ok works");
@@ -41,13 +41,13 @@ test_test("delta_ok works");
test_out("not ok 1 - foo");
test_fail(+2);
-test_diag("Arguments are equal to within 0.00001");
+test_diag("Arguments are equal to within relative tolerance 0.01");
delta_not_ok( 1e-3, 9.91e-4, "foo" );
test_test("delta_not_ok fail works");
test_out("not ok 1 - foo");
test_fail(+2);
-test_diag("Arguments are equal to within 0.5");
+test_diag("Arguments are equal to within relative tolerance 0.01");
delta_not_ok( -50, -49.6, "foo" );
test_test("delta_no_ok fail works");
@@ -1,11 +1,12 @@
+use 5.006;
use strict;
use warnings;
-# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.037
-
-use Test::More tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.051
+use Test::More;
+plan tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
my @module_files = (
'Test/Number/Delta.pm'
@@ -24,11 +25,12 @@ use File::Spec;
use IPC::Open3;
use IO::Handle;
+open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
+
my @warnings;
for my $lib (@module_files)
{
# see L<perlfaq8/How can I capture STDERR from an external command?>
- open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
my $stderr = IO::Handle->new;
my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
@@ -46,6 +48,7 @@ for my $lib (@module_files)
-is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING};
+is(scalar(@warnings), 0, 'no warnings found')
+ or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ) if $ENV{AUTHOR_TESTING};
@@ -2,7 +2,7 @@ use strict;
use warnings;
use Test::More;
-# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006001
+# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006008
use Test::Spelling 0.12;
use Pod::Wordlist;
@@ -1,7 +1,6 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::MetaTests.
-use Test::More;
+use Test::CPAN::Meta;
-eval "use Test::CPAN::Meta";
-plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@;
meta_yaml_ok();
@@ -1,13 +1,7 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests.
-use Test::More;
-
-eval "use Test::Pod::Coverage 1.08";
-plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
- if $@;
-
-eval "use Pod::Coverage::TrustPod";
-plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
- if $@;
+use Test::Pod::Coverage 1.08;
+use Pod::Coverage::TrustPod;
all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
@@ -1,7 +1,6 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
use Test::More;
-
-eval "use Test::Pod 1.41";
-plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;
+use Test::Pod 1.41;
all_pod_files_ok();
@@ -2,8 +2,8 @@ use strict;
use warnings;
use Test::More;
-# generated by Dist::Zilla::Plugin::Test::Version 0.002004
-BEGIN { eval "use Test::Version; 1;" or die $@; }
+# generated by Dist::Zilla::Plugin::Test::Version 0.003001
+use Test::Version;
my @imports = ( 'version_all_ok' );