Skip to content

Commit ae3da66

Browse files
committed
Move to common tag expression evaluation
Cucumber::TagExpressions provides the infrastructure to use a common tag selection 'language' across implementations. By using it, we don't have to invent our own.
1 parent 69d6595 commit ae3da66

File tree

6 files changed

+42
-111
lines changed

6 files changed

+42
-111
lines changed

bin/pherkin

+4-8
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,8 @@ Extra Steps
5353

5454
Tag specifications
5555

56-
-t, --tags @tag Run scenarios tagged with '@tag'
57-
-t, --tags @tag1,@tag2 Run scenarios tagged with '@tag1' or '@tag2'
58-
-t, --tags ~@tag Run scenarios tagged without '@tag'
59-
-t @tag1 -t @tag2 Run only scenarios tagged with '@tag1' and '@tag2'
60-
-t @tag1 -t ~@tag2 Run scenarios tagged with '@tag1' but not '@tag2'
56+
-t, --tags <expr> Run scenarios for which the tags satisfy the
57+
cucumber tag expression <expr>
6158

6259
Configuration profiles (see CONFIGURATION PROFILES below/`man pherkin`)
6360

@@ -112,12 +109,11 @@ command line. C<default> is used if you didn't specify one. For example:
112109
- foo/steps
113110
- ~/steps
114111
output: TermColor
115-
tags:
116-
- tag1,tag2
112+
tags: @tag1 or @tag2
117113

118114
is equivalent to:
119115

120-
--steps foo/steps --steps ~/steps --output TermColor --tags tag1,tag2
116+
--steps foo/steps --steps ~/steps --output TermColor --tags '@tag1 or @tag2'
121117

122118
If you specify both command-line options, and options in a configuration file,
123119
then the command-line ones override single-value items, and are placed at the

cpanfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

2-
requires 'perl', '5.010';
2+
requires 'perl', '5.014';
3+
requires 'Cucumber::TagExpressions', '5.0.5';
34
requires 'File::Find::Rule';
45
requires 'JSON::MaybeXS', '1.1.0';
56
# List::Util 1.33 adds 'any'

lib/App/pherkin.pm

+6-45
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use Data::Dumper;
1414
use File::Spec;
1515
use Path::Class qw/file dir/;
1616

