File Coverage

blib/lib/Test2/Tools/Type.pm
Criterion Covered Total %
statement 48 48 100.0
branch 10 12 83.3
condition n/a
subroutine 13 13 100.0
pod 4 4 100.0
total 75 77 97.4


line stmt bran cond sub pod time code
1             package Test2::Tools::Type;
2              
3 2     2   199191 use strict;
  2         4  
  2         77  
4 2     2   9 use warnings;
  2         4  
  2         121  
5              
6 2     2   16 use base qw(Exporter);
  2         3  
  2         302  
7              
8             our $VERSION = '1.0.1';
9              
10 2     2   15 use Carp qw(croak);
  2         3  
  2         126  
11              
12 2     2   12 use Test2::API qw(context);
  2         3  
  2         95  
13 2     2   1059 use Test2::Compare::Type ();
  2         7  
  2         60  
14              
15 2     2   11 use Scalar::Type qw(bool_supported);
  2         4  
  2         8  
16              
17             our @EXPORT = qw(
18             is_integer is_number
19             is_bool bool_supported
20             type
21             );
22              
23             sub import {
24 4 50   4   223206 if(@_) {
25 4 100       6 if(grep { $_ eq ':extras' } @_) {
  8         18  
26 2         544 require Test2::Tools::Type::Extras;
27 2         91 Test2::Tools::Type::Extras->import();
28 2         8 push @EXPORT, @Test2::Tools::Type::Extras::EXPORT;
29 2         3 @_ = grep { $_ ne ':extras' } @_;
  5         9  
30             }
31 4 100       7 if(grep { $_ eq 'show_types' } @_) {
  6         12  
32 2         79 print "Supported types:\n";
33 2         6 print " ".substr($_, 3)."\n" foreach(sort grep { /^is_/ } @EXPORT);
  23         166  
34 2         8 return;
35             }
36             }
37 2         109 goto &Exporter::import;
38             }
39              
40 18     18 1 8074 sub is_integer { _checker(\&Scalar::Type::is_integer, @_); }
41 15     15 1 6826 sub is_number { _checker(\&Scalar::Type::is_number, @_); }
42              
43             sub is_bool {
44 7 50   7 1 167 croak("You need perl 5.36 or higher to use is_bool")
45             unless(bool_supported());
46 7         19 _checker(\&Scalar::Type::is_bool, @_);
47             }
48              
49             sub _checker {
50 94     94   189 my($checker, $candidate, $name) = @_;
51              
52 94         188 my $result = $checker->($candidate);
53              
54             # if we're coming from Test2::Compare::Type just do the check, don't
55             # get/twiddle/release a context
56 94 100       332 return $result if($Test2::Compare::Type::verifying);
57              
58 63         145 my $ctx = context();
59 63 100       4318 return $ctx->pass_and_release($name) if($result);
60 37         76 return $ctx->fail_and_release($name);
61             }
62              
63             sub type {
64 28     28 1 43923 my @caller = caller;
65 28         164 return Test2::Compare::Type->new(
66             file => $caller[1],
67             lines => [$caller[2]],
68             type => \@_,
69             );
70             }
71              
72             1;
73              
74             =head1 NAME
75              
76             Test2::Tools::Type - Tools for checking data types
77              
78             =head1 SYNOPSIS
79              
80             use Test2::V0;
81             use Test2::Tools::Type;
82              
83             is_integer(1, "is 1 integer?"); # pass, yes it is
84             is_integer('1', "is '1' an integer?"); # fail, no it's a string
85              
86             SKIP: {
87             skip "Your perl is too old" unless(bool_supported());
88             is_bool(1 == 2, "is false a Boolean?"); # pass, yes it is
89             is_bool(3.1415, "is pi a Boolean?"); # fail, no it isn't
90             }
91              
92             like
93             { should_be_int => 1, other_stuff => "we don't care about this" },
94             hash {
95             field should_be_int => type('integer');
96             },
97             "is the should_be_int field an integer?";
98              
99             or if you want even more check functions:
100              
101             use Test2::V0;
102             use Test2::Tools::Type qw(:extras);
103              
104             is_hashref($foo);
105              
106             =head1 OVERVIEW
107              
108             Sometimes you don't want to be too precise in your tests, you just want to
109             check that your code returns the right type of result but you don't care whether
110             it's returning 192 or 193 - just checking that it returns an integer is good
111             enough.
112              
113             =head1 FUNCTIONS
114              
115             All these are exported by default.
116              
117             =head2 bool_supported
118              
119             Returns true if your perl is recent enough to have the Boolean type, false
120             otherwise. It will be true if your perl is version 5.35.7 or higher.
121              
122             =head2 is_bool
123              
124             Emits a test pass if its argument is a Boolean - ie is the result of a comparison -
125             and a fail otherwise.
126              
127             It is a fatal error to call this on a perl that is too old. If your tests need
128             to run on perl 5.35.6 or earlier then you will need to check C
129             before using it. See the L above.
130              
131             =head2 is_integer
132              
133             Emits a test pass if its argument is an integer and a fail otherwise. Note that it
134             can tell the difference between C<1> (an integer) and C<'1'> (a string).
135              
136             =head2 is_number
137              
138             Emits a test pass if its argument is a number and a fail otherwise. Note that it
139             can tell the difference between C<1> (a number), C<1.2> (also a number) and
140             C<'1'> (a string).
141              
142             =head2 type
143              
144             Returns a check that you can use in a test such as:
145              
146             like
147             { int => 1 },
148             hash { field int => type('integer'); },
149             "the 'int' field is an integer";
150              
151             You can negate the test with a C thus. This test will fail:
152              
153             like
154             { int => 1 },
155             hash { field int => !type('integer'); },
156             "the 'int' field is an integer";
157              
158             You can supply more than one argument, so if you want to check that
159             something is a I integer, for example, you can do:
160              
161             is(94, type(qw(positive integer)));
162              
163             You can check something's type and value:
164              
165             # this uses 'number' from Test2::Tools::Compare
166             is($foo, type('integer', number(94)));
167              
168             And indeed you can use any other Test2 checker:
169              
170             # 'in_set' also comes from Test2::Tools::Compare
171             is($foo, type('integer', in_set(1, 5, 8)));
172              
173             Valid arguments are any other Test2 checker (specifically, anything that
174             inherits from L), and any of the C methods' names,
175             with the leading C removed. You can see a list of supported types thus:
176              
177             $ perl -MTest2::Tools::Type=show_types
178              
179             or to include the extra functions:
180              
181             $ perl -MTest2::Tools::Type=show_types,:extras
182              
183             =head1 EXTRA FUNCTIONS
184              
185             By default the only check functions you get are those that are thin wrappers
186             around L. If you pass the C<:extras> argument at C-time then
187             all the following are available as well:
188              
189             =head2 regex_supported
190              
191             Returns true if your perl can reliably report the difference between a regex
192             and a reference to a scalar, or false otherwise. It will be true if your perl
193             is version 5.12 or higher.
194              
195             =head2 is_positive, is_negative
196              
197             Emit a test pass/fail depending on the argument's sign. Note that C<0> is
198             considered neither positive nor negative.
199              
200             =head2 is_zero
201              
202             Emit a pass/fail depending on whether the argument is zero.
203              
204             =head2 is_ref
205              
206             Emit a pass/fail depending on whether the argument is a reference. This
207             includes blessed objects.
208              
209             =head2 is_object
210              
211             Emit a pass/fail depending on whether the argument is a blessed object.
212              
213             =head2 is_regex
214              
215             Emit a test pass if its argument is a regex, and a fail otherwise.
216              
217             It is a fatal error to call this on a perl that is too old. If your tests need
218             to run on perl 5.10.1 or earlier then you will need to check C
219             before using it.
220              
221             =head2 is_hashref, is_arrayref, is_scalarref, is_coderef, is_globref, is_regex, is_refref
222              
223             Emit a pass/fail if the argumet is a reference to something of the appropriate type.
224              
225             =head1 CAVEATS
226              
227             The definitions of Boolean, integer and number are exactly the same as those in
228             L, which this is a thin wrapper around.
229              
230             Blessed objects will match both C and the appropriate C. If you
231             need to check that something is a ref, but is I blessed, do something like:
232              
233             is($foo, type(hashref => !type('object')));
234              
235             =head1 SEE ALSO
236              
237             L
238              
239             L
240              
241             =head1 BUGS
242              
243             If you find any bugs please report them on Github, preferably with a test case.
244              
245             =head1 FEEDBACK
246              
247             I welcome feedback about my code, especially constructive criticism.
248              
249             =head1 AUTHOR, COPYRIGHT and LICENCE
250              
251             Copyright 2024 David Cantrell EFE
252              
253             This software is free-as-in-speech software, and may be used,
254             distributed, and modified under the terms of either the GNU
255             General Public Licence version 2 or the Artistic Licence. It's
256             up to you which one you use. The full text of the licences can
257             be found in the files GPL2.txt and ARTISTIC.txt, respectively.
258              
259             =head1 CONSPIRACY
260              
261             This module is also free-as-in-mason software.
262              
263             =cut