[libcode-tidyall-perl] 09/374: add class-based tests

Jonas Smedegaard js at alioth.debian.org
Sun Sep 29 22:25:39 UTC 2013


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository libcode-tidyall-perl.

commit 805b7bdd1fcd34d1385181d5b4042422dd60e8e5
Author: Jonathan Swartz <swartz at pobox.com>
Date:   Wed Jun 6 10:07:37 2012 -0700

    add class-based tests
---
 bin/tidyall                                |   81 +++++++++++++---------------
 dist.ini                                   |   11 ++--
 lib/Code/TidyAll.pm                        |   78 +++++++++++++++------------
 lib/Code/TidyAll/Plugin.pm                 |    2 +-
 lib/Code/TidyAll/Plugin/perlcritic.pm      |    2 +-
 lib/Code/TidyAll/Test/Class.pm             |    8 +++
 lib/Code/TidyAll/Test/Plugin/ReverseFoo.pm |   16 ++++++
 lib/Code/TidyAll/Test/Plugin/UpperText.pm  |   20 +++++++
 lib/Code/TidyAll/Util.pm                   |    5 +-
 lib/Code/TidyAll/t/Basic.pm                |   77 ++++++++++++++++++++++++++
 t/Basic.t                                  |    3 ++
 t/use.t                                    |   14 -----
 12 files changed, 219 insertions(+), 98 deletions(-)

diff --git a/bin/tidyall b/bin/tidyall
index 3538c82..3f85de3 100755
--- a/bin/tidyall
+++ b/bin/tidyall
@@ -16,14 +16,14 @@ my %params;
 my $class = 'Code::TidyAll';
 
 GetOptions(
-    'backup_dir'  => \$params{backup_dir},
-    'backup_keep' => \$params{backup_keep},
-    'cache_dir'   => \$params{cache_dir},
-    'class'       => \$class,
-    'data_dir'    => \$params{data_dir},
-    'c|conf'      => \$params{conf_file},
-    'h|help'      => \$help,
-    'r|recursive' => \$params{recursive},
+    'backup-purge' => \$params{backup_purge},
+    'class'        => \$class,
+    'data-dir'     => \$params{data_dir},
+    'no-backup'    => \$params{no_backup},
+    'no-cache'     => \$params{no_cache},
+    'c|conf'       => \$params{conf_file},
+    'h|help'       => \$help,
+    'r|recursive'  => \$params{recursive},
 ) or usage();
 
 usage("-c|--conf required") if !$params{conf_file};
@@ -32,9 +32,7 @@ die "cannot load '$class'" unless can_load($class);
 my @paths = @ARGV or usage("path(s) required");
 
 my $ct = $class->new(%params);
-foreach my $path (@paths) {
-    $ct->process_path($path);
-}
+$ct->process_paths($path);
 
 1;
 
@@ -47,27 +45,21 @@ tidyall - Your all-in-one code tidier and validator
 =head1 SYNOPSIS
 
     # Process one or more specific files
-    tidyall [-c /path/to/config] file [file...]
+    tidyall -c /path/to/config file [file...]
 
     # Process all files under a directory
-    tidyall [-c /path/to/config] -r dir
-
-    # Process all files ready to commit according to git/svn status
-    tidyall [-c /path/to/config] -g dir
-    tidyall [-c /path/to/config] -s dir
+    tidyall -c /path/to/config -r dir
 
 =head1 OPTIONS
 
- -c, --conf          Configuration file; default is ~/.tidyallrc
- -g, --git-mode      Only process locally modified files according to git status
- -h, --help          Print help message
- -r, --recursive     Descend into directories recursively
- -s, --svn-mode      Only process locally modified files according to svn status
- --backup-dir        Where to backup files before processing. Defaults to data_dir/backup
- --backup-keep       How long to keep backup files. Defaults to "1h"
- --cache-dir         Where to keep the last-processed cache. Defaults to data_dir/cache
- --class             Optionally specify a Code::TidyAll subclass
- --data_dir          Container for a number of subdirs. Defaults to dir of conf file
+ -c, --conf       Required configuration file
+ -h, --help       Print help message
+ -r, --recursive  Descend into directories recursively
+ --backup-purge   When backup files can be purged. Defaults to "1d"
+ --class          Code::TidyAll subclass to use. Defaults to "Code::TidyAll"
+ --data-dir       Container for backups, cache, etc. Defaults to dir of conf file
+ --no-backup      Don't backup files
+ --no-cache       Don't cache last processed times; process all files every time
 
 =head1 DESCRIPTION
 
