File Coverage

blib/lib/Test2/Tools/Expressive.pm
Criterion Covered Total %
statement 116 124 93.5
branch 38 42 90.4
condition n/a
subroutine 13 13 100.0
pod 7 7 100.0
total 174 186 93.5


line stmt bran cond sub pod time code
1             package Test2::Tools::Expressive;
2              
3 8     8   750304 use 5.008001;
  8         19  
4 8     8   27 use strict;
  8         10  
  8         114  
5 8     8   21 use warnings;
  8         11  
  8         282  
6              
7             =head1 NAME
8              
9             Test2::Tools::Expressive -- Expressive tools for Perl's Test2 framework
10              
11             =head1 VERSION
12              
13             Version 0.02
14              
15             =cut
16              
17             our $VERSION = '0.02';
18              
19 8     8   3136 use parent 'Exporter';
  8         1851  
  8         31  
20              
21             our @EXPORT_OK = qw(
22             is_undef
23              
24             is_blank
25             is_nonblank
26              
27             is_empty_array
28             is_nonempty_array
29              
30             is_empty_hash
31             is_nonempty_hash
32             );
33              
34             our @EXPORT = @EXPORT_OK;
35              
36 8     8   530 use Test2::API qw( context );
  8         12  
  8         276  
37 8     8   3142 use Test2::Tools::Explain;
  8         2013  
  8         5988  