17+
use Cucumber::TagExpressions;
18+
1719
use Test::BDD::Cucumber::I18n
1820
qw(languages langdef readable_keywords keyword_to_subname);
1921
use Test::BDD::Cucumber::Loader;
@@ -22,8 +24,7 @@ use Moo;
2224
use Types::Standard qw( ArrayRef Bool Str );
2325
has 'step_paths' => ( is => 'rw', isa => ArrayRef, default => sub { [] } );
2426
has 'extensions' => ( is => 'rw', isa => ArrayRef, default => sub { [] } );
25-
has 'tags' => ( is => 'rw', isa => ArrayRef, required => 0 );
26-
has 'tag_scheme' => ( is => 'rw', isa => ArrayRef, required => 0 );
27+
has 'tags' => ( is => 'rw', isa => Str, required => 0 );
2728
has 'match_only' => ( is => 'rw', isa => Bool, default => 0 );
2829
has 'matching' => ( is => 'rw', isa => Str, default => 'first');
2930
has 'strict' => ( is => 'rw', isa => Bool, default => 0 );
@@ -114,9 +115,8 @@ sub _run_tests {
114115
$harness->startup();
115116

116117
my $tag_spec;
117-
if ( $self->tag_scheme ) {
118-
$tag_spec = Test::BDD::Cucumber::Model::TagSpec->new(
119-
{ tags => $self->tag_scheme } );
118+
if ( $self->tags ) {
119+
$tag_spec = Cucumber::TagExpressions->parse( $self->tags );
120120
}
121121

122122
$executor->execute( $_, $harness, $tag_spec ) for @features;
@@ -324,7 +324,7 @@ sub _process_arguments {
324324
output => [ 'o|output=s' ],
325325
strict => [ 'strict' ],
326326
steps => [ 's|steps=s@', [] ],
327-
tags => [ 't|tags=s@', [] ],
327+
tags => [ 't|tags=s' ],
328328
i18n => [ 'i18n=s' ],
329329
extensions => [ 'e|extension=s@', [] ],
330330
matching => [ 'matching=s' ],
@@ -477,9 +477,6 @@ sub _process_arguments {
477477
# Store any extra step paths
478478
$self->step_paths( $deref->('steps') );
479479

480-
# Store our TagSpecScheme
481-
$self->tag_scheme( $self->_process_tags( @{ $deref->('tags') } ) );
482-
483480
$self->matching( $deref->('matching') )
484481
if $deref->('matching');
485482

@@ -492,42 +489,6 @@ sub _process_arguments {
492489
return ( pop @ARGV );
493490
}
494491

495-
sub _process_tags {
496-
my ( $self, @tags ) = @_;
497-
498-
# This is a bit faffy and possibly suboptimal.
499-
my $tag_scheme = [];
500-
my @ands = ();
501-
502-
# Iterate over our commandline tag strings.
503-
foreach my $tag (@tags) {
504-
my @parts = ();
505-
506-
foreach my $part ( split( ',', $tag ) ) {
507-
508-
# Trim any @ or ~@ from the front of the tag
509-
$part =~ s/^(~?)@//;
510-
511-
# ~@tag => "NOT tag" => [ not => tag ]
512-
if ( defined $1 and $1 eq '~' ) {
513-
push @parts, [ not => $part ];
514-
} else {
515-
push @parts, $part;
516-
}
517-
}
518-
519-
# @tag,@cow => "@tag OR @cow" => [ or => tag, cow ]
520-
# (It's simpler to always stick an 'or' on the front.)
521-
push @ands, [ or => @parts ];
522-
}
523-
524-
# -t @tag -t @cow => "@tag AND @cow" => [ and => tag, cow ]
525-
# (It's simpler to always stick an 'and' on the front.)
526-
$tag_scheme = [ and => @ands ];
527-
528-
return $tag_scheme;
529-
}
530-
531492
sub _print_languages {
532493

533494
my @languages = languages();

lib/Test/BDD/Cucumber/Executor.pm

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2+
use v5.14;
3+
14
package Test::BDD::Cucumber::Executor;
25

36
=head1 NAME
@@ -17,6 +20,7 @@ use Types::Standard qw( Bool Str ArrayRef HashRef );
1720
use List::Util qw/first any/;
1821
use Module::Runtime qw/use_module/;
1922
use utf8;
23+
use Carp qw(carp croak);
2024
use Encode ();
2125

2226
use Test2::API qw/intercept/;
@@ -142,7 +146,7 @@ sub add_steps {
142146
=head2 execute
143147
144148
Execute accepts a feature object, a harness object, and an optional
145-
L<Test::BDD::Cucumber::TagSpec> object and for each scenario in the
149+
L<Cucumber::TagExpressions::ExpressionNode> object and for each scenario in the
146150
feature which meets the tag requirements (or all of them, if you
147151
haven't specified one), runs C<execute_scenario>.
148152
@@ -202,6 +206,23 @@ representing the Background
202206
203207
=cut
204208

209+
sub _match_tags {
210+
my ($spec, @tagged_components) = @_;
211+
state $deprecation_warned = 0;
212+
213+
if ($spec->isa('Cucumber::TagExpressions::ExpressionNode')) {
214+
return grep {
215+
$spec->evaluate( @{ $_->tags } )
216+
} @tagged_components;
217+
}
218+
else {
219+
$deprecation_warned ||=
220+
carp 'Test::BDD::Cucumber::Model::TagSpec is deprecated; replace with Cucumber::TagExpressions';
221+
222+
return $spec->filter( @tagged_components );
223+
}
224+
}
225+
205226
sub execute_outline {
206227
my ( $self, $options ) = @_;
207228
my ( $feature, $feature_stash, $harness, $outline, $background, $tagspec )
@@ -210,7 +231,7 @@ sub execute_outline {
210231
# Multiply out Scenario Outlines as appropriate
211232
my @datasets = @{ $outline->datasets };
212233
if (not @datasets) {
213-
if (not $tagspec or $tagspec->filter($outline) ) {
234+
if (not $tagspec or _match_tags( $tagspec, $outline )) {
214235
$self->execute_scenario(
215236
{
216237
feature => $feature,
@@ -227,7 +248,7 @@ sub execute_outline {
227248
}
228249

229250
if ($tagspec) {
230-
@datasets = $tagspec->filter(@datasets);
251+
@datasets = _match_tags( $tagspec, @datasets );
231252
return unless @datasets;
232253
}
233254

lib/Test/BDD/Cucumber/Model/TagSpec.pm

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ package Test::BDD::Cucumber::Model::TagSpec;
44
55
Test::BDD::Cucumber::Model::TagSpec - Encapsulates tag selectors
66
7+
=head1 STATUS
8+
9+
DEPRECATED - This module's functionality has been superseeded by
10+
L<Cucumber::TagExpressions>. A module published by the Cucumber
11+
project, with cross-implementation tests to achieve overall consistency.
12+
713
=head1 DESCRIPTION
814
915
Try and deal with the crazy-sauce tagging mechanism in a sane

t/700_tag_processing.t

-54
This file was deleted.

0 commit comments

Comments
 (0)