File Coverage

blib/lib/Test/Given/Context.pm
Criterion Covered Total %
statement 124 124 100.0
branch 27 28 96.4
condition 12 14 85.7
subroutine 30 30 100.0
pod 0 18 0.0
total 193 214 90.1


line stmt bran cond sub pod time code
1             package Test::Given::Context;
2 41     41   196 use strict;
  41         69  
  41         1381  
3 41     41   190 use warnings;
  41         62  
  41         2529  
4              
5             BEGIN {
6 41     41   195 require Exporter;
7 41         610 our @ISA = qw(Exporter);
8 41         743 our @EXPORT_OK = qw(define_var);
9             }
10              
11 41     41   23112 use Test::Given::Check;
  41         118  
  41         1418  
12 41     41   28408 use Test::Given::Aspect;
  41         108  
  41         1006  
13 41     41   208 use Test::Given::Builder;
  41         67  
  41         461  
14             my $TEST_CLASS = 'Test::Given::Builder';
15              
16             sub new {
17 134     134 0 410 my ($class, $description, $parent) = @_;
18 134         1187 bless {
19             description => $description,
20             parent => $parent,
21             }, $class;
22             }
23              
24             sub add_context {
25 93     93 0 180 my ($self, $description) = @_;
26 93         712 my $subcontext = Test::Given::Context->new($description, $self);
27 93         151 push @{ $self->{contexts} }, $subcontext;
  93         495  
28 93         265 return $subcontext;
29             }
30              
31 90     90 0 3978 sub parent { shift->{parent} }
32              
33 99     99 0 274 sub add_given { shift->_add('givens', _with_package(@_)) }
34 20     20 0 49 sub add_when { shift->_add('whens', _with_package(@_)) }
35 29     29 0 87 sub add_invariant { shift->_add('invariants', _with_package(@_)) }
36 8     8 0 18 sub add_done { shift->_add('dones', _with_package(@_)) }
37              
38             sub add_then {
39 137     137 0 221 my $self = shift;
40 137         297 $self->_add('thens', @_);
41             }
42              
43             sub add_and {
44 82     82 0 121 my ($self) = shift;
45 82         127 my $and_type = $self->{and_type};
46              
47 82 100       450 die "'And' requires previous Given, When, Invariant, Then, or onDone clause in current context\n" unless $and_type;
48              
49 80 100       193 if ( $and_type eq 'thens' ) {
50 52         61 my $then_parent = ${ $self->{thens} }[$#{ $self->{thens} }];
  52         167  
  52         91  
51 52         197 $then_parent->add_check(@_);
52             }
53             else {
54 28         65 $self->_add($and_type, _with_package(@_));
55             }
56             }
57              
58             sub _with_package {
59 184 100   184   459 if (@_ > 1) {
60 106         807 unshift @_, (caller(2))[0];
61 106         10339 return reverse(@_);
62             }
63 78         225 return @_;
64             }
65              
66             my %class_lu = (
67             contexts => 'Test::Given::Context',
68             givens => 'Test::Given::Given',
69             whens => 'Test::Given::When',
70             invariants => 'Test::Given::Invariant',
71             thens => 'Test::Given::Test',
72             dones => 'Test::Given::Done',
73             );
74             sub _add {
75 321     321   632 my ($self, $type, @args) = @_;
76 321         552 $self->{and_type} = $type;
77 321         534 my $class = $class_lu{$type};
78 321         359 push @{ $self->{$type} }, $class->new(@args);
  321         2057  
79             }
80              
81             sub run_tests {
82 127     127 0 321 my ($self, $indent) = @_;
83 127   100     507 $indent ||= '';
84              
85 127         490 my $tb = $TEST_CLASS->builder;
86 127 100       1499 $tb->note($indent . $self->{description}) if $self->{parent};
87              
88 127 100 100     7973 if ( !$self->{thens} && !_okay_to_have_no_tests($self) ) {
89 3         72 warn "No 'Then' or 'Invariant' clauses in context: $self->{description}\n";
90             }
91             else {
92 124         195 foreach my $then (@{ $self->{thens} }) {
  124         536  
93 135         521 $then->execute($self);
94             }
95             }
96              
97 125 100       548 if ( $self->{contexts} ) {
98 57         92 foreach my $context (@{ $self->{contexts} }) {
  57         162  
99 88         603 $context->run_tests($indent . '* ');
100             }
101             }
102              
103 121         469 $self->apply_dones();
104             }
105              
106             sub apply_givens {
107 306     306 0 406 my ($self) = @_;
108 306 100       1210 $self->{parent}->apply_givens() if $self->{parent};
109 306         473 map { $_->apply() } @{ $self->{givens} };
  253         937  
  306         798  
110             }
111              
112             my @exceptions;
113             sub exceptions {
114 133     133 0 400 return \@exceptions;
115             }
116              
117             sub apply_whens {
118 300     300 0 835 my ($self) = @_;
119 300 100       1498 $self->{parent}->apply_whens() if $self->{parent};
120             map {
121 36         44 eval { $_->apply() };
  36         157  
  300         859  
122 36 100       217 push @exceptions, $@ if $@;
123 300         424 } @{ $self->{whens} };
124             }
125              
126             sub apply_invariants {
127 300     300 0 452 my ($self, $exceptions) = @_;
128 300         399 my @failed = ();
129 300 100       1216 push @failed, $self->{parent}->apply_invariants($exceptions) if $self->{parent};
130 300         374 push @failed, grep { not $_->execute($exceptions) } @{ $self->{invariants} };
  123         381  
  300         697  
131 300         633 return @failed;
132             }
133              
134             sub apply_dones {
135 121     121 0 199 my ($self) = @_;
136 121         195 map { $_->apply() } @{ $self->{dones} };
  14         61  
  121         1250  
137             }
138              
139             sub _okay_to_have_no_tests {
140 41     41   160 my ($self) = @_;
141 41   33     948 return !$self->{parent} && !$self->{givens} && !$self->{whens} && !$self->{invariants};
142             }
143             sub _has_invariants {
144 47     47   138 my ($self) = @_;
145 47         93 my $context = $self;
146 47         87 my $has_invariants;
147 47   100     473 while ( $context && !$has_invariants ) {
148 56         130 $has_invariants = $context->{invariants};
149 56         189 $context = $context->{parent};
150             }
151 47         258 return $has_invariants;
152             }
153             sub test_count {
154 131     131 0 203 my ($self) = @_;
155 131 100       220 my $count = scalar @{ $self->{thens} || [] };
  131         665  
156              
157 131 100 100     541 if ( $count == 0 && $self->_has_invariants() ) {
158 4         13 $self->add_then();
159 4         8 $count = 1;
160             }
161              
162 131 50       382 map { $count += $_->test_count() } @{ $self->{contexts} || [] } if $self->{contexts};
  90 100       322  
  57         272  
163 131         475 return $count;
164             }
165              
166             my $context_vars = {};
167             sub reset {
168 135     135 0 215 my ($self) = @_;
169 135         293 @exceptions = ();
170 135         733 foreach my $package (keys %$context_vars) {
171 41     41   56451 no strict 'refs';
  41         83  
  41         4878  
172 105         157 foreach my $name (keys %{ $context_vars->{$package} }) {
  105         407  
173 291         331 undef *{$package . $name};
  291         1025  
174             }
175             }
176             }
177              
178             sub define_var {
179 242     242 0 32777996 my ($package, $name, $value) = @_;
180 242         1115 $context_vars->{$package}->{$name} = $value;
181 41     41   241 no strict 'refs';
  41         84  
  41         2229  
182 242         679 *{$package . $name} = $value;
  242         2307  
183             }
184              
185             1;