38              
39             =head1 SYNOPSIS
40              
41             use Test2::Tools::Expressive;
42              
43             my $user = get_user_object( $bogus_id );
44             is_undef( $user, 'Should not be able to find a user with a bogus ID' );
45              
46             =head1 WHY TEST::EXPRESSIVE?
47              
48             Test2::Tools::Expressive is designed to make your code more readable,
49             based on the idea that reading English is easier and less prone to
50             misinterpretation than reading Perl, and less prone to error by reducing
51             common cut & paste tasks.
52              
53             The module's functions also provide diagnostics to make it easier to
54             see why your test failed. For example this test:
55              
56             my $errors = try_something();
57             is_empty_array( $errors, 'Did errors come back empty?' );
58              
59             Gives this:
60              
61             # Failed test 'Did errors come back empty?'
62             # at t/test.t line 37.
63             # Expected ARRAY reference but got HASH
64              
65             =head1 EXPORTS
66              
67             All functions in this module are exported by default.
68              
69             =head1 SUBROUTINES
70              
71             =head2 is_undef( $got [, $name ] )
72              
73             Verifies that C<$got> is undefined.
74              
75             You must pass at least one argument. Otherwise, calling C
76             with no parameters would pass.
77              
78             =cut
79              
80             sub is_undef {
81 15     15 1 111617 my $nargs = scalar @_;
82              
83 15         18 my $got = shift;
84 15         13 my $name = shift;
85              
86 15         12 my $ok;
87 15         22 my $ctx = context();
88              
89 15 100       721 if ( $nargs == 0 ) {
90 1         3 $ok = $ctx->ok( 0, $name );
91 1         108 $ctx->diag( 'Must pass a value to is_undef' );
92             }
93             else {
94 14         37 $ok = $ctx->ok( !defined $got, $name );
95             }
96              
97 15         1124 $ctx->release;
98              
99 15         201 return $ok;
100             }
101              
102              
103             =head2 is_blank( $got [, $name ] )
104              
105             Verifies that C<$got> is a defined scalar, is not a reference and is an
106             empty string. Note that the string must be empty, so an all-whitespace
107             string will fail.
108              
109             =cut
110              
111             sub is_blank {
112 6     6 1 102920 my $got = shift;
113 6         6 my $name = shift;
114              
115 6         4 my $ok;
116 6         11 my $ctx = context();
117              
118 6         264 my $ref = ref $got;
119 6 100       23 if ( $ref ne '' ) {
    100          
120 2         5 $ok = $ctx->ok( 0, $name );
121 2 100       173 my $article = ($ref =~ /^[AI]/) ? 'an' : 'a';
122 2         6 $ctx->diag( "Got $article $ref reference" );
123             }
124             elsif ( $got ne '' ) {
125 2         4 $ok = $ctx->ok( 0, $name );
126 2         196 $ctx->diag( 'Got a nonempty string' );
127             }
128             else {
129 2         4 $ok = $ctx->ok( 1, $name );
130             }
131              
132 6         209 $ctx->release;
133              
134 6         80 return $ok;
135             }
136              
137              
138             =head2 is_nonblank( $got [, $name ] )
139              
140             Verifies that C<$got> is a defined scalar, is not a reference and is
141             not an empty string.
142              
143             =cut
144              
145             sub is_nonblank {
146 6     6 1 100540 my $got = shift;
147 6         6 my $name = shift;
148              
149 6         4 my $ok;
150 6         9 my $ctx = context();
151              
152 6         263 my $ref = ref $got;
153 6 100       23 if ( $ref ne '' ) {
    100          
154 2         5 $ok = $ctx->ok( 0, $name );
155 2 100       174 my $article = ($ref =~ /^[AI]/) ? 'an' : 'a';
156 2         7 $ctx->diag( "Got $article $ref reference" );
157             }
158             elsif ( $got eq '' ) {
159 2         4 $ok = $ctx->ok( 0, $name );
160 2         195 $ctx->diag( 'Got an empty string' );
161             }
162             else {
163 2         5 $ok = $ctx->ok( 1, $name );
164             }
165              
166 6         212 $ctx->release;
167              
168 6         82 return $ok;
169             }
170              
171              
172             =head2 is_nonempty_array( $got [, $name ] )
173              
174             Verifies that C<$got> is an arrayref, and that the array contains at
175             least one element.
176              
177             =cut
178              
179             sub is_nonempty_array {
180 6     6 1 103571 my $got = shift;
181 6         7 my $name = shift;
182              
183 6         5 my $ok;
184 6         10 my $ctx = context();
185              
186 6         272 my $ref = ref $got;
187 6 50       23 if ( $ref eq '' ) {
    100          
    100          
188 0         0 $ok = $ctx->ok( 0, $name );
189 0         0 $ctx->diag( 'Not a reference' );
190             }
191             elsif ( $ref ne 'ARRAY' ) {
192 2         4 $ok = $ctx->ok( 0, $name );
193 2         201 $ctx->diag( "Expected ARRAY reference but got $ref." );
194             }
195 4         6 elsif ( !@{$got} ) {
196 2         6 $ok = $ctx->ok( 0, $name );
197 2         170 $ctx->diag( 'Array contains no elements' );
198             }
199             else {
200 2         4 $ok = $ctx->ok( 1, $name );
201             }
202              
203 6         215 $ctx->release;
204              
205 6         82 return $ok;
206             }
207              
208              
209             =head2 is_empty_array( $got [, $name ] )
210              
211             Verifies that C<$got> is an arrayref, and that the array it refers to
212             has no elements.
213              
214             If the array contains anything, they will be dumped as a diagnostic
215             using Test2::Tools::Explain.
216              
217             =cut
218              
219             sub is_empty_array {
220 6     6 1 101045 my $got = shift;
221 6         7 my $name = shift;
222              
223 6         8 my $ok;
224 6         10 my $ctx = context();
225              
226 6         332 my $ref = ref $got;
227 6 50       24 if ( $ref eq '' ) {
    100          
    100          
228 0         0 $ok = $ctx->ok( 0, $name );
229 0         0 $ctx->diag( 'Not a reference' );
230             }
231             elsif ( $ref ne 'ARRAY' ) {
232 2         5 $ok = $ctx->ok( 0, $name );
233 2         198 $ctx->diag( "Expected ARRAY reference but got $ref." );
234             }
235 4         8 elsif ( (my $n = @{$got}) > 0 ) {
236 2         6 $ok = $ctx->ok( 0, $name );
237 2 100       216 my $s = $n == 1 ? '' : 's';
238 2         8 $ctx->diag( "Array contains $n element$s" );
239 2         89 $ctx->diag( explain( $got ) );
240             }
241             else {
242 2         5 $ok = $ctx->ok( 1, $name );
243             }
244              
245 6         5364 $ctx->release;
246              
247 6         92 return $ok;
248             }
249              
250              
251             =head2 is_empty_hash( $got [, $name ] )
252              
253             Verifies that C<$got> is a hashref, and that the hash it refers to has
254             no elements.
255              
256             If the hash contains any elements, they will be dumped as a diagnostic
257             using Test2::Tools::Explain.
258              
259             =cut
260              
261             sub is_empty_hash {
262 6     6 1 100761 my $got = shift;
263 6         7 my $name = shift;
264              
265 6         5 my $ok;
266 6         9 my $ctx = context();
267              
268 6         270 my $ref = ref $got;
269 6 50       24 if ( $ref eq '' ) {
    100          
    100          
270 0         0 $ok = $ctx->ok( 0, $name );
271 0         0 $ctx->diag( 'Not a reference' );
272             }
273             elsif ( $ref ne 'HASH' ) {
274 2         6 $ok = $ctx->ok( 0, $name );
275 2         201 $ctx->diag( "Expected HASH reference but got $ref." );
276             }
277 4         10 elsif ( (my $n = scalar keys %{$got}) > 0 ) {
278 2         5 $ok = $ctx->ok( 0, $name );
279 2 100       175 my $s = $n == 1 ? '' : 's';
280 2         6 $ctx->diag( "Hash contains $n element$s" );
281 2         70 $ctx->diag( explain( $got ) );
282             }
283             else {
284 2         5 $ok = $ctx->ok( 1, $name );
285             }
286              
287 6         5063 $ctx->release;
288              
289 6         84 return $ok;
290             }
291              
292              
293             =head2 is_nonempty_hash( $got [, $name ] )
294              
295             Verifies that C<$got> is a hashref, and that the hash contains at least
296             one entry.
297              
298             =cut
299              
300             sub is_nonempty_hash {
301 6     6 1 100477 my $got = shift;
302 6         7 my $name = shift;
303              
304 6         4 my $ok;
305 6         9 my $ctx = context();
306              
307 6         268 my $ref = ref $got;
308 6 50       23 if ( $ref eq '' ) {
    100          
    100          
309 0         0 $ok = $ctx->ok( 0, $name );
310 0         0 $ctx->diag( 'Not a reference' );
311             }
312             elsif ( $ref ne 'HASH' ) {
313 2         5 $ok = $ctx->ok( 0, $name );
314 2         196 $ctx->diag( "Expected HASH reference but got $ref." );
315             }
316 4         8 elsif ( scalar keys %{$got} == 0 ) {
317 2         5 $ok = $ctx->ok( 0, $name );
318 2         168 $ctx->diag( 'Hash contains no entries.' );
319             }
320             else {
321 2         5 $ok = $ctx->ok( 1, $name );
322             }
323              
324 6         214 $ctx->release;
325              
326 6         82 return $ok;
327             }
328              
329              
330             =head1 AUTHOR
331              
332             Andy Lester, C<< >>
333              
334             =head1 BUGS
335              
336             Please report any bugs or feature requests to
337             L.
338             I will be notified, and then you'll automatically be notified of progress
339             on your bug as I make changes.
340              
341             =head1 SUPPORT
342              
343             You can find documentation for this module with the perldoc command.
344              
345             perldoc Test2::Tools::Expressive
346              
347             You can also look for information at:
348              
349             =over 4
350              
351             =item * GitHub project page
352              
353             L
354              
355             =item * AnnoCPAN: Annotated CPAN documentation
356              
357             L
358              
359             =item * CPAN Ratings
360              
361             L
362              
363             =item * Search CPAN
364              
365             L
366              
367             =back
368              
369              
370             =head1 ACKNOWLEDGEMENTS
371              
372              
373             =head1 LICENSE AND COPYRIGHT
374              
375             Copyright 2016 Andy Lester.
376              
377             This program is free software; you can redistribute it and/or modify it
378             under the terms of the the Artistic License (2.0). You may obtain a
379             copy of the full license at:
380              
381             L
382              
383             Any use, modification, and distribution of the Standard or Modified
384             Versions is governed by this Artistic License. By using, modifying or
385             distributing the Package, you accept this license. Do not use, modify,
386             or distribute the Package, if you do not accept this license.
387              
388             If your Modified Version has been derived from a Modified Version made
389             by someone other than you, you are nevertheless required to ensure that
390             your Modified Version complies with the requirements of this license.
391              
392             This license does not grant you the right to use any trademark, service
393             mark, tradename, or logo of the Copyright Holder.
394              
395             This license includes the non-exclusive, worldwide, free-of-charge
396             patent license to make, have made, use, offer to sell, sell, import and
397             otherwise transfer the Package with respect to any patent claims
398             licensable by the Copyright Holder that are necessarily infringed by the
399             Package. If you institute patent litigation (including a cross-claim or
400             counterclaim) against any party alleging that the Package constitutes
401             direct or contributory patent infringement, then this Artistic License
402             to you shall terminate on the date that such litigation is filed.
403              
404             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
405             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
406             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
407             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
408             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
409             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
410             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
411             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
412              
413              
414             =cut
415              
416             1; # End of Test2::Tools::Expressive