File Coverage

blib/lib/Test/Cucumber/Tiny.pm
Criterion Covered Total %
statement 200 222 90.0
branch 76 94 80.8
condition 7 11 63.6
subroutine 36 37 97.3
pod 13 14 92.8
total 332 378 87.8


line stmt bran cond sub pod time code
1             package Test::Cucumber::Tiny;
2             {
3             $Test::Cucumber::Tiny::VERSION = '0.64';
4             }
5 6     6   134425 use Mo qw( default );
  6         3318  
  6         34  
6 6     6   11675 use Try::Tiny;
  6         12787  
  6         406  
7 6     6   54 use Carp qw( confess );
  6         12  
  6         257  
8 6     6   4773 use YAML ();
  6         66596  
  6         158  
9 6     6   5880 use Readonly;
  6         20480  
  6         18377  
10             require Test::More;
11              
12             =head1 NAME
13              
14             Test::Cucumber::Tiny - Cucumber-style testing in perl
15              
16             =head1 SYNOPSIS
17              
18             Cucumber is a tool that executes plain-text functional
19             descriptions as automated tests. The language that Cucumber
20             understands is called Gherkin.
21              
22             While Cucumber can be thought of as a "testing" tool,
23             the intent of the tool is to support BDD. This means that
24             the "tests" are typically written before anything else and
25             verified by business analysts, domain experts, etc. non technical
26             stakeholders. The production code is then written outside-in,
27             to make the stories pass.
28              
29             =head1 USAGE
30              
31             If you need to shared the scenarios with the business analysts.
32              
33             Write the scenarios in YAML
34              
35             use Test::More tests => 1;
36             use Test::Cucumber::Tiny;
37              
38             subtest "Feature Test - Calculator" => sub {
39             ## In order to avoid silly mistake
40             ## As a math idiot
41             ## I want to be told a sum of 2 numbers
42              
43             ## Here is an example using YAML file:
44              
45             my $cucumber = Test::Cucumber::Tiny->ScenariosFromYAML(
46             "t/test_functions/something_something.yml");
47              
48             ## Here is an example using a list:
49              
50             my $cucumber = Test::Cucumber::Tiny->Scenarios(
51             {
52             Scenario => "Add 2 numbers",
53             Given => [
54             "first, I entered 50 into the calculator",
55             "second, I entered 70 into the calculator",
56             ],
57             When => [ "I press add", ],
58             Then => [ "The result should be 120 on the screen", ]
59             },
60             {
61             Scenario => "Add numbers in examples",
62             Given => [
63             "first, I entered <1st> into the calculator",
64             "second, I entered <2nd> into the calculator",
65             ],
66             When => [ "I press add", ],
67             Then => [ "The result should be <answer> on the screen", ],
68             Examples => [
69             {
70             '1st' => 5,
71             '2nd' => 6,
72             answer => 11,
73             },
74             {
75             '1st' => 100,
76             '2nd' => 200,
77             answer => 300,
78             }
79             ],
80             },
81             {
82             Scenario => "Add numbers using data",
83             Given => [
84             {
85             condition => "first, I entered number of",
86             data => 45,
87             },
88             {
89             condition => "second, I entered number of",
90             data => 77,
91             }
92             ],
93             When => [ "I press add", ],
94             Then => [
95             {
96             condition => "The result is",
97             data => 122,
98             }
99             ],
100             }
101             );
102              
103             $cucumber->Given(
104             qr/^(.+),.+entered (\d+)/ => sub {
105             my $c = shift;
106             my $subject = shift;
107             my $key = $1;
108             my $num = $2;
109             $c->{$key} = $num;
110             $c->Log($subject);
111             }
112             )->Given(
113             qr/^(.+),.+entered number of/ => sub {
114             my $c = shift;
115             my $subject = shift;
116             my $key = $1;
117             $c->{$key} = $c->{data};
118             }
119             )->When(
120             qr/press add/ => sub {
121             my $c = shift;
122             my $subject = shift;
123             $c->{answer} = $c->{first} + $c->{second};
124             }
125             )->Then(
126             qr/result.+should be (\d+)/ => sub {
127             my $c = shift;
128             my $subject = shift;
129             my $expected = $1;
130             is $c->{answer}, $expected, $subject;
131             }
132             )->Then(
133             qr/result is/ => sub {
134             my $c = shift;
135             my $subject = shift;
136             is $c->{data}, $c->{answer}, $subject;
137             }
138             )->Test;
139             };
140              
141             =cut
142              
143             has scenarios => (
144             required => 1,
145             is => "ro",
146             isa => "ArrayRef[HashRef]",
147             );
148              
149             =head1 METHODS
150              
151             =head2 new
152              
153             Create a cucumber for test
154              
155             Test::Cucumber::Tiny->new(
156             scenarios => [
157             {
158             ....
159             }
160             ]
161             )
162              
163             ->Given(...)
164            
165             ->Then(...)
166              
167             ->Test;
168              
169             =head2 Scenarios
170              
171             Create a cucumber with a plain array list of scenarios
172              
173             Test::Cucumber::Tiny->Scenarios(
174             { ... }
175             )
176             ->Given(...)
177             ->When(...)
178             ->Then(...)
179             ->Test;
180              
181             =cut
182              
183             sub Scenarios {
184 4     4 1 5068 my $class = shift;
185 4 100       53 return $class->new( scenarios => \@_ )
186             if !ref $class;
187 1         2 my $self = $class;
188 1         29 push @{ $self->scenarios }, @_;
  1         7  
189 1         84 return $self;
190             }
191              
192             =head2 ScenariosFromYML
193              
194             Create a cucumber from a YAML file.
195              
196             YMAL Example:
197              
198             - Scenario: Add 2 numbers
199             Given:
200             - first, I entered 50 into the calculator
201             - second, I entered 70 into the calculator
202             When: I press add
203             Then: The result should be 120 on the screen
204              
205             - Scenario: Add 3 numbers
206             Given:
207             - first, I entered 50 into the calculator
208             - second, I entered 70 into the calculator
209             - third, I entered 10 into the calculator
210             When: I press add
211             Then: The result should be 130 on the screen
212              
213             In Code:
214              
215             my $cuc = Test::Cucumber::Tiny->ScenariosFromYML( "feature-1.yml" )
216             ->ScenariosFromYML( "feature-2.yml" )
217             ->ScenariosFromYML( "feature-3.yml" )
218             ->ScenariosFromYML( "feature-4.yml" )
219             ->Given(...)
220             ->Whn(...)
221             ->Then(...)
222             ->Test;
223              
224             =cut
225              
226             sub ScenariosFromYML {
227 6     6 1 23565 goto &ScenariosFromYAML;
228             }
229              
230             sub ScenariosFromYAML {
231 6     6 0 15 my $class = shift;
232 6 50       23 my @scenarios = _decode_yml(@_)
233             or return $class;
234 2         18 return $class->Scenarios( @scenarios );
235             }
236              
237             =head2 Before
238              
239             @param regexp
240              
241             @code ref
242              
243             =cut
244              
245             sub Before {
246 18     18 1 9547 my $self = shift;
247 18 100       79 my $condition = shift
248             or die "Missing regexp or coderef";
249 17         23 my $definition = shift;
250              
251 17 100       66 if ( ref $condition eq "CODE" ) {
252 2         3 $definition = $condition;
253 2         10 $condition = qr/.+/;
254             }
255              
256 17         23 push @{ $self->_befores },
  17         61  
257             {
258             condition => $condition,
259             definition => $definition,
260             };
261              
262 17         97 return $self;
263             }
264              
265             has _befores => (
266             is => "ro",
267             isa => "ArrayRef[HashRef]",
268             default => sub { [] },
269             );
270              
271             =head2 Given
272              
273             @param regexp
274              
275             @param code ref
276              
277             =cut
278              
279             sub Given {
280 26     26 1 4454 my $self = shift;
281 26 100       86 my $condition = shift
282             or die "Missing 'Given' condition";
283 25 100       76 my $definition = shift
284             or die "Missing 'Given' definition coderef";
285 24         30 push @{ $self->_givens },
  24         76  
286             {
287             condition => $condition,
288             definition => $definition,
289             };
290 24         219 return $self;
291             }
292              
293             has _givens => (
294             is => "ro",
295             isa => "ArrayRef[HashRef]",
296             default => sub { [] },
297             );
298              
299             =head2 When
300              
301             @param regexp / hashref { regexp, data }
302              
303             @param code ref
304              
305             =cut
306              
307             sub When {
308 25     25 1 1220 my $self = shift;
309 25 100       76 my $condition = shift
310             or die "Missing 'When' condition";
311 24 100       70 my $definition = shift
312             or die "Missing 'When' definition coderef";
313 23         31 push @{ $self->_whens },
  23         65  
314             {
315             condition => $condition,
316             definition => $definition,
317             };
318 23         168 return $self;
319             }
320              
321             has _whens => (
322             is => "ro",
323             isa => "ArrayRef[HashRef]",
324             default => sub { [] },
325             );
326              
327             =head2 Then
328              
329             @param regexp / hashref { regexp, data }
330              
331             @param code ref
332              
333             =cut
334              
335             sub Then {
336 24     24 1 1386 my $self = shift;
337 24 100       66 my $condition = shift
338             or die "Missing 'Then' condition";
339 23 100       59 my $definition = shift
340             or die "Missing 'Then' definition coderef";
341 22         26 push @{ $self->_thens },
  22         61  
342             {
343             condition => $condition,
344             definition => $definition,
345             };
346 22         313 return $self;
347             }
348              
349             has _thens => (
350             is => "ro",
351             isa => "ArrayRef[HashRef]",
352             default => sub { [] },
353             );
354              
355             =head2 Any
356              
357             Use any to set all 3 like below
358              
359             ->Any( qr/.+/ => sub { return 1 } );
360              
361             Same as
362              
363             ->Before( qr/.+/ => sub { return 1 } );
364             ->Given( qr/.+/ => sub { return 1 } );
365             ->When( qr/.+/ => sub { return 1 } );
366             ->Then( qr/.+/ => sub { return 1 } );
367             ->After( qr/.+/ => sub { return 1 } );
368              
369             =cut
370              
371             sub Any {
372 14     14 1 499 my $self = shift;
373 14         222 $self->Before(@_);
374 14         49 $self->Given(@_);
375 14         36 $self->When(@_);
376 14         38 $self->Then(@_);
377 14         39 $self->After(@_);
378 14         22 return $self;
379             }
380              
381             =head2 After
382              
383             @param regexp
384              
385             @code ref
386              
387             =cut
388              
389             sub After {
390 17     17 1 562 my $self = shift;
391 17 100       53 my $condition = shift
392             or die "Missing regexp or coderef";
393 16         21 my $definition = shift;
394              
395 16 100       53 if ( ref $condition eq "CODE" ) {
396 1         2 $definition = $condition;
397 1         4 $condition = qr/.+/;
398             }
399              
400 16         45 push @{ $self->_afters },
  16         61  
401             {
402             condition => $condition,
403             definition => $definition,
404             };
405              
406 16         70 return $self;
407             }
408              
409             has _afters => (
410             is => "ro",
411             isa => "ArrayRef[HashRef]",
412             default => sub { [] },
413             );
414              
415             =head2 NextStep
416              
417             When you are the functions of Given
418              
419             Call NextStep will jump to When
420              
421             When you are the functions of When
422              
423             Call NextStep will jump to Then
424              
425             When you are the functions of Then
426              
427             Call NextStep will finish the current scenario.
428              
429             =cut
430              
431             Readonly my $NEXT_STEP => "Next Step";
432              
433             sub NextStep {
434 3     3 1 260 die { intercept => $NEXT_STEP };
435             }
436              
437             =head2 NextExample
438              
439             When you are the functions of Given, When or Then
440              
441             Call NextExample will finish the current cycle and
442             use the next example data in the current scenario.
443              
444             =cut
445              
446             Readonly my $NEXT_EXAMPLE => "Nex Example";
447              
448             sub NextExample {
449 4     4 1 4352 die { intercept => $NEXT_EXAMPLE };
450             }
451              
452             =head2 NextScenario
453              
454             Just jump to the next scenario.
455              
456             =cut
457              
458             Readonly my $NEXT_SCENARIO => "Next Scenario";
459              
460             sub NextScenario {
461 3     3 1 680 die { intercept => $NEXT_SCENARIO };
462             }
463              
464             =head2 Test
465              
466             Start Cucumber to run through the scenario.
467              
468             =cut
469              
470             Readonly my @STEPS => qw(
471             Before
472             Given
473             When
474             Then
475             After
476             );
477              
478             sub Test {
479 10     10 1 5782 my $self = shift;
480 10         76 my @run_through = ( "Before", @STEPS, "After" );
481              
482             $self->Any(
483             qr/^debugger$/ => sub {
484 0     0   0 my $c = shift;
485 0         0 my $subject = shift;
486 0         0 my $Scenario = $c->{Scenario};
487 0         0 my $Step = $c->{Step};
488 0         0 my $Data = $c->{data};
489 0         0 my $Example = $c->{Example};
490 0         0 my $Examples = $c->{Examples};
491 0         0 my $FEATURE_WIDE = $c->{FEATURE_WIDE};
492 0         0 $self->Log("! DEBUG: $Scenario - $Step");
493 0         0 $DB::single = 1;
494 0         0 $DB::single = 2; ## Avoid warnings use only once
495 0         0 print q{};
496             }
497 10         391 );
498              
499 10         72 SCENARIO:
500 10         15 foreach my $scenario ( @{ $self->scenarios } ) {
501              
502 23         621 _check_scenario_steps($scenario);
503              
504 23 100       98 my $subject = $scenario->{Scenario}
505             or die "Missing the name of Scenario";
506              
507 22 100       30 my @examples = @{ $scenario->{Examples} || [ {} ] };
  22         156  
508              
509 22         53 my %stash = ();
510 22         77 my $stash_ref = bless \%stash, ref $self;
511              
512 22         880 Readonly $stash{Scenario} => $subject;
513 22         3506 Readonly $stash{Examples} => \@examples;
514 22         2814 Readonly $stash{FEATURE_WIDE} => $self->FEATURE_WIDE_VAR;
515              
516 22         2536 my %triggers = ();
517              
518             $triggers{Before} = sub {
519 57     57   151 $self->_trigger_before_running_step(
520             Before => ( $subject, $scenario ) );
521 22         123 };
522              
523             $triggers{After} = sub {
524 42     42   121 $self->_trigger_before_running_step(
525             After => ( $subject, $scenario ) );
526 22         84 };
527              
528             EXAMPLE:
529 22         49 foreach my $example (@examples) {
530 31         203 $stash{Example} = $example;
531              
532 31         115 my $subject = _apply_example( $subject => %$example );
533              
534 31         136 $self->Log("\n--> Scenario: $subject\n");
535              
536             STEP:
537 31         8780 foreach my $step (@run_through) {
538 170         3431 $stash{Step} = $step;
539 170 100       560 my $intercept =
540             $self->_run_step( $step, $scenario, $example, $stash_ref,
541             $triggers{$step} )
542             or next STEP;
543 10 100       730 next STEP if $intercept eq $NEXT_STEP;
544 7 100       55 next EXAMPLE if $intercept eq $NEXT_EXAMPLE;
545 3 50       20 next SCENARIO if $intercept eq $NEXT_SCENARIO;
546             }
547             }
548             }
549             }
550              
551             sub _trigger_before_running_step {
552 99     99   2536 my $self = shift;
553 99         125 my $big_name = shift;
554 99         119 my $subject = shift;
555 99         105 my $scenario = shift;
556 99         198 my $small_name = lcfirst $big_name;
557 99         186 my $array_name = "_$small_name" . 's';
558 99 50       107 if ( !@{ $self->$array_name } ) {
  99         316  
559 0         0 $self->NextStep;
560             }
561 99 100       1935 if ( !$scenario->{$big_name} ) {
562 32         112 $scenario->{$big_name} = $subject;
563             }
564             }
565              
566             sub _run_step {
567 170     170   222 my $self = shift;
568 170         202 my $step = shift;
569 170         180 my $scenario = shift;
570 170         182 my $example = shift;
571 170         163 my $stash_ref = shift;
572 170   100 71   729 my $before_step = shift || sub { };
  71         188  
573             try {
574 170     170   8524 my $small_step = lc $step;
575 170         1258 my $big_step = ucfirst $step;
576 170         313 my $array_name = "_$small_step" . 's';
577 170         413 $before_step->();
578 170         806 _run_test(
579             $big_step => $scenario->{$big_step},
580             $example, $self->$array_name, $stash_ref
581             );
582             }
583             catch {
584 13     13   952 my $int = _intercept();
585 13 100       766 return $int
586             ? $int
587             : confess($_);
588 170         1385 };
589             }
590              
591             has FEATURE_WIDE_VAR => (
592             is => "ro",
593             isa => "HashRef",
594             default => sub { {} },
595             );
596              
597             sub _run_test {
598 170     170   1581 my $step = shift;
599 170 100       583 my $preconditions = shift
600             or die "Missing '$step' in scenario";
601 167         189 my $example_ref = shift;
602 167         171 my $items_ref = shift;
603 167         215 my $stash_ref = shift;
604              
605 167 100       573 my @preconditions =
606             ref $preconditions eq "ARRAY"
607             ? @$preconditions
608             : ($preconditions);
609              
610 167         284 foreach my $precondition (@preconditions) {
611              
612 190 50       461 return if !$precondition;
613 190 100 100     599 return if ref $precondition && !%$precondition;
614              
615 188         331 foreach my $item (@$items_ref) {
616 423         41562 my $condition = $item->{condition};
617 423         978 $precondition = _apply_example( $precondition => %$example_ref );
618 423 100       952 if ( ref $precondition ) {
619 7         71 my %checks = _check_hash_has_the_only_keys(
620             [qw(condition data)] => %$precondition );
621 7 50       28 if ( $checks{missing} ) {
622 0         0 die sprintf "\nFIXME: missing setting of %s $step\n\n",
623 0         0 join( ", ", map { qq{"$_"} } @{ $checks{missing} } );
  0         0  
624             }
625 7         51 $stash_ref->{data} = $precondition->{data};
626 7         23 $stash_ref->{"_${step}_data"} = $precondition->{data};
627 7         12 $precondition = $precondition->{condition};
628             }
629 423 100       4199 if ( $precondition =~ /$condition/ ) {
630 117         494 $item->{definition}->( $stash_ref, "$step $precondition" );
631             }
632             }
633             }
634             }
635              
636             sub _apply_example {
637 454     454   554 my $pre_cond = shift;
638 454 100       2048 my %example = @_
639             or return $pre_cond;
640 176         391 foreach my $key ( keys %example ) {
641 477 50       1265 if ( ref $pre_cond ) {
642 0         0 $pre_cond->{condition} =~ s/<\Q$key\E>/$example{$key}/g;
643             }
644             else {
645 477         9389 $pre_cond =~ s/<\Q$key\E>/$example{$key}/g;
646             }
647             }
648 176         726 return $pre_cond;
649             }
650              
651             sub _intercept {
652 13 50   13   72 my $error = $_
653             or return q{};
654 13 100       37 return q{} if !ref $error;
655 10 50       28 return q{} if ref $error ne "HASH";
656 10 50       31 my $intercept = $error->{intercept}
657             or return q{};
658 10         20 return $intercept;
659             }
660              
661             Readonly my @HEADS => qw(
662             Scenario
663             Examples
664             );
665              
666             sub _check_scenario_steps {
667 23     23   41 my $scenario = shift;
668 23         130 my %scenario_hash = ();
669 23 50       75 if ( ref $scenario eq "ARRAY" ) {
670 0         0 %scenario_hash = @$scenario;
671             }
672 23 50       75 if ( ref $scenario eq "HASH" ) {
673 23         143 %scenario_hash = %$scenario;
674             }
675              
676 23         119 my %known = map { $_ => 1 } ( @HEADS, @STEPS );
  161         2141  
677              
678 23 50       307 my %result =
679             _check_hash_has_the_only_keys( [ @HEADS, @STEPS ], %scenario_hash )
680             or return;
681              
682 23 50       116 return if !@{ $result{invalid} };
  23         149  
683              
684 0 0       0 my $subject =
685             $scenario_hash{Scenario} ? " at '$scenario_hash{Scenario}'" : q{};
686              
687 0         0 die sprintf "\nFIXME: unrecognized steps %s$subject\n\n",
688 0         0 join( ", ", map { qq{"$_"} } @{ $result{invalid} } );
  0         0  
689             }
690              
691             sub _check_hash_has_the_only_keys {
692 30     30   697 my $keys_ref = shift;
693 30         113 my %hash = @_;
694              
695 30         70 my %needed = map { $_ => 1 } @$keys_ref;
  175         676  
696 30         93 my @invalid = grep { !$needed{$_} } keys %hash;
  113         246  
697 30         80 my @missing = grep { !exists $hash{$_} } keys %needed;
  175         336  
698              
699 30 100 33     171 return if !@invalid && !@missing;
700              
701             return (
702 23         326 invalid => \@invalid,
703             missing => \@missing,
704             );
705             }
706              
707             ## method name in Test::More
708             ## e.g. diag, explain, note, etc...
709             has verbose => (
710             is => "ro",
711             isa => "Str",
712             default => "explain",
713             );
714              
715             =head2 Log
716              
717             To use different Test verbose methods like diag, note or explain
718              
719             To set the method by
720              
721             export CUCUMBER_VERBOSE=diag
722              
723             or
724              
725             $ENV{CUCUMBER_VERBOSE} = "diag";
726              
727             or
728              
729             ...::Tiny->new( verbose => "diag" );
730              
731             By default the method is "explain"
732              
733             =head3 usage
734              
735             $cucumber->Log( "here" );
736              
737             $cucumber->Given(qr/.+/ => sub {
738             my $c = shift;
739             $c->Log( "Test" );
740             });
741              
742             =cut
743              
744             sub Log {
745 55     55 1 184 my $self = shift;
746 55 50       129 my $message = shift
747             or return;
748 55 50 33     243 my $mode = $ENV{CUCUMBER_VERBOSE} || $self->verbose
749             or return;
750 55 50       389 my $code = Test::More->can($mode)
751             or confess(
752             "FIXME: Invalid verbose mode $mode. Try any method in Test::More");
753 55         180 $code->($message);
754             }
755              
756             =head1 BUILTIN STEPS
757              
758             =head2 debugger
759              
760             Use debugger in any steps with perl -d
761              
762             that will stop to the point when reached.
763              
764             e.g.
765              
766             Test::Cucumber::Tiny->Scenarios(
767             {
768             Given => "a child found a book in library",
769             When => "he finished reading",
770             Then => [
771             "debugger", ## <---- STOP here when run with perl -d test.t
772             "he will return it",
773             ]
774             }
775             );
776              
777             =head1 BUILTIN DATA POINTS
778              
779             =head2 $c
780              
781             Scenario wide stash, each scenario has it own one.
782              
783             any step subref the first arguments will be a hashref
784              
785             e.g.
786              
787             $cucumber->Given( qr/.+/ => sub {
788             my $c = shift; ## it is a hashref
789             my $subject = shift; ## The subject of the step
790             $c->Log( $subject );
791             });
792              
793             =head2 $c->{FEATURE_WIDE}
794              
795             Feature wide stash, all scenarios shared the same one.
796              
797             you can reach it inside the scenario stash by
798             FEATURE_WIDE key
799              
800             e.g.
801              
802             $cucumber->Given( qr/.+/ => sub {
803             my $c = shift;
804             my $subject = shift;
805             my $f = $c->{FEATURE_WIDE}; ## A readonly HashRef
806             $f->{something_here} = 1;
807             $c->Log( $subject );
808             });
809              
810             =head2 $c->{Scenario}
811              
812             The subject you set for that scenario
813              
814             e.g.
815              
816             $cucumber->Given( qr/.+/ => sub {
817             my $c = shift;
818             $c->Log( $c->{Scenario} );
819             });
820              
821             =head2 $c->{Step}
822              
823             The subject you set for the current step
824              
825             e.g.
826              
827             $cucumber->Given( qr/.+/ => sub {
828             my $c = shift;
829             $c->Log( $c->{Step} );
830             });
831              
832             =head2 $c->{data}
833              
834             The current running step sample data
835              
836             e.g.
837              
838             ...::Tiny->Scenarios(
839             {
840             Given => {
841             condition => "...",
842             data => "ANYTHING HERE",
843             }, ...
844             }
845             )
846             ->Given( qr/.+/ => sub {
847             my $c = shift;
848             my $anything_here = $c->{data};
849             });
850              
851             =head2 $c->{Example}
852              
853             The current running example
854              
855             =head2 $c->{Examples}
856              
857             All the examples in the current scenario
858              
859             e.g.
860              
861             ...::Tiny->Scenarios(
862             {
863             Given => "... <placeholder>",
864             Examples => [
865             {
866             placeholder => "foobar",
867             },
868             {
869             placeholder => "sample",
870             }
871             ]
872             }
873             )
874             ->Given( qr/.+/ => sub {
875             my $c = shift;
876             my $examples = $c->{data};
877             });
878              
879             =cut
880              
881             =head1 SEE ALSO
882              
883             L<http://cukes.info/>
884              
885             L<https://github.com/cucumber/cucumber/wiki/Scenario-outlines>
886              
887             =cut
888              
889             sub _decode_yml {
890 6 100   6   29 my $yml_file = shift
891             or die "Missing YAML file\n";
892              
893 5 100       166 if ( !-f $yml_file ) {
894 1         8 die "YAML file is not found\n";
895             }
896              
897 4 100       44 my $scenarios_ref = YAML::LoadFile($yml_file)
898             or die "YAML file has no scenarios";
899              
900 3 100       31491 if ( ref $scenarios_ref ne "ARRAY" ) {
901 1         11 die "Invalid sceanrio in yml file. It is expecting array list\n";
902             }
903              
904 2         16 return @$scenarios_ref;
905             }
906              
907 6     6   60 no Mo;
  6         13  
  6         232  
908 6     6   39 no Carp;
  6         11  
  6         175  
909 6     6   28 no YAML;
  6         11  
  6         173  
910 6     6   28 no Try::Tiny;
  6         10  
  6         305  
911              
912             1;