File Coverage

blib/lib/Test/DZil.pm
Criterion Covered Total %
statement 74 75 98.6
branch 17 22 77.2
condition 6 7 85.7
subroutine 17 17 100.0
pod 5 5 100.0
total 119 126 94.4


line stmt bran cond sub pod time code
1             # ABSTRACT: tools for testing Dist::Zilla plugins
2              
3             use Dist::Zilla::Pragmas;
4 50     50   5060430  
  50         152  
  50         334  
5             use Params::Util qw(_HASH0);
6 50     50   22465 use JSON::MaybeXS;
  50         256927  
  50         3324  
7 50     50   22267 use Scalar::Util qw(blessed);
  50         270363  
  50         2926  
8 50     50   344 use Test::Deep ();
  50         114  
  50         1860  
9 50     50   23383 use YAML::Tiny;
  50         320343  
  50         1316  
10 50     50   28451  
  50         280767  
  50         4292  
11             use Sub::Exporter -setup => {
12 50         568 exports => [
13             is_filelist =>
14             is_yaml =>
15             is_json =>
16             dist_ini => \'_dist_ini',
17             simple_ini => \'_simple_ini',
18             Builder =>
19             Minter =>
20             ],
21             groups => [ default => [ qw(-all) ] ],
22             };
23 50     50   30260  
  50         327390  
24             use namespace::autoclean -except => 'import';
25 50     50   50610  
  50         794074  
  50         261  
26             #pod =head1 DESCRIPTION
27             #pod
28             #pod Test::DZil provides routines for writing tests for Dist::Zilla plugins.
29             #pod
30             #pod =cut
31              
32             #pod =func Builder
33             #pod
34             #pod =func Minter
35             #pod
36             #pod my $tzil = Builder->from_config(...);
37             #pod
38             #pod These return class names that subclass L<Dist::Zilla::Dist::Builder> or
39             #pod L<Dist::Zilla::Dist::Minter>, respectively, with the L<Dist::Zilla::Tester>
40             #pod behavior added.
41             #pod
42             #pod =cut
43              
44             require Dist::Zilla::Tester;
45             Dist::Zilla::Tester::builder();
46 164     164 1 522478 }
47 164         1322  
48             require Dist::Zilla::Tester;
49             Dist::Zilla::Tester::minter();
50             }
51 1     1 1 586  
52 1         7 #pod =func is_filelist
53             #pod
54             #pod is_filelist( \@files_we_have, \@files_we_want, $desc );
55             #pod
56             #pod This test assertion compares two arrayrefs of filenames, taking care of slash
57             #pod normalization and sorting. C<@files_we_have> may also contain objects that
58             #pod do L<Dist::Zilla::Role::File>.
59             #pod
60             #pod =cut
61              
62             my ($have, $want, $comment) = @_;
63              
64             my @want = @$want;
65             my @have = map { my $str = (blessed $_ and
66 37     37 1 382 $_->DOES('Dist::Zilla::Role::File'))
67             ? $_->name
68 37         144 : $_;
69 37 100 66     96 $str =~ s{\\}{/}g; $str } @$have;
  227         3119  
70              
71             local $Test::Builder::Level = $Test::Builder::Level + 1;
72             Test::Deep::cmp_bag(\@have, \@want, $comment);
73 227         489 }
  227         480  