@@ -75,9 +67,9 @@ There are a lot of great code tidiers and validators out there. C<tidyall>
 makes them available from a single unified interface.
 
 You can run C<tidyall> on a single file or an entire hierarchy of files, and
-configure which tidiers/validators are applied to which types of files. Files
-are backed up to a separate directory before processing, and for maximum
-efficiency only files that have changed since the last time will be processed.
+configure which tidiers/validators are applied to which types of files.
+C<tidyall> will back up files beforehand, and for efficiency will only consider
+files that have changed since they were last processed.
 
 =head2 What's a tidier? What's a validator?
 
@@ -94,8 +86,9 @@ formed Perl.
 
 =head1 CONFIGURATION
 
-An INI-style config file is required to use C<tidyall>. It can be specified
-with -c, or left to the default ~/.tidyallrc.
+An INI-style config file, specified with -c, is required to use C<tidyall>. If
+the path is of the form I<dir>/.../I<file>, it will look upwards from I<dir>
+for I<file>.
 
 Here's a sample config file:
 
@@ -154,25 +147,27 @@ C<include>.
 
 =head1 DATA DIRECTORY
 
-By default, C<tidyall> will keep its cache and backups (see below) in a single
-data directory. It defaults to
+C<tidyall> keeps cache and backup files (below) under a data directory. It can
+be specified with C<--data-dir>; by default it is a directory named
+".tidyall.d" in the same path as the config file.
 
 =head1 LAST-PROCESSED CACHE
 
-C<tidyall> keeps track of each file's signature after it was last
-processed. On subsequent runs, it will only process a file if its
-signature has changed.
+C<tidyall> keeps track of each file's signature after it was last processed. On
+subsequent runs, it will only process a file if its signature has changed.
+
+You can turn off this behavior with C<--no-cache>.
+
 =head1 BACKUPS
 
-C<tidyall> will backup each file before overwriting it. The backups are kept in
-a separate directory hierarchy, specified by C<--backup-dir> and defaulting to
-C<data_dir/backup>. A new backup file will be created for each processing.
+C<tidyall> will backup each file before modifying it. The timestamped backups
+are kept in a separate directory hierarchy under the data dir.
 
 Old backup files will be purged automatically as part of occasional C<tidyall>
-runs. The duration specified in C<--backup-keep> indicates both the minimum
+runs. The duration specified in C<--backup-purge> indicates both the minimum
 amount of time backups should be kept, and the frequency that purges should be
 run. It may be specified as "30min" or "4h" or any string acceptable to
-L<Time::Duration::Parse>.
+L<Time::Duration::Parse>. It defaults to "1d".
 
-You can disable backups by specifying C<--backup-keep 0>.
+You can turn off backups with C<--no-backups>.
 
diff --git a/dist.ini b/dist.ini
index 71fe659..44aafca 100644
--- a/dist.ini
+++ b/dist.ini
@@ -34,12 +34,17 @@ file = lib/Code/TidyAll/Util.pm
 [PruneCruft]
 
 [Prereqs / RuntimeRequires]
+Capture::Tiny = 0
+Date::Format = 0
+Digest::SHA1 = 0
+File::Find = 0
+File::Slurp = 0
+Hash::MoreUtils = 0
+Time::Duration::Parse = 0
+Try::Tiny = 0
 
 [Prereqs / TestRequires]
-Hash::MoreUtils = 0
 Test::More = 0
-JSON::XS = 0
-Digest::SHA1 = 0
 
 ; These need to be at the bottom
 [InstallGuide]
diff --git a/lib/Code/TidyAll.pm b/lib/Code/TidyAll.pm
index ae4db7e..b96b6da 100644
--- a/lib/Code/TidyAll.pm
+++ b/lib/Code/TidyAll.pm
@@ -2,22 +2,25 @@ package Code::TidyAll;
 use Cwd qw(realpath);
 use Config::INI::Reader;
 use Code::TidyAll::Cache;
-use Code::TidyAll::Util qw(can_load read_file);
+use Code::TidyAll::Util qw(can_load dirname mkpath read_file write_file);
+use Date::Format;
 use Digest::SHA1 qw(sha1_hex);
 use File::Find qw(find);
-use JSON::XS qw(encode_json);
+use Time::Duration::Parse qw(parse_duration);
 use strict;
 use warnings;
 
 # Incoming parameters
 use Object::Tiny qw(
-  backup_dir
+  backup_purge
   cache
-  cache_dir
   conf_file
   data_dir
+  no_backups
+  no_cache
   plugins
   recursive
+  verbose
 );
 
 # Internal
