File Coverage

blib/lib/Test/BDD/Cucumber/StepFile.pm
Criterion Covered Total %
statement 59 62 95.1
branch 6 8 75.0
condition 2 3 66.6
subroutine 21 24 87.5
pod 7 7 100.0
total 95 104 91.3


line stmt bran cond sub pod time code
1             package Test::BDD::Cucumber::StepFile;
2             $Test::BDD::Cucumber::StepFile::VERSION = '0.84';
3             =head1 NAME
4              
5             Test::BDD::Cucumber::StepFile - Functions for creating and loading Step Definitions
6              
7             =head1 VERSION
8              
9             version 0.84
10              
11             =cut
12              
13 13     13   98 use strict;
  13         29  
  13         396  
14 13     13   71 use warnings;
  13         61  
  13         312  
15 13     13   100 use utf8;
  13         26  
  13         77  
16              
17 13     13   357 use Carp qw/croak/;
  13         40  
  13         654  
18 13     13   102 use File::Spec;
  13         33  
  13         496  
19 13     13   96 use Scalar::Util qw/reftype/;
  13         29  
  13         720  
20              
21 13     13   1467 use Test::BDD::Cucumber::I18n qw(languages langdef keyword_to_subname);
  13         34  
  13         8606  
22              
23             require Exporter;
24             our @ISA = qw(Exporter);
25             our @EXPORT = qw(Step Transform Before After C S);
26              
27             our @definitions;
28              
29             =head1 DESCRIPTION
30              
31             Provides the Given/When/Then functions, and a method for loading Step Definition
32             files and returning the steps.
33              
34             =head1 SYNOPSIS
35              
36             Defining steps:
37              
38             #!perl
39              
40             use strict; use warnings; use Test::More;
41             # or: use strict; use warnings; use Test2::V0;
42              
43             use Test::BDD::Cucumber::StepFile;
44              
45             Given 'something', sub { print "YEAH!" }
46             When qr/smooooth (\d+)/, sub { print "YEEEHAH $1" }
47             Then qr/something (else)/, sub { S->{'match'} = $1 }
48             Step qr/die now/, sub { die "now" }
49             Transform qr/^(\d+)$/, sub { int $1 }
50             Before sub { setup_db() }
51             After sub { teardown() }
52              
53             Loading steps, in a different file:
54              
55             use Test::BDD::Cucumber::StepFile;
56             my @steps = Test::BDD::Cucumber::StepFile->load('filename_steps.pl');
57              
58             =head1 EXPORTED FUNCTIONS
59              
60             =head2 Given
61              
62             =head2 When
63              
64             =head2 Then
65              
66             =head2 Step
67              
68             =head2 Transform
69              
70             =head2 Before
71              
72             =head2 After
73              
74             Accept a regular expression or string, and a coderef. Some cute tricks ensure
75             that when you call the C method on a file with these statements in,
76             these are returned to it...
77              
78             =cut
79              
80             sub _ensure_meta {
81 79     79   457 my ($p, $f, $l) = caller(1);
82 79 100 66     429 if (ref $_[1] and reftype $_[1] eq 'HASH') {
83 1         4 $_[1]->{source} = $f;
84 1         2 $_[1]->{line} = $l;
85 1         10 return @_;
86             }
87             else {
88 78         522 return ($_[0], { source => $f, line => $l }, $_[1]);
89             }
90             }
91              
92             # Mapped to Given, When, and Then as part of the i18n mapping below
93 29     29   14950 sub _Given { push( @definitions, [ Given => _ensure_meta(@_) ] ) }
94 24     24   118 sub _When { push( @definitions, [ When => _ensure_meta(@_) ] ) }
95 18     18   154 sub _Then { push( @definitions, [ Then => _ensure_meta(@_) ] ) }
96              
97 0     0 1 0 sub Step { push( @definitions, [ Step => _ensure_meta(@_) ] ) }
98              
99 4     4 1 20 sub Transform { push( @definitions, [ Transform => _ensure_meta(@_) ] ) }
100 2     2 1 23 sub Before { push( @definitions, [ Before => _ensure_meta(qr//, @_) ] ) }
101 2     2 1 11 sub After { push( @definitions, [ After => _ensure_meta(qr//, @_) ] ) }
102              
103             my @SUBS;
104              
105             for my $language ( languages() ) {
106             my $langdef = langdef($language);
107              
108             _alias_function( $langdef->{given}, \&_Given );
109             _alias_function( $langdef->{when}, \&_When );
110             _alias_function( $langdef->{then}, \&_Then );
111              
112             # Hm ... in cucumber, all step defining keywords are the same.
113             # Here, the parser replaces 'and' and 'but' with the last verb. Tricky ...
114             # _alias_function( $langdef->{and}, \&And);
115             # _alias_function( $langdef->{but}, \&But);
116             }
117              
118             push @EXPORT, @SUBS;
119              
120             sub _alias_function {
121 3003     3003   5649 my ( $keywords, $f ) = @_;
122              
123 3003         7851 my @keywords = split( '\|', $keywords );
124 3003         5383 for my $word (@keywords) {
125              
126             # asterisks won't be aliased to any sub
127 5109 50       9348 next if $word eq '*';
128              
129 5109         9406 my $subname = keyword_to_subname($word);
130 5109 100       10586 next unless length $subname;
131              
132             {
133 13     13   154 no strict 'refs';
  13         28  
  13         570  
  5070         6616  
134 13     13   95 no warnings 'redefine';
  13         33  
  13         517  
135 13     13   75 no warnings 'once';
  13         31  
  13         3640  
136              
137 5070         18845 *$subname = $f;
138 5070         13675 push @SUBS, $subname;
139             }
140             }
141             }
142              
143             =head2 C
144              
145             =head2 S
146              
147             Return the context and the Scenario stash, respectively, B
148             inside a step definition>.
149              
150             =cut
151              
152             # We need an extra level of indirection when we want to support step functions
153             # loaded into their own packages (which we do, for cleanliness); the exporter
154             # binds the subs declared below to S and C symbols in the imported-into package
155             # That prevents us from binding a different function to these symbols at
156             # execution time.
157             # We *can* bind the _S and _C functions declared below.
158 702     702 1 15112 sub S { _S() }
159 265     265 1 735 sub C { _C() }
160              
161 0     0   0 sub _S { croak "You can only call `S` inside a step definition" }
162 0     0   0 sub _C { croak "You can only call `C` inside a step definition" }
163              
164             =head2 load
165              
166             Loads a file containing step definitions, and returns a list of the steps
167             defined in it, of the form:
168              
169             (
170             [ 'Given', qr/abc/, sub { etc } ],
171             [ 'Step', 'asdf', sub { etc } ]
172             )
173              
174             =cut
175              
176             sub load {
177 13     13 1 18636 my ( $class, $filename ) = @_;
178             {
179 13         27 local @definitions;
  13         42  
180              
181             # Debian Jessie with security patches requires an absolute path
182 13         7881 do File::Spec->rel2abs($filename);
183 13 50       66 die "Step file [$filename] failed to load: $@" if $@;
184 13         108 return @definitions;
185             }
186              
187             }
188              
189             =head1 AUTHOR
190              
191             Peter Sergeant C
192              
193             =head1 LICENSE
194              
195             Copyright 2019-2023, Erik Huelsmann
196             Copyright 2011-2019, Peter Sergeant; Licensed under the same terms as Perl
197              
198             =cut
199              
200             1;