74              
75 37         105 #pod =func is_yaml
76 37         519 #pod
77             #pod is_yaml( $yaml_string, $want_struct, $comment );
78             #pod
79             #pod This test assertion deserializes the given YAML string and does a
80             #pod C<L<cmp_deeply|Test::Deep/cmp_deeply>>.
81             #pod
82             #pod =cut
83              
84             my ($yaml, $want, $comment) = @_;
85              
86             my $have = YAML::Tiny->read_string($yaml)
87             or die "Cannot decode YAML";
88              
89 2     2 1 5567 local $Test::Builder::Level = $Test::Builder::Level + 1;
90             Test::Deep::cmp_deeply($have->[0], $want, $comment);
91 2 50       16 }
92              
93             #pod =func is_json
94 2         2615 #pod
95 2         10 #pod is_json( $json_string, $want_struct, $comment );
96             #pod
97             #pod This test assertion deserializes the given JSON string and does a
98             #pod C<L<cmp_deeply|Test::Deep/cmp_deeply>>.
99             #pod
100             #pod =cut
101              
102             my ($json, $want, $comment) = @_;
103              
104             my $have = JSON::MaybeXS->new(ascii => 1)->decode($json)
105             or die "Cannot decode JSON";
106              
107             local $Test::Builder::Level = $Test::Builder::Level + 1;
108 2     2 1 727 Test::Deep::cmp_deeply($have, $want, $comment);
109             }
110 2 50       19  
111             my ($starting_core) = @_;
112             $starting_core ||= {};
113 2         102  
114 2         10 sub {
115             my (@arg) = @_;
116             my $new_core = _HASH0($arg[0]) ? shift(@arg) : {};
117              
118 95     95   224 my $core_config = { %$starting_core, %$new_core };
119 95   100     599  
120             my $config = '';
121              
122 159     159   1540 for my $key (sort keys %$core_config) {
123 159 100       1185 my @values = ref $core_config->{ $key }
124             ? @{ $core_config->{ $key } }
125 159         2005 : $core_config->{ $key };
126              
127 159         625 $config .= "$key = $_\n" for grep {defined} @values;
128             }
129 159         1305  
130             $config .= "\n" if length $config;
131 0         0  
132 961 50       2629 for my $line (@arg) {
133             my @plugin = ref $line ? @$line : ($line, {});
134 961         1586 my $moniker = shift @plugin;
  961         3732  
135             my $name = _HASH0($plugin[0]) ? undef : shift @plugin;
136             my $payload = shift(@plugin) || {};
137 159 50       913  
138             Carp::confess("bogus plugin configuration: too many args") if @plugin;
139 159         480  
140 469 100       1608 $config .= '[' . $moniker;
141 469         935 $config .= ' / ' . $name if defined $name;
142 469 100       1452 $config .= "]\n";
143 469   100     1274  
144             for my $key (sort keys %$payload) {
145 469 50       1173 my @values = ref $payload->{ $key }
146             ? @{ $payload->{ $key } }
147 469         1110 : $payload->{ $key };
148 469 100       1238  
149 469         814 $config .= "$key = $_\n" for grep {defined} @values;
150             }
151 469         1421  
152             $config .= "\n";
153 17         49 }
154 317 100       1052  
155             return $config;
156 317         582 }
  334         1340  