@@ -48,21 +51,19 @@ sub new {
         if ( ref($conf_params) ne 'HASH' ) {
             die "'$conf_file' did not evaluate to a hash";
         }
-        my $main_params = delete( $conf_params_ > {_} ) || {};
+        my $main_params = delete( $conf_params->{'_'} ) || {};
         %params = ( plugins => $conf_params, %$main_params, %params );
+        $params{data_dir} ||= join( "/", dirname($conf_file), ".tidyall.d" );
     }
 
     my $self = $class->SUPER::new(%params);
-    die "plugins required" unless $self->{plugins};
+    die "conf_file or plugins required"  unless $self->{plugins};
+    die "conf_file or data_dir required" unless $self->{data_dir};
 
-    if ( defined( $self->data_dir ) ) {
-        $self->{backup_dir} ||= $self->data_dir . "/backup";
-        $self->{cache_dir}  ||= $self->data_dir . "/cache";
-    }
-    if ( defined( $self->cache_dir ) ) {
-        $self->{cache} ||= Code::TidyAll::Cache->new( cache_dir => $self->cache_dir );
-    }
-    $self->{base_sig} = $self->_sig( [ $Code::TidyAll::VERSION, $self->plugins ] );
+    $self->{cache} ||= Code::TidyAll::Cache->new( cache_dir => $self->data_dir . "/cache" )
+      unless $self->no_cache;
+    $self->{base_sig} = $self->_sig( [ $Code::TidyAll::VERSION || 0, $self->plugins ] );
+    $self->{backup_purge} = parse_duration( $self->{backup_purge} || "1 day" );
 
     my $plugins = $self->plugins;
     $self->{plugin_objects} =
@@ -89,6 +90,13 @@ sub load_plugin {
     }
 }
 
