[libtest-bdd-cucumber-perl] 02/02: Highlight parameters correctly using @- and @+

Intrigeri intrigeri at moszumanska.debian.org
Thu Jun 19 10:18:54 UTC 2014


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

intrigeri pushed a commit to annotated tag 0.25
in repository libtest-bdd-cucumber-perl.

commit 963e24908a5531a8f12d92880d2cee8d48b968f2
Author: Peter Sergeant <pete at clueball.com>
Date:   Sun Jun 8 09:32:18 2014 +0100

    Highlight parameters correctly using @- and @+
---
 CHANGES                                    |  3 ++
 dist.ini                                   |  3 +-
 lib/Test/BDD/Cucumber/Errors.pm            |  3 +-
 lib/Test/BDD/Cucumber/Executor.pm          | 66 +++++++++++++++++++++--
 lib/Test/BDD/Cucumber/Harness.pm           |  5 +-
 lib/Test/BDD/Cucumber/Harness/Data.pm      |  3 +-
 lib/Test/BDD/Cucumber/Harness/TermColor.pm | 22 ++++----
 t/260_match_matcher.t                      | 84 ++++++++++++++++++++++++++++++
 8 files changed, 171 insertions(+), 18 deletions(-)

diff --git a/CHANGES b/CHANGES
index c74fe71..1f2c909 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,7 @@
 -----
+0.25: 08 Jun 2014
+    - Highlight parameters properly in TermColor output using @+ and @-
+      https://github.com/sheriff/test-bdd-cucumber-perl/issues/24
 0.24: 07 Jun 2014
     - Replacing string `eval` with block `eval` for requiring test harnesses -
       thanks Paul Cochrane
diff --git a/dist.ini b/dist.ini
index de0d179..6d06616 100644
--- a/dist.ini
+++ b/dist.ini
@@ -1,5 +1,5 @@
 name      = Test-BDD-Cucumber
-version   = 0.24
+version   = 0.25
 abstract  = Feature-complete Cucumber-style testing in Perl
 main_module = lib/Test/BDD/Cucumber.pm
 author    = ['Peter Sergeant <pete at clueball.com>','Ben Rogers <ben at bdr.org>']
@@ -29,6 +29,7 @@ Getopt::Long = 0
 JSON::MaybeXS = 0
 Module::Runtime = 0
 Moose = 0
+Number::Range = 0
 Path::Class = 0
 Storable = 0
 Term::ANSIColor = 3.00