157             }
158              
159 469         1125 #pod =func dist_ini
160             #pod
161             #pod my $ini_text = dist_ini(\%root_config, @plugins);
162 159         2673 #pod
163             #pod This routine returns a string that could be used to populate a simple
164 95         843 #pod F<dist.ini> file. The C<%root_config> gives data for the "root" section of the
165             #pod configuration. To provide a line multiple times, provide an arrayref. For
166             #pod example, the root section could read:
167             #pod
168             #pod {
169             #pod name => 'Dist-Sample',
170             #pod author => [
171             #pod 'J. Smith <jsmith@example.com>',
172             #pod 'Q. Smith <qsmith@example.com>',
173             #pod ],
174             #pod }
175             #pod
176             #pod The root section is optional.
177             #pod
178             #pod Plugins can be given in a few ways:
179             #pod
180             #pod =begin :list
181             #pod
182             #pod = C<"PluginMoniker">
183             #pod
184             #pod = C<[ "PluginMoniker" ]>
185             #pod
186             #pod These become C<[PluginMoniker]>
187             #pod
188             #pod = C<[ "PluginMoniker", "PluginName" ]>
189             #pod
190             #pod This becomes C<[PluginMoniker / PluginName]>
191             #pod
192             #pod = C<[ "PluginMoniker", { ... } ]>
193             #pod
194             #pod = C<[ "PluginMoniker", "PluginName", { ... } ]>
195             #pod
196             #pod These use the given hashref as the parameters inside the section, with the same
197             #pod semantics as the root section.
198             #pod
199             #pod =end :list
200             #pod
201             #pod =cut
202              
203             _build_ini_builder;
204             }
205              
206             #pod =func simple_ini
207             #pod
208             #pod This behaves exactly like C<dist_ini>, but it merges any given root config into
209             #pod a starter config, which means that you can often skip any explicit root config.
210             #pod The starter config may change slightly over time, but is something like this:
211 46     46   10964 #pod
212             #pod {
213             #pod name => 'DZT-Sample',
214             #pod abstract => 'Sample DZ Dist',
215             #pod version => '0.001',
216             #pod author => 'E. Xavier Ample <example@example.org>',
217             #pod license => 'Perl_5',
218             #pod copyright_holder => 'E. Xavier Ample',
219             #pod }
220             #pod
221             #pod =cut
222              
223             _build_ini_builder({
224             name => 'DZT-Sample',
225             abstract => 'Sample DZ Dist',
226             version => '0.001',
227             author => 'E. Xavier Ample <example@example.org>',
228             license => 'Perl_5',
229             copyright_holder => 'E. Xavier Ample',
230             });
231             }
232 49     49   13217  
233             1;
234              
235              
236             =pod
237              
238             =encoding UTF-8
239              
240             =head1 NAME
241              
242             Test::DZil - tools for testing Dist::Zilla plugins
243              
244             =head1 VERSION
245              
246             version 6.028
247              
248             =head1 DESCRIPTION
249              
250             Test::DZil provides routines for writing tests for Dist::Zilla plugins.
251              
252             =head1 PERL VERSION
253              
254             This module should work on any version of perl still receiving updates from
255             the Perl 5 Porters. This means it should work on any version of perl released
256             in the last two to three years. (That is, if the most recently released
257             version is v5.40, then this module should work on both v5.40 and v5.38.)
258              
259             Although it may work on older versions of perl, no guarantee is made that the
260             minimum required version will not be increased. The version may be increased
261             for any reason, and there is no promise that patches will be accepted to lower
262             the minimum required perl.
263              
264             =head1 FUNCTIONS
265              
266             =head2 Builder
267              
268             =head2 Minter
269              
270             my $tzil = Builder->from_config(...);
271              
272             These return class names that subclass L<Dist::Zilla::Dist::Builder> or
273             L<Dist::Zilla::Dist::Minter>, respectively, with the L<Dist::Zilla::Tester>
274             behavior added.
275              
276             =head2 is_filelist
277              
278             is_filelist( \@files_we_have, \@files_we_want, $desc );
279              
280             This test assertion compares two arrayrefs of filenames, taking care of slash
281             normalization and sorting. C<@files_we_have> may also contain objects that
282             do L<Dist::Zilla::Role::File>.
283              
284             =head2 is_yaml
285              
286             is_yaml( $yaml_string, $want_struct, $comment );
287              
288             This test assertion deserializes the given YAML string and does a
289             C<L<cmp_deeply|Test::Deep/cmp_deeply>>.
290              
291             =head2 is_json
292              
293             is_json( $json_string, $want_struct, $comment );
294              
295             This test assertion deserializes the given JSON string and does a
296             C<L<cmp_deeply|Test::Deep/cmp_deeply>>.
297              
298             =head2 dist_ini
299              
300             my $ini_text = dist_ini(\%root_config, @plugins);
301              
302             This routine returns a string that could be used to populate a simple
303             F<dist.ini> file. The C<%root_config> gives data for the "root" section of the
304             configuration. To provide a line multiple times, provide an arrayref. For
305             example, the root section could read:
306              
307             {
308             name => 'Dist-Sample',
309             author => [
310             'J. Smith <jsmith@example.com>',
311             'Q. Smith <qsmith@example.com>',
312             ],
313             }
314              
315             The root section is optional.
316              
317             Plugins can be given in a few ways:
318              
319             =over 4
320              
321             =item C<"PluginMoniker">
322              
323             =item C<[ "PluginMoniker" ]>
324              
325             These become C<[PluginMoniker]>
326              
327             =item C<[ "PluginMoniker", "PluginName" ]>
328              
329             This becomes C<[PluginMoniker / PluginName]>
330              
331             =item C<[ "PluginMoniker", { ... } ]>
332              
333             =item C<[ "PluginMoniker", "PluginName", { ... } ]>
334              
335             These use the given hashref as the parameters inside the section, with the same
336             semantics as the root section.
337              
338             =back
339              
340             =head2 simple_ini
341              
342             This behaves exactly like C<dist_ini>, but it merges any given root config into
343             a starter config, which means that you can often skip any explicit root config.
344             The starter config may change slightly over time, but is something like this:
345              
346             {
347             name => 'DZT-Sample',
348             abstract => 'Sample DZ Dist',
349             version => '0.001',
350             author => 'E. Xavier Ample <example@example.org>',
351             license => 'Perl_5',
352             copyright_holder => 'E. Xavier Ample',
353             }
354              
355             =head1 AUTHOR
356              
357             Ricardo SIGNES 😏 <cpan@semiotic.systems>
358              
359             =head1 COPYRIGHT AND LICENSE
360              
361             This software is copyright (c) 2022 by Ricardo SIGNES.
362              
363             This is free software; you can redistribute it and/or modify it under
364             the same terms as the Perl 5 programming language system itself.
365              
366             =cut