line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Proto::Common; |
2
|
15
|
|
|
15
|
|
20832
|
use 5.008; |
|
15
|
|
|
|
|
53
|
|
|
15
|
|
|
|
|
589
|
|
3
|
15
|
|
|
15
|
|
83
|
use strict; |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
436
|
|
4
|
15
|
|
|
15
|
|
87
|
use warnings; |
|
15
|
|
|
|
|
36
|
|
|
15
|
|
|
|
|
371
|
|
5
|
15
|
|
|
15
|
|
7101
|
use Sub::Name; |
|
15
|
|
|
|
|
5631
|
|
|
15
|
|
|
|
|
897
|
|
6
|
15
|
|
|
15
|
|
119
|
use Exporter 'import'; |
|
15
|
|
|
|
|
29
|
|
|
15
|
|
|
|
|
530
|
|
7
|
15
|
|
|
15
|
|
90
|
use Scalar::Util qw(blessed looks_like_number); |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
2772
|
|
8
|
|
|
|
|
|
|
our @EXPORT = qw(define_test define_simple_test simple_test upgrade upgrade_comparison); |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $TEST_PREFIX = '_TEST_'; #~ this is used when creating internal methods. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Test::Proto::Common - Provides common functions for Test::Proto development |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use Test::Proto::Common; # exports all functions automatically |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
Provides functions used to build a Prototype class. |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=cut |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 FUNCTIONS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
All these functions are for use in prototype classes, not in scripts. |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head3 define_test |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
define_test 'is_uppercase', sub { |
31
|
|
|
|
|
|
|
my ($self, $data, $reason) = @_; # self is the runner, NOT the prototype |
32
|
|
|
|
|
|
|
if ($self->subject =~ !/[a-z]/){ |
33
|
|
|
|
|
|
|
return $self->pass; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
return $self->fail; |
36
|
|
|
|
|
|
|
}; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Adds a test definition to the class. This allows you to create user-facing test methods which interact with the test definition. The name you provide is the name of the test definition, which usually matches the test method (but is not required to). |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Optionally, you can set the package to which this method is to be added as a third argument. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub define_test { |
45
|
814
|
|
|
814
|
1
|
2525
|
my ( $testName, $testSub, $customPackage ) = @_; |
46
|
814
|
|
|
|
|
3306
|
my ( $package, $filename, $line ) = caller; |
47
|
814
|
50
|
|
|
|
2433
|
$package = $customPackage if defined $customPackage; |
48
|
|
|
|
|
|
|
{ |
49
|
15
|
|
|
15
|
|
93
|
no strict 'refs'; |
|
15
|
|
|
|
|
39
|
|
|
15
|
|
|
|
|
3905
|
|
|
814
|
|
|
|
|
1124
|
|
50
|
814
|
|
|
|
|
2177
|
my $fullName = $package . '::' . $TEST_PREFIX . $testName; |
51
|
814
|
|
|
|
|
13375
|
*$fullName = subname( $TEST_PREFIX . $testName, $testSub ); #~ Consider Sub::Install here, per Khisanth on irc.freenode.net#perl |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
#~ return value of this not specified |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head3 define_simple_test |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Adds a test definition to the class. In this case, the subroutine passed evaluates the subject against the expected data. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=cut |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub define_simple_test { |
64
|
0
|
|
|
0
|
1
|
0
|
my ( $testName, $testSub, $customPackage ) = @_; |
65
|
0
|
|
|
|
|
0
|
my ( $package, $filename, $line ) = caller; |
66
|
0
|
0
|
|
|
|
0
|
$package = $customPackage if defined $customPackage; |
67
|
|
|
|
|
|
|
define_test( |
68
|
|
|
|
|
|
|
$testName, |
69
|
|
|
|
|
|
|
sub { |
70
|
0
|
|
|
0
|
|
0
|
my ( $self, $data, $reason ) = ( shift, shift, shift ); # self is the runner, NOT the prototype |
71
|
0
|
0
|
|
|
|
0
|
if ( $testSub->( $self->subject, $data->{expected} ) ) { |
72
|
0
|
|
|
|
|
0
|
return $self->pass; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
else { |
75
|
0
|
|
|
|
|
0
|
return $self->fail; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
}, |
78
|
0
|
|
|
|
|
0
|
$package |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head3 simple_test |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
simple_test 'lc_eq', sub { |
85
|
|
|
|
|
|
|
return lc ($_[0]) eq $_[1]; |
86
|
|
|
|
|
|
|
}; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
... |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
p->lc_eq('yes')->ok('Yes'); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Adds a test method to the class. The first argument is the name of that method, the second argument is the code to be executed - however, the code should return only a true or false value, and is passed only the test subject and the expected value, not the runner or full data. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
The test method itself takes one argument, the expected value. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub simple_test { |
99
|
0
|
|
|
0
|
1
|
0
|
my ( $testName, $testSub ) = @_; |
100
|
0
|
|
|
|
|
0
|
my ( $package, $filename, $line ) = caller; |
101
|
|
|
|
|
|
|
{ |
102
|
15
|
|
|
15
|
|
97
|
no strict 'refs'; |
|
15
|
|
|
|
|
28
|
|
|
15
|
|
|
|
|
11100
|
|
|
0
|
|
|
|
|
0
|
|
103
|
|
|
|
|
|
|
{ |
104
|
|
|
|
|
|
|
#package $package; |
105
|
0
|
|
|
|
|
0
|
define_simple_test( $testName, $testSub, $package ); |
|
0
|
|
|
|
|
0
|
|
106
|
|
|
|
|
|
|
} |
107
|
0
|
|
|
|
|
0
|
my $fullName = $package . '::' . $testName; |
108
|
|
|
|
|
|
|
*$fullName = subname( |
109
|
|
|
|
|
|
|
$testName, |
110
|
|
|
|
|
|
|
sub { |
111
|
0
|
|
|
0
|
|
0
|
my ( $self, $expected, $reason ) = ( shift, shift, shift ); |
112
|
0
|
|
|
|
|
0
|
$self->add_test( $testName, { expected => $expected }, $reason ); |
113
|
|
|
|
|
|
|
} |
114
|
0
|
|
|
|
|
0
|
); # Consider Sub::Install here, per Khisanth on irc.freenode.net#perl |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head3 upgrade |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
upgrade('NONE'); # returns Test::Proto::Base->new()->eq('NONE') |
121
|
|
|
|
|
|
|
upgrade(1); # returns Test::Proto::Base->new()->num_eq(1) |
122
|
|
|
|
|
|
|
upgrade(['foo']); # returns Test::Proto::ArrayRef->new()->array_eq(['foo']) |
123
|
|
|
|
|
|
|
upgrade({'foo'=>'bar'}); # returns Test::Proto::HashRef->new()->hash_of({'foo'=>'bar'}) |
124
|
|
|
|
|
|
|
upgrade(sub {return $_ * 2 == 4}); Test::Proto::Base->new()->try(...) |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Returns a Prototype which corresponds to the data in the first argument. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
If the first argument is already a prototype, this does nothing. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Use this when you have a parameter and want to validate data against it, but you do not know if it is a prototype or 'natural data'. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub upgrade { |
135
|
2242
|
|
|
2242
|
1
|
4591
|
my ( $expected, $noref ) = @_; |
136
|
|
|
|
|
|
|
{ |
137
|
2242
|
|
|
|
|
2753
|
require Test::Proto::Base; |
|
2242
|
|
|
|
|
15220
|
|
138
|
2242
|
|
|
|
|
17160
|
require Test::Proto::HashRef; |
139
|
2242
|
|
|
|
|
13577
|
require Test::Proto::ArrayRef; |
140
|
|
|
|
|
|
|
|
141
|
2242
|
50
|
|
|
|
8124
|
if ( defined ref $expected ) { |
142
|
2242
|
100
|
|
|
|
10010
|
if ( blessed $expected) { |
143
|
1185
|
50
|
33
|
|
|
29226
|
return Test::Proto::ArrayRef->new()->array->contains_only($expected) |
|
|
|
33
|
|
|
|
|
144
|
|
|
|
|
|
|
if $expected->isa('Test::Proto::Series') |
145
|
|
|
|
|
|
|
or $expected->isa('Test::Proto::Repeatable') |
146
|
|
|
|
|
|
|
or $expected->isa('Test::Proto::Alternation'); |
147
|
1185
|
100
|
|
|
|
34462
|
return $expected if $expected->isa('Test::Proto::Base'); |
148
|
|
|
|
|
|
|
} |
149
|
1082
|
100
|
|
|
|
7035
|
return Test::Proto::ArrayRef->new()->array->array_eq($expected) if ref $expected eq 'ARRAY'; |
150
|
974
|
100
|
|
|
|
2972
|
return Test::Proto::HashRef->new()->hash->superhash_of($expected) if ref $expected eq 'HASH'; |
151
|
971
|
100
|
|
|
|
3289
|
return Test::Proto::Base->new()->like($expected) if ref $expected eq 'Regexp'; |
152
|
946
|
100
|
|
|
|
4280
|
return Test::Proto::Base->new()->try($expected) if ref $expected eq 'CODE'; |
153
|
|
|
|
|
|
|
} |
154
|
913
|
100
|
|
|
|
14333
|
return Test::Proto::Base->new()->scalar->num_eq($expected) if Scalar::Util::looks_like_number($expected); |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
#return Test::Proto::Base->new()->eq($expected) if $noref; |
157
|
530
|
|
|
|
|
14308
|
return Test::Proto::Base->new()->scalar->eq($expected); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head3 upgrade_comparison |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
upgrade_comparison(sub {lc shift cmp lc shift}, 'Lowercase Comparison'); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
This creates a Test::Proto::Compare object using the code provided in the first argument. The second argument, if present, is used as the summary. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
If the first argument is either of the strings 'cmp' or '<=>', it will return the appropriate string or numeric comparison, as these are special-cased. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=cut |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub upgrade_comparison { |
172
|
60
|
|
|
60
|
1
|
2828
|
require Test::Proto::Compare; |
173
|
60
|
|
|
|
|
2532
|
require Test::Proto::Compare::Numeric; |
174
|
60
|
|
|
|
|
156
|
my ( $comparison, $summary ) = @_; |
175
|
60
|
100
|
|
|
|
225
|
$summary = 'Unknown comparison' unless defined $summary; #:5.8 |
176
|
60
|
100
|
66
|
|
|
636
|
if ( ref $comparison eq 'CODE' ) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
177
|
27
|
|
|
|
|
717
|
return Test::Proto::Compare->new($comparison)->summary($summary); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
elsif ( blessed $comparison and $comparison->isa('Test::Proto::Compare') ) { |
180
|
3
|
|
|
|
|
13
|
return $comparison; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
elsif ( defined $comparison and !ref $comparison ) { |
183
|
2
|
100
|
|
|
|
40
|
return Test::Proto::Compare->new if $comparison eq 'cmp'; |
184
|
1
|
50
|
|
|
|
31
|
return Test::Proto::Compare::Numeric->new if $comparison eq '<=>'; |
185
|
|
|
|
|
|
|
} |
186
|
28
|
|
|
|
|
738
|
return Test::Proto::Compare->new; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head3 chainable |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
around 'attr', 'other_attr', \&Test::Proto::Common::chainable; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
... |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
$object->attr(2)->some_method; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Use this to make a Moo attribute chainable. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub chainable { |
202
|
185869
|
|
|
185869
|
1
|
4587000
|
my $orig = shift; |
203
|
185869
|
|
|
|
|
237636
|
my $self = shift; |
204
|
185869
|
100
|
|
|
|
366020
|
if ( exists $_[0] ) { |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
#~ when setting, return self |
207
|
18118
|
|
|
|
|
48042
|
$orig->( $self, @_ ); |
208
|
18118
|
|
|
|
|
53007
|
return $self; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
else { |
211
|
|
|
|
|
|
|
#~ when getting, return value |
212
|
167751
|
|
|
|
|
2321785
|
return $orig->( $self, @_ ); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
1; |