+sub process_paths {
+    my ( $self, @paths ) = @_;
+    foreach my $path (@paths) {
+        $self->process_path($path);
+    }
+}
+
 sub process_path {
     my ( $self, $path ) = @_;
 
@@ -110,19 +118,33 @@ sub process_dir {
 sub process_file {
     my ( $self, $file ) = @_;
     my $cache = $self->cache;
-    if ( !$cache || ( ( $cache->get($file) || '' ) ne $self->_file_sig($file) ) ) {
+    if ( !$cache || ( ( $cache->get("sig/$file") || '' ) ne $self->_file_sig($file) ) ) {
         my $matched = 0;
         foreach my $plugin ( @{ $self->plugin_objects } ) {
             if ( $plugin->matcher->($file) ) {
-                print "$file\n" if !$matched++;
+                if ( !$matched++ ) {
+                    print "$file\n";
+                    $self->backup_file($file);
+                }
                 eval { $plugin->process_file($file) };
                 if ( my $error = $@ ) {
-                    printf( "*** '%s': %s\n", $plugin->name, $error );
+                    printf STDERR "*** '%s': %s\n", $plugin->name, $error;
                     return;
                 }
             }
         }
-        $cache->set( $file, $self->_file_sig($file) ) if $cache;
+        $cache->set( "sig/$file", $self->_file_sig($file) ) if $cache;
+    }
+}
+
+sub backup_file {
+    my ( $self, $file ) = @_;
+    unless ( $self->no_backups ) {
+        my $backup_file = join( "",
+            $self->data_dir, "/backups", realpath($file), "-",
+            time2str( "%Y-%m-%d-%H-%M-%S", time ) );
+        mkpath( dirname($backup_file), 0, 0775 );
+        write_file( $backup_file, read_file($file) );
     }
 }
 
@@ -155,7 +177,7 @@ sub _file_sig {
 
 sub _sig {
     my ( $self, $data ) = @_;
-    return sha1_hex( encode_json($data) );
+    return sha1_hex( join( ",", @$data ) );
 }
 
 1;
@@ -235,26 +257,16 @@ whether it should be excluded. This overrides C<include> above.
 
 Options specific to the plugin to be used for its tidying/validation.
 
-=item cache
-
-Optional. A cache object, or a hashref of parameters to pass to L<CHI|CHI> to
-construct a cache. If provided, this will be used to ensure that each file is
-only processed if it did not change since the last time it was processed.
-
 =back
 
-=item backup_dir
-
-Where to backup files before processing. Defaults to C<data_dir>/backup.
-
-=item cache_dir
+=item cache
 
-A cache directory, used to ensure that files are only processed when they or
-the configuration has changed. Defaults to C<data_dir>/cache.
+A cache object, or a hashref of parameters to pass to L<CHI|CHI> to construct a
+cache. This overrides the default cache.
 
 =item data_dir
 
-Default parent directory for C<backup_dir> and C<cache_dir>.
+Data directory for backups and cache.
 
 =item recursive
 
diff --git a/lib/Code/TidyAll/Plugin.pm b/lib/Code/TidyAll/Plugin.pm
index d3f171f..dec67d1 100644
--- a/lib/Code/TidyAll/Plugin.pm
+++ b/lib/Code/TidyAll/Plugin.pm
@@ -40,7 +40,7 @@ sub _build_include {
     return
          $self->conf->{include}
       || $self->defaults->{include}
-      || die sprintf( "cannot determine include condition for plugin '%s'", $self->name );
+      || die sprintf( "did not specify include for plugin '%s', and no default", $self->name );
 }
 
 sub _build_exclude {
diff --git a/lib/Code/TidyAll/Plugin/perlcritic.pm b/lib/Code/TidyAll/Plugin/perlcritic.pm
index 2f2d7f0..98d6443 100644
--- a/lib/Code/TidyAll/Plugin/perlcritic.pm
+++ b/lib/Code/TidyAll/Plugin/perlcritic.pm
@@ -1,5 +1,5 @@
 package Code::TidyAll::Plugin::PerlCritic;
-use Code::TidyAll::Util qw(write_file tempdir_simple);
+use Code::TidyAll::Util qw(write_file);
 use Perl::Critic::Command qw();
 use Capture::Tiny qw(capture_merged);
 use strict;
diff --git a/lib/Code/TidyAll/Test/Class.pm b/lib/Code/TidyAll/Test/Class.pm
new file mode 100644
index 0000000..38a053e
--- /dev/null
+++ b/lib/Code/TidyAll/Test/Class.pm
@@ -0,0 +1,8 @@
+package Code::TidyAll::Test::Class;
+use Test::Class::Most;
+use strict;
+use warnings;
+
+__PACKAGE__->SKIP_CLASS("abstract base class");
+
+1;
diff --git a/lib/Code/TidyAll/Test/Plugin/ReverseFoo.pm b/lib/Code/TidyAll/Test/Plugin/ReverseFoo.pm
new file mode 100644
index 0000000..6abe867
--- /dev/null
+++ b/lib/Code/TidyAll/Test/Plugin/ReverseFoo.pm
@@ -0,0 +1,16 @@
+package Code::TidyAll::Test::Plugin::ReverseFoo;
+use Code::TidyAll::Util qw(read_file write_file);
+use base qw(Code::TidyAll::Plugin);
+use strict;
+use warnings;
+
+sub defaults {
+    return { include => qr/foo[^\/]+$/ };
+}
+
+sub process_file {
+    my ( $self, $file ) = @_;
+    write_file( $file, scalar( reverse( read_file($file) ) ) );
+}
+
+1;
diff --git a/lib/Code/TidyAll/Test/Plugin/UpperText.pm b/lib/Code/TidyAll/Test/Plugin/UpperText.pm
new file mode 100644
index 0000000..4f7a2f1
--- /dev/null
+++ b/lib/Code/TidyAll/Test/Plugin/UpperText.pm
@@ -0,0 +1,20 @@
+package Code::TidyAll::Test::Plugin::UpperText;
+use base qw(Code::TidyAll::Plugin);
+use strict;
+use warnings;
+
+sub defaults {
+    return { include => qr/\.txt$/ };
+}
+
+sub process_source {
+    my ( $self, $source ) = @_;
+    if ( $source =~ /^[A-Z]*$/i ) {
+        return uc($source);
+    }
+    else {
+        die "non-alpha content found";
+    }
+}
+
+1;
diff --git a/lib/Code/TidyAll/Util.pm b/lib/Code/TidyAll/Util.pm
index 6c35947..e003afa 100644
--- a/lib/Code/TidyAll/Util.pm
+++ b/lib/Code/TidyAll/Util.pm
@@ -8,7 +8,7 @@ use strict;
 use warnings;
 use base qw(Exporter);
 
-our @EXPORT_OK = qw(basename can_load dirname mkpath read_file tempdir_simple write_file );
+our @EXPORT_OK = qw(can_load dirname mkpath read_file tempdir_simple write_file );
 
 sub can_load {
 
@@ -34,8 +34,7 @@ sub can_load {
 }
 
 sub tempdir_simple {
-    my ($template) = @_;
-
+    my $template = shift || 'Code-TidyAll-XXXX';
     return tempdir( $template, TMPDIR => 1, CLEANUP => 1 );
 }
 
diff --git a/lib/Code/TidyAll/t/Basic.pm b/lib/Code/TidyAll/t/Basic.pm
new file mode 100644
index 0000000..8b7fe02
--- /dev/null
+++ b/lib/Code/TidyAll/t/Basic.pm
@@ -0,0 +1,77 @@
+package Code::TidyAll::t::Basic;
+use Code::TidyAll::Util qw(mkpath read_file tempdir_simple write_file);
+use Code::TidyAll;
+use File::Basename;
+use File::Path;
+use Capture::Tiny qw(capture);
+use Test::Class::Most parent => 'Code::TidyAll::Test::Class';
+
+sub tidy {
+    my ( $self, %params ) = @_;
+    my $desc = $params{desc};
+
+    my $temp_dir    = tempdir_simple();
+    my $content_dir = "$temp_dir/content";
+    my $data_dir    = "$temp_dir/data";
+    mkpath( $content_dir, 0, 0775 );
+
+    while ( my ( $path, $content ) = each( %{ $params{source} } ) ) {
+        write_file( "$content_dir/$path", $content );
+    }
+
+    my %plugins =
+      map { ( "+Code::TidyAll::Test::Plugin::$_", $params{plugins}->{$_} ) }
+      keys( %{ $params{plugins} } );
+    my $ct = Code::TidyAll->new( plugins => \%plugins, recursive => 1, data_dir => $data_dir );
+
+    my ( $stdout, $stderr ) = capture { $ct->process_dir($content_dir) };
+    if ( $params{errors} ) {
+        like( $stderr, $params{errors}, "$desc - errors" );
+    }
+    else {
+        ok( $stderr !~ /\S/, "$desc - no errors ($stderr)" );
+    }
+    while ( my ( $path, $content ) = each( %{ $params{dest} } ) ) {
+        is( read_file("$content_dir/$path"), $content, "$desc - $path content" );
+    }
+}
+
+sub test_basic : Tests {
+    my $self = shift;
+
+    $self->tidy(
+        plugins => {},
+        source  => { "foo.txt" => "abc" },
+        dest    => { "foo.txt" => "abc" },
+        desc    => 'one file no plugins',
+    );
+    $self->tidy(
+        plugins => { 'UpperText' => {} },
+        source  => { "foo.txt"   => "abc" },
+        dest    => { "foo.txt"   => "ABC" },
+        desc    => 'one file UpperText',
+    );
+    $self->tidy(
+        plugins => { 'UpperText' => {}, 'ReverseFoo' => {} },
+        source => { "foo.txt" => "abc", "bar.txt" => "def", "foo.tx" => "ghi", "bar.tx" => "jkl" },
+        dest   => { "foo.txt" => "CBA", "bar.txt" => "DEF", "foo.tx" => "ihg", "bar.tx" => "jkl" },
+        desc => 'four files UpperText ReverseFoo',
+    );
+    $self->tidy(
+        plugins => { 'UpperText' => {} },
+        source  => { "foo.txt"   => "abc1" },
+        dest    => { "foo.txt"   => "abc1" },
+        desc    => 'one file UpperText errors',
+        errors  => qr/non-alpha content/
+    );
+}
+
+sub test_construct_errors : Tests {
+    my $self = shift;
+
+    my $data_dir = tempdir_simple();
+    throws_ok { Code::TidyAll->new( data_dir => $data_dir ) } qr/conf_file or plugins required/;
+    throws_ok { Code::TidyAll->new( plugins  => {} ) } qr/conf_file or data_dir required/;
+}
+
+1;
diff --git a/t/Basic.t b/t/Basic.t
new file mode 100644
index 0000000..afb1f20
--- /dev/null
+++ b/t/Basic.t
@@ -0,0 +1,3 @@
+#!perl -w
+use Code::TidyAll::t::Basic;
+Code::TidyAll::t::Basic->runtests;
diff --git a/t/use.t b/t/use.t
deleted file mode 100644
index cfefca3..0000000
--- a/t/use.t
+++ /dev/null
@@ -1,14 +0,0 @@
-#!perl
-use Test::More;
-use Code::TidyAll;
-use Code::TidyAll::Util qw(tempdir_simple);
-use Capture::Tiny qw(capture_merged);
-
-my $root_dir = tempdir_simple('Code-TidyAll-XXXX');
-my $ct       = Code::TidyAll->new(
-    root_dir => $root_dir,
-    plugins  => {},
-);
-is( capture_merged { $ct->tidyall() }, '', 'no output' );
-
-done_testing();

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libcode-tidyall-perl.git



More information about the Pkg-perl-cvs-commits mailing list