diff --git a/lib/Test/BDD/Cucumber/Errors.pm b/lib/Test/BDD/Cucumber/Errors.pm
index 33128ed..2c97fc3 100644
--- a/lib/Test/BDD/Cucumber/Errors.pm
+++ b/lib/Test/BDD/Cucumber/Errors.pm
@@ -68,7 +68,7 @@ sub parse_error_from_line {
         _get_context_range( $line->document, $feature_line );
 
     my $formatted_lines;
-    for ( 0 .. 4 ) {
+    for ( 0 .. $#lines ) {
         my $actual_line = $start_line + $_;
         my $mark = ($feature_line == $actual_line) ? '*' : '|';
         $formatted_lines .=
@@ -112,6 +112,7 @@ sub _get_context_range {
 
     # Then cut it off
     @range = grep { $_ >= $min_range } @range;
+    @range = grep { $_ <= $max_range } @range;
 
     return( $range[0], map { $document->lines->[$_ - 1]->raw_content } @range );
 }
diff --git a/lib/Test/BDD/Cucumber/Executor.pm b/lib/Test/BDD/Cucumber/Executor.pm
index 38c61ec..f940ca9 100644
--- a/lib/Test/BDD/Cucumber/Executor.pm
+++ b/lib/Test/BDD/Cucumber/Executor.pm
@@ -15,7 +15,9 @@ use Moose;
 use FindBin::libs;
 use Storable qw(dclone);
 use List::Util qw/first/;
+use List::MoreUtils qw/pairwise/;
 use Test::Builder;
+use Number::Range;
 
 use Test::BDD::Cucumber::StepContext;
 use Test::BDD::Cucumber::Util;
@@ -362,6 +364,9 @@ sub dispatch {
     # Say we're about to start it up
     $context->harness->step( $context );
 
+    # Store the string position of matches for highlighting
+    my @match_locations;
+
     # New scope for the localization
     my $result;
     {
@@ -371,6 +376,8 @@ sub dispatch {
         # Execute!
         eval {
             no warnings 'redefine';
+
+            # Set S and C to be step-specific values before executing the step
             local *Test::BDD::Cucumber::StepFile::S = sub {
                 return $context->stash->{'scenario'}
             };
@@ -378,8 +385,17 @@ sub dispatch {
                 return $context
             };
 
-            # Rematch the regex, setting $1, $2, and friends correctly
-            $context->matches([ $context->text =~ $regular_expression ]);
+            # Take a copy of this. Turns out actually matching against it
+            # directly causes all sorts of weird-ass eisenbugs which mst has
+            # promised to investigate.
+            my $text = $context->text;
+
+            # Save the matches
+            $context->matches([ $text =~ $regular_expression ]);
+
+            # Save the location of matched subgroups for highlighting hijinks
+            my @starts = @-; my @ends = @+;
+            @match_locations = pairwise {[$a, $b]} @starts, @ends;
 
             # OK, actually execute
             $coderef->( $context )
@@ -401,14 +417,58 @@ sub dispatch {
         });
 
     }
+
+    my @clean_matches = $self->_extract_match_strings(
+        $context->text, \@match_locations
+    );
+    @clean_matches = [ 0, $context->text ] unless @clean_matches;
+
     # Say the step is done, and return the result. Happens outside
     # the above block so that we don't have the localized harness
     # anymore...
     $context->harness->add_result( $result );
-    $context->harness->step_done( $context, $result );
+    $context->harness->step_done( $context, $result, \@clean_matches );
     return $result;
 }
 
+sub _extract_match_strings {
+    my ($self, $text, $locations) = @_;
+
+    # Clean up the match locations
+    my @match_locations = grep {
+            ( $_->[0] != $_->[1] ) && # No zero-length matches
+            # And nothing that matched the full string
+            (! (( $_->[0] == 0 ) && (( $_->[1] == length $text ) )))
+        } grep { defined $_ && ref $_ && defined $_->[0] && defined $_->[1] }
+        @$locations;
+
+    return unless @match_locations;
+
+    # Consolidate overlaps
+    my $range = Number::Range->new();
+
+    {
+        # Don't want a complain about numbers already in range, as that's
+        # expected for nested matches
+        no warnings;
+        $range->addrange($_->[0] . '..' . ($_->[1]-1) ) for @match_locations;
+    }
+
+    # Walk the string, splitting
+    my @parts = ([0,'']);
+    for ( 0 .. ((length $text) - 1) ) {
+        my $to_highlight = $range->inrange( $_ );
+        my $character = substr( $text, $_, 1 );
+
+        if ( $parts[-1]->[0] != $to_highlight ) {
+            push( @parts, [$to_highlight, ''] );
+        }
+
+        $parts[-1]->[1] .= $character;
+    }
+
+    return @parts;
+}
 
 sub _test_status {
     my $self    = shift;
diff --git a/lib/Test/BDD/Cucumber/Harness.pm b/lib/Test/BDD/Cucumber/Harness.pm
index 32ad781..0219606 100644
--- a/lib/Test/BDD/Cucumber/Harness.pm
+++ b/lib/Test/BDD/Cucumber/Harness.pm
@@ -68,7 +68,10 @@ sub scenario_done { my ( $self, $scenario, $dataset ) = @_; }
 
 Called at the start and end of step execution respectively. Both methods
 accept a L<Test::BDD::Cucmber::StepContext> object. C<step_done> also accepts
-a L<Test::BDD::Cucumber::Model::Result> object.
+a L<Test::BDD::Cucumber::Model::Result> object and an arrayref of arrayrefs with
+locations of consolidated matches, for highlighting.
+
+ [ [2,5], [7,9] ]
 
 =cut
 
diff --git a/lib/Test/BDD/Cucumber/Harness/Data.pm b/lib/Test/BDD/Cucumber/Harness/Data.pm
index c5ff28a..f29f2c2 100644
--- a/lib/Test/BDD/Cucumber/Harness/Data.pm
+++ b/lib/Test/BDD/Cucumber/Harness/Data.pm
@@ -124,9 +124,10 @@ sub step {
 }
 
 sub step_done {
-    my ($self, $context, $result) = @_;
+    my ($self, $context, $result, $highlights) = @_;
 
     $self->current_step->{'result'} = $result;
+    $self->current_step->{'highlights'} = $highlights;
     push( @{ $self->current_scenario->{'steps'} }, $self->current_step );
     $self->current_step({});
 }
diff --git a/lib/Test/BDD/Cucumber/Harness/TermColor.pm b/lib/Test/BDD/Cucumber/Harness/TermColor.pm
index b4b055e..e7b0164 100644
--- a/lib/Test/BDD/Cucumber/Harness/TermColor.pm
+++ b/lib/Test/BDD/Cucumber/Harness/TermColor.pm
@@ -37,7 +37,6 @@ BEGIN {
 }
 
 use Term::ANSIColor;
-use Test::BDD::Cucumber::Util;
 use Test::BDD::Cucumber::Model::Result;
 
 extends 'Test::BDD::Cucumber::Harness';
@@ -82,7 +81,7 @@ sub scenario_done { print "\n"; }
 
 sub step {}
 sub step_done {
-    my ($self, $context, $result ) = @_;
+    my ($self, $context, $result, $highlights ) = @_;
 
     my $color;
     my $follow_up = [];
@@ -109,20 +108,20 @@ sub step_done {
 
     my $text;
 
-    if ( $context->is_hook )
-    {
+    if ( $context->is_hook ) {
         $color eq 'red' or return;
         $text = 'In ' . ucfirst( $context->verb ) . ' Hook';
-    }
-    else
-    {
+        undef $highlights;
+    } else {
         $text = $context->step->verb_original . ' ' . $context->text;
+        $highlights = [[ 0, $context->step->verb_original . ' ' ], @$highlights];
     }
 
     $self->_display({
         indent    => 4,
         color     => $color,
         text      => $text,
+        highlights => $highlights,
         highlight => 'bright_cyan',
         trailing  => 0,
         follow_up => $follow_up,
@@ -174,14 +173,15 @@ sub _display {
 
     # Highlight as appropriate
     my $color = color $options->{'color'};
-    if ( $options->{'highlight'} ) {
+    if ( $options->{'highlight'} && $options->{'highlights'} ) {
         my $reset = color 'reset';
         my $base  = color $options->{'color'};
         my $hl    = color $options->{'highlight'};
 
-        my $text = $base . Test::BDD::Cucumber::Util::bs_quote( $options->{'text'} );
-        $text =~ s/("(.+?)"|[ ^](\d[-?\d\.]*))/$reset$hl$1$reset$base/g;
-        print Test::BDD::Cucumber::Util::bs_unquote( $text );
+        for ( @{$options->{'highlights'}} ) {
+            my ($flag, $text) = @$_;
+            print $reset . ( $flag ? $hl : $base ) . $text . $reset;
+        }
 
     # Normal output
     } else {
diff --git a/t/260_match_matcher.t b/t/260_match_matcher.t
new file mode 100644
index 0000000..2983b85
--- /dev/null
+++ b/t/260_match_matcher.t
@@ -0,0 +1,84 @@
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Differences;
+use Test::BDD::Cucumber::Parser;
+use Test::BDD::Cucumber::Executor;
+use Test::BDD::Cucumber::Harness::Data;
+
+# Check that when we execute steps we get a nicely split string back for
+# highlighting
+for (
+    [
+        "Simple example",
+        "the quick brown fox",
+        qr/the (quick) brown (fox)/,
+        [
+            [ 0 => 'the ' ],
+            [ 1 => 'quick' ],
+            [ 0 => ' brown ' ],
+            [ 1 => 'fox' ],
+        ]
+    ],
+    [
+        "Non-capture",
+        "the quick brown fox",
+        qr/the (?:quick) brown (fox)/,
+        [
+            [ 0 => 'the quick brown ' ],
+            [ 1 => 'fox' ],
+        ]
+    ],
+    [
+        "Nested-capture",
+        "the quick brown fox",
+        qr/the (q(uic)k) brown (fox)/,
+        [
+            [ 0 => 'the ' ],
+            [ 1 => 'quick' ],
+            [ 0 => ' brown ' ],
+            [ 1 => 'fox' ],
+        ]
+    ],
+    [
+        "Multi-group",
+        "the quick brown fox",
+        qr/the (.)+ brown (fox)/,
+        [
+            [ 0 => 'the quic' ],
+            [ 1 => 'k' ],
+            [ 0 => ' brown ' ],
+            [ 1 => 'fox' ],
+        ]
+    ],
+) {
+    my ( $test_name, $step_text, $step_re, $expected ) = @$_;
+
+    # Set up a feature
+    my $feature = Test::BDD::Cucumber::Parser->parse_string(
+        "Feature: Foo\n\tScenario:\n\t\tGiven $step_text\n"
+    );
+
+    # Set up step definitions
+    my $executor = Test::BDD::Cucumber::Executor->new();
+    $executor->add_steps(
+        [ Given => $step_re, sub { 1; } ],
+    );
+
+    # Instantiate the harness, and run it
+    my $harness = Test::BDD::Cucumber::Harness::Data->new();
+    $executor->execute( $feature, $harness );
+
+    # Get the step result
+    my $step = $harness->features->[0]->{'scenarios'}->[0]->{'steps'}->[0];
+    my $highlights = $step->{'highlights'};
+
+    is_deeply( $highlights, $expected, $test_name ) || eq_or_diff(
+        $highlights, $expected
+    );
+}
+
+done_testing();
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libtest-bdd-cucumber-perl.git



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