| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Test2::Tools::TypeTiny; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Test2 tools for checking Type::Tiny types |
|
4
|
3
|
|
|
3
|
|
209556
|
use version; |
|
|
3
|
|
|
|
|
3813
|
|
|
|
3
|
|
|
|
|
24
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = 'v0.93.1'; # VERSION |
|
6
|
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
360
|
use v5.18; |
|
|
3
|
|
|
|
|
22
|
|
|
8
|
3
|
|
|
3
|
|
22
|
use strict; |
|
|
3
|
|
|
|
|
19
|
|
|
|
3
|
|
|
|
|
92
|
|
|
9
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
|
3
|
|
|
|
|
24
|
|
|
|
3
|
|
|
|
|
230
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
3
|
|
|
3
|
|
969
|
use parent 'Exporter'; |
|
|
3
|
|
|
|
|
609
|
|
|
|
3
|
|
|
|
|
17
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
3
|
|
|
3
|
|
242
|
use List::Util v1.29 qw< uniq shuffle pairmap pairs >; |
|
|
3
|
|
|
|
|
61
|
|
|
|
3
|
|
|
|
|
468
|
|
|
14
|
3
|
|
|
3
|
|
18
|
use Scalar::Util qw< blessed refaddr >; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
231
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
3
|
|
|
3
|
|
1859
|
use Test2::API qw< context run_subtest >; |
|
|
3
|
|
|
|
|
272113
|
|
|
|
3
|
|
|
|
|
445
|
|
|
17
|
3
|
|
|
3
|
|
1847
|
use Test2::Tools::Basic; |
|
|
3
|
|
|
|
|
4101
|
|
|
|
3
|
|
|
|
|
341
|
|
|
18
|
3
|
|
|
3
|
|
2287
|
use Test2::Tools::Compare qw< is like >; |
|
|
3
|
|
|
|
|
243180
|
|
|
|
3
|
|
|
|
|
452
|
|
|
19
|
3
|
|
|
3
|
|
1777
|
use Test2::Tools::Exception qw< lives dies >; |
|
|
3
|
|
|
|
|
2461
|
|
|
|
3
|
|
|
|
|
217
|
|
|
20
|
3
|
|
|
3
|
|
24
|
use Test2::Compare qw< compare strict_convert >; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
144
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
3
|
|
|
3
|
|
1975
|
use Data::Dumper; |
|
|
3
|
|
|
|
|
24699
|
|
|
|
3
|
|
|
|
|
306
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
3
|
|
|
3
|
|
1798
|
use namespace::clean; |
|
|
3
|
|
|
|
|
52224
|
|
|
|
3
|
|
|
|
|
35
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our $DEBUG_INDENT = 4; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
#pod =encoding utf8 |
|
29
|
|
|
|
|
|
|
#pod |
|
30
|
|
|
|
|
|
|
#pod =head1 SYNOPSIS |
|
31
|
|
|
|
|
|
|
#pod |
|
32
|
|
|
|
|
|
|
#pod use Test2::V0; |
|
33
|
|
|
|
|
|
|
#pod use Test2::Tools::TypeTiny; |
|
34
|
|
|
|
|
|
|
#pod |
|
35
|
|
|
|
|
|
|
#pod use MyTypes qw< FullyQualifiedDomainName >; |
|
36
|
|
|
|
|
|
|
#pod |
|
37
|
|
|
|
|
|
|
#pod type_subtest FullyQualifiedDomainName, sub { |
|
38
|
|
|
|
|
|
|
#pod my $type = shift; |
|
39
|
|
|
|
|
|
|
#pod |
|
40
|
|
|
|
|
|
|
#pod should_pass_initially( |
|
41
|
|
|
|
|
|
|
#pod $type, |
|
42
|
|
|
|
|
|
|
#pod qw< |
|
43
|
|
|
|
|
|
|
#pod www.example.com |
|
44
|
|
|
|
|
|
|
#pod example.com |
|
45
|
|
|
|
|
|
|
#pod www123.prod.some.domain.example.com |
|
46
|
|
|
|
|
|
|
#pod llanfairpwllgwyngllgogerychwyrndrobwllllantysiliogogogoch.co.uk |
|
47
|
|
|
|
|
|
|
#pod >, |
|
48
|
|
|
|
|
|
|
#pod ); |
|
49
|
|
|
|
|
|
|
#pod should_fail( |
|
50
|
|
|
|
|
|
|
#pod $type, |
|
51
|
|
|
|
|
|
|
#pod qw< www ftp001 .com domains.t x.c prod|ask|me -prod3.example.com >, |
|
52
|
|
|
|
|
|
|
#pod ); |
|
53
|
|
|
|
|
|
|
#pod should_coerce_into( |
|
54
|
|
|
|
|
|
|
#pod $type, |
|
55
|
|
|
|
|
|
|
#pod qw< |
|
56
|
|
|
|
|
|
|
#pod ftp001-prod3 ftp001-prod3.ourdomain.com |
|
57
|
|
|
|
|
|
|
#pod prod-ask-me prod-ask-me.ourdomain.com |
|
58
|
|
|
|
|
|
|
#pod nonprod3-foobar-me nonprod3-foobar-me.ourdomain.com |
|
59
|
|
|
|
|
|
|
#pod >, |
|
60
|
|
|
|
|
|
|
#pod ); |
|
61
|
|
|
|
|
|
|
#pod should_sort_into( |
|
62
|
|
|
|
|
|
|
#pod $type, |
|
63
|
|
|
|
|
|
|
#pod [qw< ftp001-prod3 ftp001-prod3.ourdomain.com prod-ask-me.ourdomain.com >], |
|
64
|
|
|
|
|
|
|
#pod ); |
|
65
|
|
|
|
|
|
|
#pod |
|
66
|
|
|
|
|
|
|
#pod parameters_should_create_type( |
|
67
|
|
|
|
|
|
|
#pod $type, |
|
68
|
|
|
|
|
|
|
#pod [], [3], [0, 0], [1, 2], |
|
69
|
|
|
|
|
|
|
#pod ); |
|
70
|
|
|
|
|
|
|
#pod parameters_should_die_as( |
|
71
|
|
|
|
|
|
|
#pod $type, |
|
72
|
|
|
|
|
|
|
#pod [], qr, |
|
73
|
|
|
|
|
|
|
#pod [-3], qr, |
|
74
|
|
|
|
|
|
|
#pod [0.2], qr, |
|
75
|
|
|
|
|
|
|
#pod ); |
|
76
|
|
|
|
|
|
|
#pod |
|
77
|
|
|
|
|
|
|
#pod message_should_report_as( |
|
78
|
|
|
|
|
|
|
#pod $type, |
|
79
|
|
|
|
|
|
|
#pod undef, qr |
|
80
|
|
|
|
|
|
|
#pod ); |
|
81
|
|
|
|
|
|
|
#pod explanation_should_report_as( |
|
82
|
|
|
|
|
|
|
#pod $type, |
|
83
|
|
|
|
|
|
|
#pod undef, [ |
|
84
|
|
|
|
|
|
|
#pod qr, |
|
85
|
|
|
|
|
|
|
#pod ], |
|
86
|
|
|
|
|
|
|
#pod ); |
|
87
|
|
|
|
|
|
|
#pod }; |
|
88
|
|
|
|
|
|
|
#pod |
|
89
|
|
|
|
|
|
|
#pod done_testing; |
|
90
|
|
|
|
|
|
|
#pod |
|
91
|
|
|
|
|
|
|
#pod =head1 DESCRIPTION |
|
92
|
|
|
|
|
|
|
#pod |
|
93
|
|
|
|
|
|
|
#pod This module provides a set of tools for checking L types. This is similar to |
|
94
|
|
|
|
|
|
|
#pod L, but works against the L and has more functionality for testing |
|
95
|
|
|
|
|
|
|
#pod and troubleshooting coercions, error messages, and other aspects of the type. |
|
96
|
|
|
|
|
|
|
#pod |
|
97
|
|
|
|
|
|
|
#pod =head1 FUNCTIONS |
|
98
|
|
|
|
|
|
|
#pod |
|
99
|
|
|
|
|
|
|
#pod All functions are exported by default. These functions create L |
|
100
|
|
|
|
|
|
|
#pod to contain different classes of tests. |
|
101
|
|
|
|
|
|
|
#pod |
|
102
|
|
|
|
|
|
|
#pod Besides the wrapper itself, these functions are most useful wrapped inside of a L |
|
103
|
|
|
|
|
|
|
#pod coderef. |
|
104
|
|
|
|
|
|
|
#pod |
|
105
|
|
|
|
|
|
|
#pod =cut |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
our @EXPORT_OK = (qw< |
|
108
|
|
|
|
|
|
|
type_subtest |
|
109
|
|
|
|
|
|
|
should_pass_initially should_fail_initially should_pass should_fail should_coerce_into |
|
110
|
|
|
|
|
|
|
parameters_should_create_type parameters_should_die_as |
|
111
|
|
|
|
|
|
|
message_should_report_as explanation_should_report_as |
|
112
|
|
|
|
|
|
|
should_sort_into |
|
113
|
|
|
|
|
|
|
>); |
|
114
|
|
|
|
|
|
|
our @EXPORT = @EXPORT_OK; |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
#pod =head2 Wrappers |
|
117
|
|
|
|
|
|
|
#pod |
|
118
|
|
|
|
|
|
|
#pod =head3 type_subtest |
|
119
|
|
|
|
|
|
|
#pod |
|
120
|
|
|
|
|
|
|
#pod type_subtest Type, sub { |
|
121
|
|
|
|
|
|
|
#pod my $type = shift; |
|
122
|
|
|
|
|
|
|
#pod |
|
123
|
|
|
|
|
|
|
#pod ... |
|
124
|
|
|
|
|
|
|
#pod }; |
|
125
|
|
|
|
|
|
|
#pod |
|
126
|
|
|
|
|
|
|
#pod Creates a subtest with the given type as the test name, and passed as the only parameter. Using a |
|
127
|
|
|
|
|
|
|
#pod generic C<$type> variable makes it much easier to copy and paste test code from other type tests |
|
128
|
|
|
|
|
|
|
#pod without accidentally forgetting to change your custom type within the code. |
|
129
|
|
|
|
|
|
|
#pod |
|
130
|
|
|
|
|
|
|
#pod If the type can be inlined, this will also run two separate subtests (within the main type subtest) |
|
131
|
|
|
|
|
|
|
#pod to check both the inlined constraint and the slower coderef constraint. The second subtest will |
|
132
|
|
|
|
|
|
|
#pod have a inline-less type, cloned from the original type. This is done by stripping out the inlined |
|
133
|
|
|
|
|
|
|
#pod constraint (or generator) in the clone. |
|
134
|
|
|
|
|
|
|
#pod |
|
135
|
|
|
|
|
|
|
#pod The tester sub will be used in both subtests. If you need the inlined constraint for certain |
|
136
|
|
|
|
|
|
|
#pod tests, you can use the C<< $type->can_be_inlined >> method to check which version of the test its |
|
137
|
|
|
|
|
|
|
#pod running. However, inlined checks should do the exact same thing as coderef checks, so keep these |
|
138
|
|
|
|
|
|
|
#pod kind of exceptions to a minimum. |
|
139
|
|
|
|
|
|
|
#pod |
|
140
|
|
|
|
|
|
|
#pod Note that it doesn't do anything to the parent types. If your type check is solely relying on |
|
141
|
|
|
|
|
|
|
#pod parent checks, this will only run the one subtest. If the parent checks are part of your package, |
|
142
|
|
|
|
|
|
|
#pod you should check those separately. |
|
143
|
|
|
|
|
|
|
#pod |
|
144
|
|
|
|
|
|
|
#pod =cut |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub type_subtest ($&) { |
|
147
|
8
|
|
|
8
|
1
|
706050
|
my ($type, $tester_coderef) = @_; |
|
148
|
|
|
|
|
|
|
|
|
149
|
8
|
|
|
|
|
47
|
my $ctx = context(); |
|
150
|
8
|
|
|
|
|
6242
|
my $pass; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# XXX: Private method abuse |
|
153
|
8
|
100
|
66
|
|
|
50
|
if (!$type->_is_null_constraint && $type->has_inlined) { |
|
154
|
4
|
|
|
|
|
84
|
$pass = run_subtest( |
|
155
|
|
|
|
|
|
|
"Type Test: ".$type->display_name, |
|
156
|
|
|
|
|
|
|
\&_multi_type_split_subtest, |
|
157
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
158
|
|
|
|
|
|
|
$type, $tester_coderef, |
|
159
|
|
|
|
|
|
|
); |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
else { |
|
162
|
4
|
|
|
|
|
95
|
$pass = run_subtest( |
|
163
|
|
|
|
|
|
|
"Type Test: ".$type->display_name, |
|
164
|
|
|
|
|
|
|
$tester_coderef, |
|
165
|
|
|
|
|
|
|
{ buffered => 1 }, |
|
166
|
|
|
|
|
|
|
$type, |
|
167
|
|
|
|
|
|
|
); |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
8
|
|
|
|
|
44779
|
$ctx->release; |
|
171
|
|
|
|
|
|
|
|
|
172
|
8
|
|
|
|
|
353
|
return $pass; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub _multi_type_split_subtest { |
|
176
|
4
|
|
|
4
|
|
1503
|
my ($type, $tester_coderef) = @_; |
|
177
|
4
|
|
|
|
|
22
|
my $ctx = context(); |
|
178
|
|
|
|
|
|
|
|
|
179
|
4
|
|
|
|
|
274
|
plan 2; |
|
180
|
|
|
|
|
|
|
|
|
181
|
4
|
|
|
|
|
1359
|
my $orig_result = run_subtest( |
|
182
|
|
|
|
|
|
|
'original type', |
|
183
|
|
|
|
|
|
|
$tester_coderef, |
|
184
|
|
|
|
|
|
|
{ buffered => 1 }, |
|
185
|
|
|
|
|
|
|
$type, |
|
186
|
|
|
|
|
|
|
); |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
### XXX: There is some internal mechanics abuse to try to get this type, because Type::Tiny |
|
189
|
|
|
|
|
|
|
### doesn't really have a $type->create_inlineless_type method, and methods like _clone and |
|
190
|
|
|
|
|
|
|
### create_child_type don't cleanly do what we want. (We don't want a child type that |
|
191
|
|
|
|
|
|
|
### would be impacted by parental inlined constraints.) |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Create the inline-less type |
|
194
|
4
|
|
|
|
|
17890
|
my %inlineless_opts = %$type; |
|
195
|
4
|
|
|
|
|
42
|
delete $inlineless_opts{$_} for qw< |
|
196
|
|
|
|
|
|
|
compiled_type_constraint uniq tmp |
|
197
|
|
|
|
|
|
|
inlined inline_generator |
|
198
|
|
|
|
|
|
|
_overload_coderef _overload_coderef_no_rebuild |
|
199
|
|
|
|
|
|
|
>; |
|
200
|
4
|
|
|
|
|
12
|
$inlineless_opts{display_name} .= ' (inline-less)'; |
|
201
|
|
|
|
|
|
|
|
|
202
|
4
|
|
|
|
|
58
|
my $inlineless_type = blessed($type)->new(%inlineless_opts); |
|
203
|
|
|
|
|
|
|
|
|
204
|
4
|
|
|
|
|
780
|
my $inlineless_result = run_subtest( |
|
205
|
|
|
|
|
|
|
'inline-less type', |
|
206
|
|
|
|
|
|
|
$tester_coderef, |
|
207
|
|
|
|
|
|
|
{ buffered => 1 }, |
|
208
|
|
|
|
|
|
|
$inlineless_type, |
|
209
|
|
|
|
|
|
|
); |
|
210
|
|
|
|
|
|
|
|
|
211
|
4
|
|
|
|
|
23390
|
$ctx->release; |
|
212
|
4
|
|
66
|
|
|
73
|
return $orig_result && $inlineless_result; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
#pod =head2 Value Testers |
|
216
|
|
|
|
|
|
|
#pod |
|
217
|
|
|
|
|
|
|
#pod Most of these checks will run through C and C calls to confirm the |
|
218
|
|
|
|
|
|
|
#pod coderefs don't die. If you need to validate the error messages themselves, consider using some of |
|
219
|
|
|
|
|
|
|
#pod the L. |
|
220
|
|
|
|
|
|
|
#pod |
|
221
|
|
|
|
|
|
|
#pod =head3 should_pass_initially |
|
222
|
|
|
|
|
|
|
#pod |
|
223
|
|
|
|
|
|
|
#pod should_pass_initially($type, @values); |
|
224
|
|
|
|
|
|
|
#pod |
|
225
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will pass with all of the given C<@values>, without any |
|
226
|
|
|
|
|
|
|
#pod need for coercions. |
|
227
|
|
|
|
|
|
|
#pod |
|
228
|
|
|
|
|
|
|
#pod =cut |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub should_pass_initially { |
|
231
|
6
|
|
|
6
|
1
|
1558
|
my $ctx = context(); |
|
232
|
6
|
|
|
|
|
608
|
my $pass = run_subtest( |
|
233
|
|
|
|
|
|
|
'should pass (without coercions)', |
|
234
|
|
|
|
|
|
|
\&_should_pass_initially_subtest, |
|
235
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
236
|
|
|
|
|
|
|
@_, |
|
237
|
|
|
|
|
|
|
); |
|
238
|
6
|
|
|
|
|
7287
|
$ctx->release; |
|
239
|
|
|
|
|
|
|
|
|
240
|
6
|
|
|
|
|
211
|
return $pass; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub _should_pass_initially_subtest { |
|
244
|
6
|
|
|
6
|
|
2102
|
my ($type, @values) = @_; |
|
245
|
|
|
|
|
|
|
|
|
246
|
6
|
|
|
|
|
37
|
plan scalar @values; |
|
247
|
|
|
|
|
|
|
|
|
248
|
6
|
|
|
|
|
2032
|
foreach my $value (@values) { |
|
249
|
18
|
|
|
|
|
3788
|
my $val_dd = _dd($value); |
|
250
|
18
|
|
|
|
|
52
|
my @val_explain = _constraint_type_check_debug_map($type, $value); |
|
251
|
18
|
|
|
|
|
76
|
_check_error_message_methods($type, $value); |
|
252
|
|
|
|
|
|
|
|
|
253
|
18
|
|
|
|
|
687
|
ok $type->check($value), "$val_dd should pass", @val_explain; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
#pod =head3 should_fail_initially |
|
258
|
|
|
|
|
|
|
#pod |
|
259
|
|
|
|
|
|
|
#pod should_fail_initially($type, @values); |
|
260
|
|
|
|
|
|
|
#pod |
|
261
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will fail with all of the given C<@values>, without using |
|
262
|
|
|
|
|
|
|
#pod any coercions. |
|
263
|
|
|
|
|
|
|
#pod |
|
264
|
|
|
|
|
|
|
#pod This function is included for completeness. However, items in C should |
|
265
|
|
|
|
|
|
|
#pod realistically end up in either a L block (if it always fails, even with coercions) or |
|
266
|
|
|
|
|
|
|
#pod a L block (if it would pass after coercions). |
|
267
|
|
|
|
|
|
|
#pod |
|
268
|
|
|
|
|
|
|
#pod =cut |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub should_fail_initially { |
|
271
|
6
|
|
|
6
|
1
|
83
|
my $ctx = context(); |
|
272
|
6
|
|
|
|
|
688
|
my $pass = run_subtest( |
|
273
|
|
|
|
|
|
|
'should fail (without coercions)', |
|
274
|
|
|
|
|
|
|
\&_should_fail_initially_subtest, |
|
275
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
276
|
|
|
|
|
|
|
@_, |
|
277
|
|
|
|
|
|
|
); |
|
278
|
6
|
|
|
|
|
8558
|
$ctx->release; |
|
279
|
|
|
|
|
|
|
|
|
280
|
6
|
|
|
|
|
192
|
return $pass; |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub _should_fail_initially_subtest { |
|
284
|
6
|
|
|
6
|
|
1978
|
my ($type, @values) = @_; |
|
285
|
|
|
|
|
|
|
|
|
286
|
6
|
|
|
|
|
29
|
plan scalar @values; |
|
287
|
|
|
|
|
|
|
|
|
288
|
6
|
|
|
|
|
1780
|
foreach my $value (@values) { |
|
289
|
32
|
|
|
|
|
7363
|
my $val_dd = _dd($value); |
|
290
|
32
|
|
|
|
|
86
|
my @val_explain = _constraint_type_check_debug_map($type, $value); |
|
291
|
32
|
|
|
|
|
124
|
_check_error_message_methods($type, $value); |
|
292
|
|
|
|
|
|
|
|
|
293
|
32
|
|
|
|
|
38155
|
ok !$type->check($value), "$val_dd should fail", @val_explain; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
#pod =head3 should_pass |
|
298
|
|
|
|
|
|
|
#pod |
|
299
|
|
|
|
|
|
|
#pod should_pass($type, @values); |
|
300
|
|
|
|
|
|
|
#pod |
|
301
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will pass with all of the given C<@values>, including |
|
302
|
|
|
|
|
|
|
#pod values that might need coercions. If it initially passes, that's okay, too. If the type does not |
|
303
|
|
|
|
|
|
|
#pod have a coercion and it fails the initial check, it will stop there and fail the test. |
|
304
|
|
|
|
|
|
|
#pod |
|
305
|
|
|
|
|
|
|
#pod This function is included for completeness. However, L is the better function |
|
306
|
|
|
|
|
|
|
#pod for types with known coercions, as it checks the resulting coerced values as well. |
|
307
|
|
|
|
|
|
|
#pod |
|
308
|
|
|
|
|
|
|
#pod =cut |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
sub should_pass { |
|
311
|
8
|
|
|
8
|
1
|
133
|
my $ctx = context(); |
|
312
|
8
|
|
|
|
|
938
|
my $pass = run_subtest( |
|
313
|
|
|
|
|
|
|
'should pass', |
|
314
|
|
|
|
|
|
|
\&_should_pass_subtest, |
|
315
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
316
|
|
|
|
|
|
|
@_, |
|
317
|
|
|
|
|
|
|
); |
|
318
|
8
|
|
|
|
|
16268
|
$ctx->release; |
|
319
|
|
|
|
|
|
|
|
|
320
|
8
|
|
|
|
|
239
|
return $pass; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub _should_pass_subtest { |
|
324
|
8
|
|
|
8
|
|
3103
|
my ($type, @values) = @_; |
|
325
|
|
|
|
|
|
|
|
|
326
|
8
|
|
|
|
|
52
|
plan scalar @values; |
|
327
|
|
|
|
|
|
|
|
|
328
|
8
|
|
|
|
|
2726
|
foreach my $value (@values) { |
|
329
|
40
|
|
|
|
|
3856
|
my $val_dd = _dd($value); |
|
330
|
40
|
|
|
|
|
103
|
my @val_explain = _constraint_type_check_debug_map($type, $value); |
|
331
|
40
|
|
|
|
|
145
|
_check_error_message_methods($type, $value); |
|
332
|
|
|
|
|
|
|
|
|
333
|
40
|
100
|
|
|
|
11938
|
if ($type->check($value)) { |
|
|
|
100
|
|
|
|
|
|
|
334
|
18
|
|
|
|
|
362
|
pass "$val_dd should pass (initial check)", @val_explain; |
|
335
|
18
|
|
|
|
|
4229
|
next; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
elsif (!$type->has_coercion) { |
|
338
|
6
|
|
|
|
|
355
|
fail "$val_dd should pass (no coercion)", @val_explain; |
|
339
|
6
|
|
|
|
|
20853
|
next; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# try to coerce then |
|
343
|
16
|
|
|
|
|
418
|
my @coercion_debug = _coercion_type_check_debug_map($type, $value); |
|
344
|
16
|
|
|
|
|
54
|
my $new_value = $type->coerce($value); |
|
345
|
16
|
|
|
|
|
5154
|
my $new_dd = _dd($new_value); |
|
346
|
16
|
50
|
|
|
|
45
|
unless (_check_coercion($value, $new_value)) { |
|
347
|
0
|
|
|
|
|
0
|
fail "$val_dd should pass (failed coercion)", @val_explain, @coercion_debug; |
|
348
|
0
|
|
|
|
|
0
|
next; |
|
349
|
|
|
|
|
|
|
} |
|
350
|
16
|
|
|
|
|
41
|
_check_error_message_methods($type, $new_value); |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# final check |
|
353
|
16
|
|
|
|
|
196
|
@val_explain = _constraint_type_check_debug_map($type, $new_value); |
|
354
|
16
|
|
|
|
|
45
|
ok $type->check($new_value), "$val_dd should pass (coerced into $new_dd)", @val_explain, @coercion_debug; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
#pod =head3 should_fail |
|
359
|
|
|
|
|
|
|
#pod |
|
360
|
|
|
|
|
|
|
#pod should_fail($type, @values); |
|
361
|
|
|
|
|
|
|
#pod |
|
362
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will fail with all of the given C<@values>, even when |
|
363
|
|
|
|
|
|
|
#pod those values are ran through its coercions. |
|
364
|
|
|
|
|
|
|
#pod |
|
365
|
|
|
|
|
|
|
#pod =cut |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub should_fail { |
|
368
|
8
|
|
|
8
|
1
|
108
|
my $ctx = context(); |
|
369
|
8
|
|
|
|
|
906
|
my $pass = run_subtest( |
|
370
|
|
|
|
|
|
|
'should fail', |
|
371
|
|
|
|
|
|
|
\&_should_fail_subtest, |
|
372
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
373
|
|
|
|
|
|
|
@_, |
|
374
|
|
|
|
|
|
|
); |
|
375
|
8
|
|
|
|
|
15480
|
$ctx->release; |
|
376
|
|
|
|
|
|
|
|
|
377
|
8
|
|
|
|
|
245
|
return $pass; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub _should_fail_subtest { |
|
381
|
8
|
|
|
8
|
|
2828
|
my ($type, @values) = @_; |
|
382
|
|
|
|
|
|
|
|
|
383
|
8
|
|
|
|
|
74
|
plan scalar @values; |
|
384
|
|
|
|
|
|
|
|
|
385
|
8
|
|
|
|
|
2550
|
foreach my $value (@values) { |
|
386
|
36
|
|
|
|
|
1706
|
my $val_dd = _dd($value); |
|
387
|
36
|
|
|
|
|
101
|
my @val_explain = _constraint_type_check_debug_map($type, $value); |
|
388
|
36
|
|
|
|
|
99
|
_check_error_message_methods($type, $value); |
|
389
|
|
|
|
|
|
|
|
|
390
|
36
|
100
|
|
|
|
17680
|
if ($type->check($value)) { |
|
|
|
100
|
|
|
|
|
|
|
391
|
6
|
|
|
|
|
192
|
fail "$val_dd should fail (initial check)", @val_explain; |
|
392
|
6
|
|
|
|
|
19769
|
next; |
|
393
|
|
|
|
|
|
|
} |
|
394
|
|
|
|
|
|
|
elsif (!$type->has_coercion) { |
|
395
|
12
|
|
|
|
|
714
|
pass "$val_dd should fail (no coercion)", @val_explain; |
|
396
|
12
|
|
|
|
|
3367
|
next; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# try to coerce then |
|
400
|
18
|
|
|
|
|
334
|
my @coercion_debug = _coercion_type_check_debug_map($type, $value); |
|
401
|
18
|
|
|
|
|
42
|
my $new_value = $type->coerce($value); |
|
402
|
18
|
|
|
|
|
1385
|
my $new_dd = _dd($new_value); |
|
403
|
18
|
100
|
|
|
|
37
|
unless (_check_coercion($value, $new_value)) { |
|
404
|
8
|
|
|
|
|
40
|
pass "$val_dd should fail (failed coercion)", @val_explain, @coercion_debug; |
|
405
|
8
|
|
|
|
|
1583
|
next; |
|
406
|
|
|
|
|
|
|
} |
|
407
|
10
|
|
|
|
|
27
|
_check_error_message_methods($type, $new_value); |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# final check |
|
410
|
10
|
|
|
|
|
190
|
@val_explain = _constraint_type_check_debug_map($type, $new_value); |
|
411
|
10
|
|
|
|
|
23
|
ok !$type->check($new_value), "$val_dd should fail (coerced into $new_dd)", @val_explain, @coercion_debug; |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
#pod =head3 should_coerce_into |
|
416
|
|
|
|
|
|
|
#pod |
|
417
|
|
|
|
|
|
|
#pod should_coerce_into($type, @orig_coerced_kv_pairs); |
|
418
|
|
|
|
|
|
|
#pod should_coerce_into($type, |
|
419
|
|
|
|
|
|
|
#pod # orig # coerced |
|
420
|
|
|
|
|
|
|
#pod undef, 0, |
|
421
|
|
|
|
|
|
|
#pod [], 0, |
|
422
|
|
|
|
|
|
|
#pod ); |
|
423
|
|
|
|
|
|
|
#pod |
|
424
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will take the "key" in C<@orig_coerced_kv_pairs> and |
|
425
|
|
|
|
|
|
|
#pod coerce it into the "value" in C<@orig_coerced_kv_pairs>. (The C<@orig_coerced_kv_pairs> parameter |
|
426
|
|
|
|
|
|
|
#pod is essentially an ordered hash here, with support for ref values as the "key".) |
|
427
|
|
|
|
|
|
|
#pod |
|
428
|
|
|
|
|
|
|
#pod The original value should not pass initial checks, as it would not be coerced in most use cases. |
|
429
|
|
|
|
|
|
|
#pod These would be considered test failures. |
|
430
|
|
|
|
|
|
|
#pod |
|
431
|
|
|
|
|
|
|
#pod =cut |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub should_coerce_into { |
|
434
|
4
|
|
|
4
|
1
|
626
|
my $ctx = context(); |
|
435
|
4
|
|
|
|
|
411
|
my $pass = run_subtest( |
|
436
|
|
|
|
|
|
|
'should coerce into', |
|
437
|
|
|
|
|
|
|
\&_should_coerce_into_subtest, |
|
438
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
439
|
|
|
|
|
|
|
@_, |
|
440
|
|
|
|
|
|
|
); |
|
441
|
4
|
|
|
|
|
11962
|
$ctx->release; |
|
442
|
|
|
|
|
|
|
|
|
443
|
4
|
|
|
|
|
127
|
return $pass; |
|
444
|
|
|
|
|
|
|
} |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub _should_coerce_into_subtest { |
|
447
|
4
|
|
|
4
|
|
1304
|
my ($type, @kv_pairs) = @_; |
|
448
|
|
|
|
|
|
|
|
|
449
|
4
|
|
|
|
|
31
|
plan int( scalar(@kv_pairs) / 2 ); |
|
450
|
|
|
|
|
|
|
|
|
451
|
4
|
|
|
|
|
1303
|
foreach my $kv (pairs @kv_pairs) { |
|
452
|
25
|
|
|
|
|
16450
|
my ($value, $expected) = @$kv; |
|
453
|
|
|
|
|
|
|
|
|
454
|
25
|
|
|
|
|
75
|
my $val_dd = _dd($value); |
|
455
|
25
|
|
|
|
|
68
|
my @val_explain = _constraint_type_check_debug_map($type, $value); |
|
456
|
25
|
|
|
|
|
73
|
_check_error_message_methods($type, $value); |
|
457
|
|
|
|
|
|
|
|
|
458
|
25
|
50
|
|
|
|
1318
|
if ($type->check($value)) { |
|
|
|
50
|
|
|
|
|
|
|
459
|
0
|
|
|
|
|
0
|
fail "$val_dd should fail (initial check)"; |
|
460
|
0
|
|
|
|
|
0
|
next; |
|
461
|
|
|
|
|
|
|
} |
|
462
|
|
|
|
|
|
|
elsif (!$type->has_coercion) { |
|
463
|
0
|
|
|
|
|
0
|
fail "$val_dd should coerce (no coercion)"; |
|
464
|
0
|
|
|
|
|
0
|
next; |
|
465
|
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# try to coerce then |
|
468
|
25
|
|
|
|
|
621
|
my @coercion_debug = _coercion_type_check_debug_map($type, $value); |
|
469
|
25
|
|
|
|
|
106
|
my $new_value = $type->coerce($value); |
|
470
|
25
|
|
|
|
|
2890
|
my $new_dd = _dd($new_value); |
|
471
|
25
|
100
|
|
|
|
64
|
unless (_check_coercion($value, $new_value)) { |
|
472
|
3
|
|
|
|
|
27
|
fail "$val_dd should coerce", @val_explain, @coercion_debug; |
|
473
|
3
|
|
|
|
|
15349
|
next; |
|
474
|
|
|
|
|
|
|
} |
|
475
|
22
|
|
|
|
|
49
|
_check_error_message_methods($type, $new_value); |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# make sure it matches the expected value |
|
478
|
22
|
|
|
|
|
278
|
@val_explain = _constraint_type_check_debug_map($type, $new_value); |
|
479
|
22
|
|
|
|
|
122
|
is $new_value, $expected, "$val_dd (coerced)", @val_explain, @coercion_debug; |
|
480
|
|
|
|
|
|
|
} |
|
481
|
|
|
|
|
|
|
} |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
#pod =head2 Parameter Testers |
|
484
|
|
|
|
|
|
|
#pod |
|
485
|
|
|
|
|
|
|
#pod These tests should only be used for parameter validation. None of the resulting types are checked |
|
486
|
|
|
|
|
|
|
#pod in other ways, so you should include other L with different kinds of |
|
487
|
|
|
|
|
|
|
#pod parameterized types. |
|
488
|
|
|
|
|
|
|
#pod |
|
489
|
|
|
|
|
|
|
#pod Note that L don't require any sort of validation |
|
490
|
|
|
|
|
|
|
#pod because the L is always called first, and |
|
491
|
|
|
|
|
|
|
#pod should die on parameter validation failure, prior to the C call. The same applies |
|
492
|
|
|
|
|
|
|
#pod for coercion generators as well. |
|
493
|
|
|
|
|
|
|
#pod |
|
494
|
|
|
|
|
|
|
#pod =head3 parameters_should_create_type |
|
495
|
|
|
|
|
|
|
#pod |
|
496
|
|
|
|
|
|
|
#pod parameters_should_create_type($type, @parameter_sets); |
|
497
|
|
|
|
|
|
|
#pod parameters_should_create_type($type, |
|
498
|
|
|
|
|
|
|
#pod [], |
|
499
|
|
|
|
|
|
|
#pod [3], |
|
500
|
|
|
|
|
|
|
#pod [0, 0], |
|
501
|
|
|
|
|
|
|
#pod [1, 2], |
|
502
|
|
|
|
|
|
|
#pod ); |
|
503
|
|
|
|
|
|
|
#pod |
|
504
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will successfully create a parameterized type with each of |
|
505
|
|
|
|
|
|
|
#pod the set of parameters in C<@parameter_sets> (a list of arrayrefs). |
|
506
|
|
|
|
|
|
|
#pod |
|
507
|
|
|
|
|
|
|
#pod =cut |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
sub parameters_should_create_type { |
|
510
|
4
|
|
|
4
|
1
|
726
|
my $type = shift; |
|
511
|
4
|
50
|
|
|
|
17
|
die $type->display_name." is not a parameterized type" unless $type->is_parameterizable; |
|
512
|
|
|
|
|
|
|
|
|
513
|
4
|
|
|
|
|
37
|
my $ctx = context(); |
|
514
|
4
|
|
|
|
|
298
|
my $pass = run_subtest( |
|
515
|
|
|
|
|
|
|
'parameters should create type', |
|
516
|
|
|
|
|
|
|
\&_parameters_should_create_type_subtest, |
|
517
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
518
|
|
|
|
|
|
|
$type, @_, |
|
519
|
|
|
|
|
|
|
); |
|
520
|
4
|
|
|
|
|
7335
|
$ctx->release; |
|
521
|
|
|
|
|
|
|
|
|
522
|
4
|
|
|
|
|
120
|
return $pass; |
|
523
|
|
|
|
|
|
|
} |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub _parameters_should_create_type_subtest { |
|
526
|
4
|
|
|
4
|
|
911
|
my ($type, @parameter_sets) = @_; |
|
527
|
|
|
|
|
|
|
|
|
528
|
4
|
|
|
|
|
19
|
plan scalar(@parameter_sets); |
|
529
|
|
|
|
|
|
|
|
|
530
|
4
|
|
|
|
|
987
|
foreach my $parameter_set (@parameter_sets) { |
|
531
|
48
|
|
|
|
|
7270
|
my $val_dd = _dd($parameter_set); |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
# NOTE: lives is a separate statement, so that $@ is populated after failure |
|
534
|
48
|
|
|
|
|
73
|
my $new_type; |
|
535
|
48
|
|
|
48
|
|
311
|
my $ok = lives { $new_type = $type->of(@$parameter_set) }; |
|
|
48
|
|
|
|
|
857
|
|
|
536
|
48
|
|
|
|
|
30169
|
ok($ok, $val_dd, "Reported exception: $@"); |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# XXX: no idea what it takes in, so just pass in a few values |
|
539
|
48
|
50
|
|
|
|
11373
|
next unless $new_type; |
|
540
|
48
|
|
|
|
|
379
|
_check_error_message_methods($new_type, $_) for (1, 0, -1, undef, \"", {}, []); |
|
541
|
|
|
|
|
|
|
} |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
#pod =head3 parameters_should_die_as |
|
545
|
|
|
|
|
|
|
#pod |
|
546
|
|
|
|
|
|
|
#pod parameters_should_die_as($type, @parameter_sets_exception_regex_pairs); |
|
547
|
|
|
|
|
|
|
#pod parameters_should_die_as($type, |
|
548
|
|
|
|
|
|
|
#pod # params # exceptions |
|
549
|
|
|
|
|
|
|
#pod [], qr, |
|
550
|
|
|
|
|
|
|
#pod [-3], qr, |
|
551
|
|
|
|
|
|
|
#pod [0.2], qr, |
|
552
|
|
|
|
|
|
|
#pod ); |
|
553
|
|
|
|
|
|
|
#pod |
|
554
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will fail validation (fatally) with the given parameters |
|
555
|
|
|
|
|
|
|
#pod and exceptions. The RHS should be an regular expression, but can be anything that |
|
556
|
|
|
|
|
|
|
#pod L accepts. |
|
557
|
|
|
|
|
|
|
#pod |
|
558
|
|
|
|
|
|
|
#pod =cut |
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
sub parameters_should_die_as { |
|
561
|
4
|
|
|
4
|
1
|
102
|
my $type = shift; |
|
562
|
4
|
50
|
|
|
|
19
|
die $type->display_name." is not a parameterized type" unless $type->is_parameterizable; |
|
563
|
|
|
|
|
|
|
|
|
564
|
4
|
|
|
|
|
43
|
my $ctx = context(); |
|
565
|
4
|
|
|
|
|
470
|
my $pass = run_subtest( |
|
566
|
|
|
|
|
|
|
'parameters should die as', |
|
567
|
|
|
|
|
|
|
\&_parameters_should_die_as_subtest, |
|
568
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
569
|
|
|
|
|
|
|
$type, @_, |
|
570
|
|
|
|
|
|
|
); |
|
571
|
4
|
|
|
|
|
5475
|
$ctx->release; |
|
572
|
|
|
|
|
|
|
|
|
573
|
4
|
|
|
|
|
118
|
return $pass; |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
sub _parameters_should_die_as_subtest { |
|
577
|
4
|
|
|
4
|
|
1445
|
my ($type, @pairs) = @_; |
|
578
|
|
|
|
|
|
|
|
|
579
|
4
|
|
|
|
|
35
|
plan int( scalar(@pairs) / 2 ); |
|
580
|
|
|
|
|
|
|
|
|
581
|
4
|
|
|
|
|
1302
|
foreach my $pair (pairs @pairs) { |
|
582
|
8
|
|
|
|
|
3241
|
my ($parameter_set, $expected) = @$pair; |
|
583
|
8
|
|
|
|
|
23
|
my $val_dd = _dd($parameter_set); |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
like( |
|
586
|
8
|
|
|
8
|
|
120
|
dies { $type->of(@$parameter_set) }, |
|
587
|
8
|
|
|
|
|
56
|
$expected, |
|
588
|
|
|
|
|
|
|
$val_dd, |
|
589
|
|
|
|
|
|
|
); |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
#pod =head2 Error Message Testers |
|
594
|
|
|
|
|
|
|
#pod |
|
595
|
|
|
|
|
|
|
#pod =head3 message_should_report_as |
|
596
|
|
|
|
|
|
|
#pod |
|
597
|
|
|
|
|
|
|
#pod message_should_report_as($type, @value_message_regex_pairs); |
|
598
|
|
|
|
|
|
|
#pod message_should_report_as($type, |
|
599
|
|
|
|
|
|
|
#pod # values # messages |
|
600
|
|
|
|
|
|
|
#pod 1, qr, |
|
601
|
|
|
|
|
|
|
#pod undef, qr!Must be a fully-qualified domain name, not !, |
|
602
|
|
|
|
|
|
|
#pod # valid value; checking message, anyway |
|
603
|
|
|
|
|
|
|
#pod 'example.com', qr, |
|
604
|
|
|
|
|
|
|
#pod ); |
|
605
|
|
|
|
|
|
|
#pod |
|
606
|
|
|
|
|
|
|
#pod Creates a subtest that confirms error message output against the value. Technically, |
|
607
|
|
|
|
|
|
|
#pod L works for valid values, too, so this isn't actually trapping assertion |
|
608
|
|
|
|
|
|
|
#pod failures, just checking the output of that method. |
|
609
|
|
|
|
|
|
|
#pod |
|
610
|
|
|
|
|
|
|
#pod The RHS should be an regular expression, but it can be anything that L |
|
611
|
|
|
|
|
|
|
#pod accepts. |
|
612
|
|
|
|
|
|
|
#pod |
|
613
|
|
|
|
|
|
|
#pod =cut |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
sub message_should_report_as { |
|
616
|
4
|
|
|
4
|
1
|
70
|
my $ctx = context(); |
|
617
|
4
|
|
|
|
|
396
|
my $pass = run_subtest( |
|
618
|
|
|
|
|
|
|
'message should report as', |
|
619
|
|
|
|
|
|
|
\&_message_should_report_as_subtest, |
|
620
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
621
|
|
|
|
|
|
|
@_, |
|
622
|
|
|
|
|
|
|
); |
|
623
|
4
|
|
|
|
|
3862
|
$ctx->release; |
|
624
|
|
|
|
|
|
|
|
|
625
|
4
|
|
|
|
|
110
|
return $pass; |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub _message_should_report_as_subtest { |
|
629
|
4
|
|
|
4
|
|
1269
|
my ($type, @pairs) = @_; |
|
630
|
|
|
|
|
|
|
|
|
631
|
4
|
|
|
|
|
26
|
plan int( scalar(@pairs) / 2 ); |
|
632
|
|
|
|
|
|
|
|
|
633
|
4
|
|
|
|
|
1351
|
foreach my $pair (pairs @pairs) { |
|
634
|
4
|
|
|
|
|
12
|
my ($value, $message_check) = @$pair; |
|
635
|
4
|
|
|
|
|
13
|
my $val_dd = _dd($value); |
|
636
|
|
|
|
|
|
|
|
|
637
|
4
|
|
|
|
|
21
|
my $message_got = $type->get_message($value); |
|
638
|
|
|
|
|
|
|
|
|
639
|
4
|
|
|
|
|
122
|
like $message_got, $message_check, $val_dd; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
#pod =head3 explanation_should_report_as |
|
644
|
|
|
|
|
|
|
#pod |
|
645
|
|
|
|
|
|
|
#pod explanation_should_report_as($type, @value_explanation_check_pairs); |
|
646
|
|
|
|
|
|
|
#pod explanation_should_report_as($type, |
|
647
|
|
|
|
|
|
|
#pod # values # explanation check |
|
648
|
|
|
|
|
|
|
#pod 'example.com', [ |
|
649
|
|
|
|
|
|
|
#pod qr< did not pass type constraint >, |
|
650
|
|
|
|
|
|
|
#pod qr< expects domain label count \(\?LD\) to be between 3 and 5>, |
|
651
|
|
|
|
|
|
|
#pod qr<\$_ appears to be a 2LD>, |
|
652
|
|
|
|
|
|
|
#pod ], |
|
653
|
|
|
|
|
|
|
#pod undef, [ |
|
654
|
|
|
|
|
|
|
#pod qr< did not pass type constraint >, |
|
655
|
|
|
|
|
|
|
#pod qr<\$_ is not a legal FQDN>, |
|
656
|
|
|
|
|
|
|
#pod ], |
|
657
|
|
|
|
|
|
|
#pod ); |
|
658
|
|
|
|
|
|
|
#pod |
|
659
|
|
|
|
|
|
|
#pod Creates a subtest that confirms deeper explanation message output from L |
|
660
|
|
|
|
|
|
|
#pod against the value. Unlike C, C actually needs failed values to |
|
661
|
|
|
|
|
|
|
#pod report back a string message. The second parameter to C is not passed, so expect |
|
662
|
|
|
|
|
|
|
#pod error messages that inspect C<$_>. |
|
663
|
|
|
|
|
|
|
#pod |
|
664
|
|
|
|
|
|
|
#pod The RHS should be an arrayref of regular expressions, since C reports back an |
|
665
|
|
|
|
|
|
|
#pod arrayref of strings. Although, it can be anything that L accepts, and |
|
666
|
|
|
|
|
|
|
#pod since it's a looser check, gaps in the arrayref are allowed. |
|
667
|
|
|
|
|
|
|
#pod |
|
668
|
|
|
|
|
|
|
#pod =cut |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
sub explanation_should_report_as { |
|
671
|
4
|
|
|
4
|
1
|
68
|
my $ctx = context(); |
|
672
|
4
|
|
|
|
|
371
|
my $pass = run_subtest( |
|
673
|
|
|
|
|
|
|
'explanation should report as', |
|
674
|
|
|
|
|
|
|
\&_explanation_should_report_as_subtest, |
|
675
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
676
|
|
|
|
|
|
|
@_, |
|
677
|
|
|
|
|
|
|
); |
|
678
|
4
|
|
|
|
|
5655
|
$ctx->release; |
|
679
|
|
|
|
|
|
|
|
|
680
|
4
|
|
|
|
|
112
|
return $pass; |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub _explanation_should_report_as_subtest { |
|
684
|
4
|
|
|
4
|
|
1065
|
my ($type, @pairs) = @_; |
|
685
|
|
|
|
|
|
|
|
|
686
|
4
|
|
|
|
|
36
|
plan int( scalar(@pairs) / 2 ); |
|
687
|
|
|
|
|
|
|
|
|
688
|
4
|
|
|
|
|
1166
|
foreach my $pair (pairs @pairs) { |
|
689
|
4
|
|
|
|
|
13
|
my ($value, $explanation_check) = @$pair; |
|
690
|
4
|
|
|
|
|
14
|
my $val_dd = _dd($value); |
|
691
|
|
|
|
|
|
|
|
|
692
|
4
|
|
|
|
|
21
|
my $explanation_got = $type->validate_explain($value); |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
my @explanation_explain = |
|
695
|
4
|
50
|
|
|
|
801
|
defined $explanation_got ? ( "Resulting Explanation:", map { " $_" } @$explanation_got ) : |
|
|
12
|
|
|
|
|
32
|
|
|
696
|
|
|
|
|
|
|
() |
|
697
|
|
|
|
|
|
|
; |
|
698
|
4
|
|
|
|
|
19
|
like $explanation_got, $explanation_check, $val_dd, @explanation_explain; |
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
} |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
#pod =head2 Other Testers |
|
703
|
|
|
|
|
|
|
#pod |
|
704
|
|
|
|
|
|
|
#pod =head3 should_sort_into |
|
705
|
|
|
|
|
|
|
#pod |
|
706
|
|
|
|
|
|
|
#pod should_sort_into($type, @sorted_arrayrefs); |
|
707
|
|
|
|
|
|
|
#pod |
|
708
|
|
|
|
|
|
|
#pod Creates a subtest that confirms the type will sort into the expected lists given. The input list |
|
709
|
|
|
|
|
|
|
#pod is a shuffled version of the sorted list. |
|
710
|
|
|
|
|
|
|
#pod |
|
711
|
|
|
|
|
|
|
#pod Because this introduces some non-deterministic behavior to the test, it will run through 100 cycles |
|
712
|
|
|
|
|
|
|
#pod of shuffling and sorting to confirm the results. A good sorter should always return a |
|
713
|
|
|
|
|
|
|
#pod deterministic result for a given list, with enough fallbacks to account for every unique case. |
|
714
|
|
|
|
|
|
|
#pod Any failure will immediate stop the loop and return both the shuffled input and output list in the |
|
715
|
|
|
|
|
|
|
#pod failure output, so that you can temporarily test in a more deterministic manner, as you debug the |
|
716
|
|
|
|
|
|
|
#pod fault. |
|
717
|
|
|
|
|
|
|
#pod |
|
718
|
|
|
|
|
|
|
#pod =cut |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub should_sort_into { |
|
721
|
4
|
|
|
4
|
1
|
72
|
my $ctx = context(); |
|
722
|
4
|
|
|
|
|
439
|
my $pass = run_subtest( |
|
723
|
|
|
|
|
|
|
'should sort into', |
|
724
|
|
|
|
|
|
|
\&_should_sort_into_subtest, |
|
725
|
|
|
|
|
|
|
{ buffered => 1, inherit_trace => 1 }, |
|
726
|
|
|
|
|
|
|
@_, |
|
727
|
|
|
|
|
|
|
); |
|
728
|
4
|
|
|
|
|
8027
|
$ctx->release; |
|
729
|
|
|
|
|
|
|
|
|
730
|
4
|
|
|
|
|
118
|
return $pass; |
|
731
|
|
|
|
|
|
|
} |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub _should_sort_into_subtest { |
|
734
|
4
|
|
|
4
|
|
1465
|
my ($type, @sorted_lists) = @_; |
|
735
|
|
|
|
|
|
|
|
|
736
|
4
|
|
|
|
|
68
|
plan scalar(@sorted_lists); |
|
737
|
|
|
|
|
|
|
|
|
738
|
4
|
|
|
|
|
1279
|
foreach my $sorted_list (@sorted_lists) { |
|
739
|
4
|
|
|
|
|
48
|
my @expected_sort = @$sorted_list; |
|
740
|
|
|
|
|
|
|
|
|
741
|
4
|
|
|
|
|
15
|
my $val_dd = _dd(\@expected_sort); |
|
742
|
|
|
|
|
|
|
|
|
743
|
4
|
|
|
|
|
12
|
my (@shuffled, @sorted); |
|
744
|
4
|
|
|
|
|
16
|
foreach my $i (1..100) { |
|
745
|
400
|
|
|
|
|
2643
|
@shuffled = shuffle @expected_sort; |
|
746
|
400
|
|
|
|
|
2448
|
@sorted = $type->sort(@shuffled); |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
# To hide all of these iterations, we'll compare with 'compare' first, and if it's a failure, |
|
749
|
|
|
|
|
|
|
# we'll use 'is' to advertise the failure. |
|
750
|
400
|
|
|
|
|
69953
|
my $delta = compare(\@sorted, \@expected_sort, \&strict_convert); |
|
751
|
400
|
50
|
|
|
|
316860
|
last if $delta; # let 'is' fail |
|
752
|
|
|
|
|
|
|
} |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# pass or fail |
|
755
|
4
|
|
|
|
|
24
|
my @io_explain = ( |
|
756
|
|
|
|
|
|
|
"Shuffled Input: "._dd(\@shuffled), |
|
757
|
|
|
|
|
|
|
"Resulting Output: "._dd(\@sorted), |
|
758
|
|
|
|
|
|
|
); |
|
759
|
4
|
|
|
|
|
37
|
is \@sorted, \@expected_sort, $val_dd, @io_explain; |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
} |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
# Helpers |
|
764
|
|
|
|
|
|
|
sub _dd { |
|
765
|
596
|
|
|
596
|
|
41685
|
my $dd = Data::Dumper->new([ shift ])->Terse(1)->Indent(0)->Useqq(1)->Deparse(1)->Quotekeys(0)->Sortkeys(1)->Maxdepth(2); |
|
766
|
596
|
|
|
|
|
30400
|
my $val = $dd->Dump; |
|
767
|
596
|
|
|
|
|
12342
|
$val =~ s/\s+/ /gs; |
|
768
|
596
|
|
|
|
|
3471
|
return $val; |
|
769
|
|
|
|
|
|
|
}; |
|
770
|
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
sub _constraint_type_check_debug_map { |
|
772
|
199
|
|
|
199
|
|
442
|
my ($type, $value) = @_; |
|
773
|
|
|
|
|
|
|
|
|
774
|
199
|
|
|
|
|
353
|
my $dd = _dd($value); |
|
775
|
|
|
|
|
|
|
|
|
776
|
199
|
|
|
|
|
738
|
my @diag_map = ($type->display_name." constraint map:"); |
|
777
|
199
|
50
|
|
|
|
1339
|
if (length $dd > 30) { |
|
778
|
0
|
|
|
|
|
0
|
push @diag_map, " Full value: $dd"; |
|
779
|
0
|
|
|
|
|
0
|
$dd = '...'; |
|
780
|
|
|
|
|
|
|
} |
|
781
|
|
|
|
|
|
|
|
|
782
|
199
|
|
|
|
|
295
|
my $current_check = $type; |
|
783
|
199
|
|
|
|
|
674
|
while ($current_check) { |
|
784
|
1254
|
|
|
|
|
11653
|
my $type_name = $current_check->display_name; |
|
785
|
1254
|
|
|
|
|
5064
|
my $check = $current_check->check($value); |
|
786
|
|
|
|
|
|
|
|
|
787
|
1254
|
100
|
|
|
|
10590
|
my $check_label = $check ? 'PASSED' : 'FAILED'; |
|
788
|
1254
|
|
|
|
|
6704
|
push @diag_map, sprintf('%*s%s->check(%s) ==> %s', $DEBUG_INDENT, '', $type_name, $dd, $check_label); |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# Advertize failure message and deeper explanations |
|
791
|
1254
|
100
|
|
|
|
2219
|
unless ($check) { |
|
792
|
170
|
|
|
|
|
464
|
push @diag_map, sprintf('%*s%s: %s', $DEBUG_INDENT * 2, '', 'message', $current_check->get_message($value)); |
|
793
|
|
|
|
|
|
|
|
|
794
|
170
|
50
|
66
|
|
|
4652
|
if ($current_check->is_parameterized && $current_check->parent->has_deep_explanation) { |
|
795
|
0
|
|
|
|
|
0
|
push @diag_map, sprintf('%*s%s:', $DEBUG_INDENT * 2, '', 'parameterized deep explanation (from parent)'); |
|
796
|
0
|
|
|
|
|
0
|
my $deep = eval { $current_check->parent->deep_explanation->( $current_check, $value, '$_' ) }; |
|
|
0
|
|
|
|
|
0
|
|
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
# Account for bugs in parent->deep_explanation |
|
799
|
|
|
|
|
|
|
push @diag_map, ( |
|
800
|
|
|
|
|
|
|
$@ ? sprintf('%*s%s: %s', $DEBUG_INDENT * 3, '', 'EVAL ERROR', $@) : |
|
801
|
|
|
|
|
|
|
!defined $deep ? sprintf('%*s%s', $DEBUG_INDENT * 3, '', 'NO RESULTS') : |
|
802
|
|
|
|
|
|
|
ref $deep ne 'ARRAY' ? sprintf('%*s%s: %s', $DEBUG_INDENT * 3, '', 'ILLEGAL RETURN TYPE', ref $deep) : |
|
803
|
0
|
0
|
|
|
|
0
|
(map { sprintf('%*s%s', $DEBUG_INDENT * 3, '', $_) } @$deep) |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
); |
|
805
|
|
|
|
|
|
|
} |
|
806
|
|
|
|
|
|
|
} |
|
807
|
|
|
|
|
|
|
|
|
808
|
1254
|
|
|
0
|
|
6110
|
local $SIG{__WARN__} = sub {}; |
|
809
|
1254
|
|
|
|
|
2798
|
push @diag_map, sprintf('%*s%s: %s', $DEBUG_INDENT * 2, '', 'is defined as', $current_check->_perlcode); |
|
810
|
|
|
|
|
|
|
|
|
811
|
1254
|
|
|
|
|
154326
|
$current_check = $current_check->parent; |
|
812
|
|
|
|
|
|
|
}; |
|
813
|
|
|
|
|
|
|
|
|
814
|
199
|
|
|
|
|
1795
|
return @diag_map; |
|
815
|
|
|
|
|
|
|
} |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
sub _coercion_type_check_debug_map { |
|
818
|
59
|
|
|
59
|
|
121
|
my ($type, $value) = @_; |
|
819
|
|
|
|
|
|
|
|
|
820
|
59
|
|
|
|
|
152
|
my $dd = _dd($value); |
|
821
|
|
|
|
|
|
|
|
|
822
|
59
|
|
|
|
|
163
|
my @diag_map = ($type->display_name." coercion map:"); |
|
823
|
59
|
50
|
|
|
|
321
|
if (length $dd > 30) { |
|
824
|
0
|
|
|
|
|
0
|
push @diag_map, sprintf('%*s%s: %s', $DEBUG_INDENT, '', 'Full value', $dd); |
|
825
|
0
|
|
|
|
|
0
|
$dd = '...'; |
|
826
|
|
|
|
|
|
|
} |
|
827
|
|
|
|
|
|
|
|
|
828
|
59
|
|
|
59
|
|
199
|
foreach my $coercion_type ($type, (pairmap { $a } @{$type->coercion->type_coercion_map}) ) { |
|
|
59
|
|
|
|
|
731
|
|
|
|
59
|
|
|
|
|
118
|
|
|
829
|
118
|
|
|
|
|
240
|
my $type_name = $coercion_type->display_name; |
|
830
|
118
|
|
|
|
|
425
|
my $check = $coercion_type->check($value); |
|
831
|
|
|
|
|
|
|
|
|
832
|
118
|
100
|
|
|
|
612
|
my $check_label = $check ? 'PASSED' : 'FAILED'; |
|
833
|
118
|
100
|
66
|
|
|
340
|
$check_label .= sprintf ' (coerced into %s)', _dd($type->coerce($value)) if $check && $coercion_type != $type; |
|
834
|
|
|
|
|
|
|
|
|
835
|
118
|
|
|
|
|
483
|
push @diag_map, sprintf('%*s%s->check(%s) ==> %s', $DEBUG_INDENT, '', $type_name, $dd, $check_label); |
|
836
|
118
|
100
|
|
|
|
304
|
last if $check; |
|
837
|
|
|
|
|
|
|
} |
|
838
|
|
|
|
|
|
|
|
|
839
|
59
|
|
|
|
|
357
|
return @diag_map; |
|
840
|
|
|
|
|
|
|
} |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
sub _check_coercion { |
|
843
|
59
|
|
|
59
|
|
122
|
my ($old_value, $new_value) = @_; |
|
844
|
59
|
|
100
|
|
|
149
|
$old_value //= ''; |
|
845
|
59
|
|
100
|
|
|
149
|
$new_value //= ''; |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
# compare memory addresses for refs instead |
|
848
|
59
|
100
|
50
|
|
|
245
|
($old_value, $new_value) = map { refaddr($_) // '' } ($old_value, $new_value) |
|
|
8
|
|
66
|
|
|
23
|
|
|
849
|
|
|
|
|
|
|
if ref $old_value || ref $new_value |
|
850
|
|
|
|
|
|
|
; |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# returns true if it was coerced |
|
853
|
59
|
|
|
|
|
153
|
return $old_value ne $new_value; |
|
854
|
|
|
|
|
|
|
} |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
sub _check_error_message_methods { |
|
857
|
535
|
|
|
535
|
|
133352
|
my ($type, $value) = @_; |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
# If it dies, we just let it naturally die |
|
860
|
535
|
|
|
|
|
1504
|
$type->get_message($value); |
|
861
|
535
|
|
|
|
|
19857
|
$type->validate_explain($value); # will return undef on good values |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
#pod =head1 TROUBLESHOOTING |
|
865
|
|
|
|
|
|
|
#pod |
|
866
|
|
|
|
|
|
|
#pod =head2 Test name output |
|
867
|
|
|
|
|
|
|
#pod |
|
868
|
|
|
|
|
|
|
#pod The test names within each C function are somewhat dynamic, depending on which stage of |
|
869
|
|
|
|
|
|
|
#pod the test it failed at. Most of the time, this is self-explanatory, but double negatives may make |
|
870
|
|
|
|
|
|
|
#pod the output a tad logic-twisting: |
|
871
|
|
|
|
|
|
|
#pod |
|
872
|
|
|
|
|
|
|
#pod not ok 1 - ... |
|
873
|
|
|
|
|
|
|
#pod |
|
874
|
|
|
|
|
|
|
#pod # should_*_initially |
|
875
|
|
|
|
|
|
|
#pod "val" should pass # simple should_pass_initially failure |
|
876
|
|
|
|
|
|
|
#pod "val" should fail # simple should_fail_initially failure |
|
877
|
|
|
|
|
|
|
#pod |
|
878
|
|
|
|
|
|
|
#pod # should_* |
|
879
|
|
|
|
|
|
|
#pod "val" should fail (initial check) # should_fail didn't initially fail |
|
880
|
|
|
|
|
|
|
#pod "val" should pass (no coercion) # should_pass initally failed, and didn't have a coercion to use |
|
881
|
|
|
|
|
|
|
#pod "val" should pass (failed coercion) # should_pass failed both the check and coercion |
|
882
|
|
|
|
|
|
|
#pod "val" should fail (coerced into "val2") # should_fail still successfully coerced into a good value |
|
883
|
|
|
|
|
|
|
#pod "val" should pass (coerced into "val2") # should_pass coerced into a bad value |
|
884
|
|
|
|
|
|
|
#pod |
|
885
|
|
|
|
|
|
|
#pod # should_coerce_into has similar errors as above |
|
886
|
|
|
|
|
|
|
#pod |
|
887
|
|
|
|
|
|
|
#pod =head3 Type Map Diagnostics |
|
888
|
|
|
|
|
|
|
#pod |
|
889
|
|
|
|
|
|
|
#pod Because types can be twisty mazes of inherited parents or multiple coercion maps, any failures will |
|
890
|
|
|
|
|
|
|
#pod produce a verbose set of diagnostics. These come in two flavors: constraint maps and coercion maps, |
|
891
|
|
|
|
|
|
|
#pod depending on where in the process the test failed. |
|
892
|
|
|
|
|
|
|
#pod |
|
893
|
|
|
|
|
|
|
#pod For example, a constraint map could look like: |
|
894
|
|
|
|
|
|
|
#pod |
|
895
|
|
|
|
|
|
|
#pod # (some definition output truncated) |
|
896
|
|
|
|
|
|
|
#pod |
|
897
|
|
|
|
|
|
|
#pod MyStringType constraint map: |
|
898
|
|
|
|
|
|
|
#pod MyStringType->check("value") ==> FAILED |
|
899
|
|
|
|
|
|
|
#pod message: Must be a good value |
|
900
|
|
|
|
|
|
|
#pod is defined as: do { package Type::Tiny; ... ) } |
|
901
|
|
|
|
|
|
|
#pod StrMatch["(?^ux:...)"]->check("value") ==> FAILED |
|
902
|
|
|
|
|
|
|
#pod message: StrMatch did not pass type constraint: ... |
|
903
|
|
|
|
|
|
|
#pod is defined as: do { package Type::Tiny; !ref($_) and !!( $_ =~ $Types::Standard::StrMatch::expressions{"..."} ) } |
|
904
|
|
|
|
|
|
|
#pod StrMatch->check("value") ==> PASSED |
|
905
|
|
|
|
|
|
|
#pod is defined as: do { package Type::Tiny; defined($_) and do { ref(\$_) eq 'SCALAR' or ref(\(my $val = $_)) eq 'SCALAR' } } |
|
906
|
|
|
|
|
|
|
#pod Str->check("value") ==> PASSED |
|
907
|
|
|
|
|
|
|
#pod is defined as: do { package Type::Tiny; defined($_) and do { ref(\$_) eq 'SCALAR' or ref(\(my $val = $_)) eq 'SCALAR' } } |
|
908
|
|
|
|
|
|
|
#pod Value->check("value") ==> PASSED |
|
909
|
|
|
|
|
|
|
#pod is defined as: (defined($_) and not ref($_)) |
|
910
|
|
|
|
|
|
|
#pod Defined->check("value") ==> PASSED |
|
911
|
|
|
|
|
|
|
#pod is defined as: (defined($_)) |
|
912
|
|
|
|
|
|
|
#pod Item->check("value") ==> PASSED |
|
913
|
|
|
|
|
|
|
#pod is defined as: (!!1) |
|
914
|
|
|
|
|
|
|
#pod Any->check("value") ==> PASSED |
|
915
|
|
|
|
|
|
|
#pod is defined as: (!!1) |
|
916
|
|
|
|
|
|
|
#pod |
|
917
|
|
|
|
|
|
|
#pod The diagnostics checked the final value with each individual parent check (including itself). |
|
918
|
|
|
|
|
|
|
#pod Based on this output, the value passed all of the lower-level C checks, because it is a string. |
|
919
|
|
|
|
|
|
|
#pod But, it failed the more-specific C regular expression. This will give you an idea of |
|
920
|
|
|
|
|
|
|
#pod which type to adjust, if necessary. |
|
921
|
|
|
|
|
|
|
#pod |
|
922
|
|
|
|
|
|
|
#pod A coercion map would look like this: |
|
923
|
|
|
|
|
|
|
#pod |
|
924
|
|
|
|
|
|
|
#pod MyStringType coercion map: |
|
925
|
|
|
|
|
|
|
#pod MyStringType->check("value") ==> FAILED |
|
926
|
|
|
|
|
|
|
#pod FQDN->check("value") ==> FAILED |
|
927
|
|
|
|
|
|
|
#pod Username->check("value") ==> FAILED |
|
928
|
|
|
|
|
|
|
#pod Hostname->check("value") ==> PASSED (coerced into "value2") |
|
929
|
|
|
|
|
|
|
#pod |
|
930
|
|
|
|
|
|
|
#pod The diagnostics looked at L's C (and the type itself), figured |
|
931
|
|
|
|
|
|
|
#pod out which types were acceptable for coercion, and returned the coercion result that passed. In |
|
932
|
|
|
|
|
|
|
#pod this case, none of the types passed except C, which was coerced into C. |
|
933
|
|
|
|
|
|
|
#pod |
|
934
|
|
|
|
|
|
|
#pod Based on this, either C converted it to the wrong value (one that did not pass |
|
935
|
|
|
|
|
|
|
#pod C), or one of the higher-level checks should have passed and didn't. |
|
936
|
|
|
|
|
|
|
#pod |
|
937
|
|
|
|
|
|
|
#pod =cut |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
1; |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
__END__ |