1package Test::Auto;
2
3use strict;
4use warnings;
5
6use Moo;
7
8use Exporter;
9use Test::Auto::Data;
10use Test::Auto::Try;
11use Test::Auto::Types ();
12use Test::More;
13use Type::Registry;
14
15use base 'Exporter';
16
17our @EXPORT = 'testauto';
18
19our $VERSION = '0.12'; # VERSION
20
21# ATTRIBUTES
22
23has file => (
24  is => 'ro',
25  isa => Test::Auto::Types::Str(),
26  required => 1
27);
28
29has data => (
30  is => 'ro',
31  isa => Test::Auto::Types::Data(),
32  required => 0
33);
34
35# EXPORTS
36
37sub testauto {
38  my ($file) = @_;
39
40  return Test::Auto->new($file)->subtests;
41}
42
43# BUILDS
44
45sub BUILD {
46  my ($self, $args) = @_;
47
48  my $data = $self->data;
49  my $file = $self->file;
50
51  $self->{data} = Test::Auto::Data->new(file => $file) if !$data;
52
53  return $self;
54}
55
56around BUILDARGS => sub {
57  my ($orig, $self, @args) = @_;
58
59  @args = (file => $args[0]) if @args == 1 && !ref $args[0];
60
61  $self->$orig(@args);
62};
63
64# METHODS
65
66sub parser {
67  my ($self) = @_;
68
69  require Test::Auto::Parser;
70
71  return Test::Auto::Parser->new(
72    source => $self
73  );
74}
75
76sub document {
77  my ($self) = @_;
78
79  require Test::Auto::Document;
80
81  return Test::Auto::Document->new(
82    parser => $self->parser
83  );
84}
85
86sub subtests {
87  my ($self) = @_;
88
89  require Test::Auto::Subtests;
90
91  return Test::Auto::Subtests->new(
92    parser => $self->parser
93  );
94}
95
961;
97
98=encoding utf8
99
100=head1 NAME
101
102Test::Auto - Test Automation
103
104=cut
105
106=head1 ABSTRACT
107
108Test Automation, Docs Generation
109
110=cut
111
112=head1 SYNOPSIS
113
114  #!/usr/bin/env perl
115
116  use Test::Auto;
117  use Test::More;
118
119  my $test = Test::Auto->new(
120    't/Test_Auto.t'
121  );
122
123  # automation
124
125  # my $subtests = $test->subtests->standard;
126
127  # ...
128
129  # done_testing;
130
131=cut
132
133=head1 DESCRIPTION
134
135This package aims to provide, a standard for documenting Perl 5 software
136projects, a framework writing tests, test automation, and documentation
137generation.
138
139=cut
140
141=head1 REASONING
142
143This framework lets you write documentation in test files using pod-like
144comment blocks. By using a particular set of comment blocks (the specification)
145this framework can run certain kinds of tests automatically. For example, we
146can automatically ensure that the package the test is associated with is
147loadable, that the test file comment blocks meet the specification, that any
148super-classes or libraries are loadable, and that the functions, methods, and
149routines are properly documented.
150
151=cut
152
153=head1 LIBRARIES
154
155This package uses type constraints from:
156
157L<Test::Auto::Types>
158
159=cut
160
161=head1 SCENARIOS
162
163This package supports the following scenarios:
164
165=cut
166
167=head2 exports
168
169  use Test::Auto;
170  use Test::More;
171
172  my $subtests = testauto 't/Test_Auto.t';
173
174  # automation
175
176  # $subtests->standard;
177
178  # ...
179
180  # done_testing;
181
182This package automatically exports the C<testauto> function which uses the
183"current file" as the automated testing source.
184
185=cut
186
187=head1 ATTRIBUTES
188
189This package has the following attributes:
190
191=cut
192
193=head2 data
194
195  data(Data)
196
197This attribute is read-only, accepts C<(Data)> values, and is optional.
198
199=cut
200
201=head2 file
202
203  file(Str)
204
205This attribute is read-only, accepts C<(Str)> values, and is required.
206
207=cut
208
209=head1 FUNCTIONS
210
211This package implements the following functions:
212
213=cut
214
215=head2 testauto
216
217  testauto(Str $file) : Subtests
218
219This function is exported automatically and returns a L<Test::Auto::Subtests>
220object for the test file given.
221
222=over 4
223
224=item testauto example #1
225
226  # given: synopsis
227
228  my $subtests = testauto 't/Test_Auto.t';
229
230=back
231
232=cut
233
234=head1 METHODS
235
236This package implements the following methods:
237
238=cut
239
240=head2 document
241
242  document() : Document
243
244This method returns a L<Test::Auto::Document> object.
245
246=over 4
247
248=item document example #1
249
250  # given: synopsis
251
252  my $document = $test->document;
253
254=back
255
256=cut
257
258=head2 parser
259
260  parser() : Parser
261
262This method returns a L<Test::Auto::Parser> object.
263
264=over 4
265
266=item parser example #1
267
268  # given: synopsis
269
270  my $parser = $test->parser;
271
272=back
273
274=cut
275
276=head2 subtests
277
278  subtests() : Subtests
279
280This method returns a L<Test::Auto::Subtests> object.
281
282=over 4
283
284=item subtests example #1
285
286  # given: synopsis
287
288  my $subtests = $test->subtests;
289
290=back
291
292=cut
293
294=head1 SPECIFICATION
295
296  # [required]
297
298  =name
299  =abstract
300  =tagline
301  =includes
302  =synopsis
303  =description
304
305  # [optional]
306
307  =libraries
308  =inherits
309  =integrates
310  =attributes
311
312  # [repeatable; optional]
313
314  =scenario $name
315  =example $name
316
317  # [repeatable; optional]
318
319  =method $name
320  =signature $name
321  =example-$number $name # [repeatable]
322
323  # [repeatable; optional]
324
325  =function $name
326  =signature $name
327  =example-$number $name # [repeatable]
328
329  # [repeatable; optional]
330
331  =routine $name
332  =signature $name
333  =example-$number $name # [repeatable]
334
335  # [repeatable; optional]
336
337  =type $name
338  =type-library $name
339  =type-composite $name # [optional]
340  =type-parent $name # [optional]
341  =type-coercion-$number $name # [optional]
342  =type-example-$number $name # [repeatable]
343
344The specification is designed to accommodate typical package declarations. It
345is used by the parser to provide the content used in the test automation and
346document generation. Note: when code blocks are evaluated I<"redefined">
347warnings are now automatically disabled.
348
349=head2 name
350
351  =name
352
353  Path::Find
354
355  =cut
356
357The C<name> block should contain the package name. This is tested for
358loadability.
359
360=head2 tagline
361
362  =tagline
363
364  Path Finder
365
366  =cut
367
368The C<tagline> block should contain a tagline for the package. This is optional
369but if present is concatenated with the C<name> during POD generation.
370
371=head2 abstract
372
373  =abstract
374
375  Find Paths using Heuristics
376
377  =cut
378
379The C<abstract> block should contain a subtitle describing the package. This is
380tested for existence.
381
382=head2 includes
383
384  =includes
385
386  function: path
387  method: children
388  method: siblings
389  method: new
390
391  =cut
392
393The C<includes> block should contain a list of C<function>, C<method>, and/or
394C<routine> names in the format of C<$type: $name>. Empty lines are ignored.
395This is tested for existence. Each function, method, and/or routine is tested
396to be documented properly. Also, the package must recognize that each exists.
397
398=head2 synopsis
399
400  =synopsis
401
402  use Path::Find 'path';
403
404  my $path = path; # get path using cwd
405
406  =cut
407
408The C<synopsis> block should contain the normative usage of the package. This
409is tested for existence. This block should be written in a way that allows it
410to be evaled successfully and should return a value.
411
412=head2 description
413
414  =description
415
416  interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis
417  tristique sollicitudin nibh sit amet
418
419  =cut
420
421The C<description> block should contain a thorough explanation of the purpose
422of the package. This is tested for existence.
423
424=head2 libraries
425
426  =libraries
427
428  Types::Standard
429  Types::TypeTiny
430
431  =cut
432
433The C<libraries> block should contain a list of packages, each of which is
434itself a L<Type::Library>. These packages are tested for loadability, and to
435ensure they are type library classes.
436
437=head2 inherits
438
439  =inherits
440
441  Path::Tiny
442
443  =cut
444
445The C<inherits> block should contain a list of parent packages. These packages
446are tested for loadability.
447
448=head2 integrates
449
450  =integrates
451
452  Path::Find::Upable
453  Path::Find::Downable
454
455  =cut
456
457The C<integrates> block should contain a list of packages that are involved in
458the behavior of the main package. These packages are not automatically tested.
459
460=head2 scenarios
461
462  =scenario export-path-make
463
464  quisque egestas diam in arcu cursus euismod quis viverra nibh
465
466  =example export-path-make
467
468  # given: synopsis
469
470  package main;
471
472  use Path::Find 'path_make';
473
474  path_make 'relpath/to/file';
475
476  =cut
477
478
479There are situation where a package can be configured in different ways,
480especially where it exists without functions, methods or routines for the
481purpose of configuring the environment. The scenario directive can be used to
482automate testing and documenting package usages and configurations.Describing a
483scenario requires two blocks, i.e. C<scenario $name> and C<example $name>. The
484C<scenario> block should contain a description of the scenario and its purpose.
485The C<example> block must exist when documenting a method and should contain
486valid Perl code and return a value. The block may contain a "magic" comment in
487the form of C<given: synopsis> or C<given: example $name> which if present will
488include the given code example(s) with the evaluation of the current block.
489Each scenario is tested and must be recognized to exist by the main package.
490
491=head2 attributes
492
493  =attributes
494
495  cwd: ro, req, Object
496
497  =cut
498
499The C<attributes> block should contain a list of package attributes in the form
500of C<$name: $is, $presence, $type>, where C<$is> should be C<ro> (read-only) or
501C<rw> (read-wire), and C<$presence> should be C<req> (required) or C<opt>
502(optional), and C<$type> can be any valid L<Type::Tiny> expression. Each
503attribute declaration must be recognized to exist by the main package and have
504a type which is recognized by one of the declared type libraries.
505
506=head2 methods
507
508  =method children
509
510  quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat
511
512  =signature children
513
514  children() : [Object]
515
516  =example-1 children
517
518  # given: synopsis
519
520  my $children = $path->children;
521
522  =example-2 children
523
524  # given: synopsis
525
526  my $filtered = $path->children(qr/lib/);
527
528  =cut
529
530Describing a method requires at least three blocks, i.e. C<method $name>,
531C<signature $name>, and C<example-1 $name>. The C<method> block should contain
532a description of the method and its purpose. The C<signature> block should
533contain a method signature in the form of C<$signature : $return_type>, where
534C<$signature> is a valid typed signature and C<$return_type> is any valid
535L<Type::Tiny> expression. The C<example-$number> block is a repeatable block,
536and at least one block must exist when documenting a method. The
537C<example-$number> block should contain valid Perl code and return a value. The
538block may contain a "magic" comment in the form of C<given: synopsis> or
539C<given: example-$number $name> which if present will include the given code
540example(s) with the evaluation of the current block. Each method is tested and
541must be recognized to exist by the main package.
542
543=head2 functions
544
545  =function path
546
547  lectus quam id leo in vitae turpis massa sed elementum tempus egestas
548
549  =signature children
550
551  path() : Object
552
553  =example-1 path
554
555  package Test::Path::Find;
556
557  use Path::Find;
558
559  my $path = path;
560
561  =cut
562
563Describing a function requires at least three blocks, i.e. C<function $name>,
564C<signature $name>, and C<example-1 $name>. The C<function> block should
565contain a description of the function and its purpose. The C<signature> block
566should contain a function signature in the form of C<$signature :
567$return_type>, where C<$signature> is a valid typed signature and
568C<$return_type> is any valid L<Type::Tiny> expression. The C<example-$number>
569block is a repeatable block, and at least one block must exist when documenting
570a function. The C<example-$number> block should contain valid Perl code and
571return a value. The block may contain a "magic" comment in the form of C<given:
572synopsis> or C<given: example-$number $name> which if present will include the
573given code example(s) with the evaluation of the current block. Each function
574is tested and must be recognized to exist by the main package.
575
576=head2 routines
577
578  =routine algorithms
579
580  sed sed risus pretium quam vulputate dignissim suspendisse in est ante
581
582  =signature algorithms
583
584  algorithms() : Object
585
586  =example-1 algorithms
587
588  # given: synopsis
589
590  $path->algorithms
591
592  =example-2 algorithms
593
594  package Test::Path::Find;
595
596  use Path::Find;
597
598  Path::Find->algorithms;
599
600  =cut
601
602Typically, a Perl subroutine is declared as a function or a method. Rarely, but
603sometimes necessary, you will need to describe a subroutine where the invocant
604is either a class or class instance. Describing a routine requires at least
605three blocks, i.e. C<routine $name>, C<signature $name>, and C<example-1
606$name>. The C<routine> block should contain a description of the routine and
607its purpose. The C<signature> block should contain a routine signature in the
608form of C<$signature : $return_type>, where C<$signature> is a valid typed
609signature and C<$return_type> is any valid L<Type::Tiny> expression. The
610C<example-$number> block is a repeatable block, and at least one block must
611exist when documenting a routine. The C<example-$number> block should contain
612valid Perl code and return a value. The block may contain a "magic" comment in
613the form of C<given: synopsis> or C<given: example-$number $name> which if
614present will include the given code example(s) with the evaluation of the
615current block. Each routine is tested and must be recognized to exist by the
616main package.
617
618=head2 types
619
620  =type Path
621
622    Path
623
624  =type-parent Path
625
626    Object
627
628  =type-library Path
629
630  Path::Types
631
632  =type-composite Path
633
634    InstanceOf["Path::Find"]
635
636  =type-coercion-1 Path
637
638    # can coerce from Str
639
640    './path/to/file'
641
642  =type-example-1 Path
643
644    require Path::Find;
645
646    Path::Find::path('./path/to/file')
647
648  =cut
649
650When developing Perl programs, or type libraries, that use L<Type::Tiny> based
651type constraints, testing and documenting custom type constraints is often
652overlooked. Describing a custom type constraint requires at least two blocks,
653i.e. C<type $name> and C<type-library $name>. While it's not strictly required,
654it's a good idea to also include at least one C<type-example-1 $name>. The
655optional C<type-parent> block should contain the name of the parent type. The
656C<type-composite> block should contain a type expression that represents the
657derived type. The C<type-coercion-$number> block is a repeatable block which
658is used to validate type coercion. The C<type-coercion-$number> block should
659contain valid Perl code and return the value to be coerced. The
660C<type-example-$number> block is a repeatable block, and it's a good idea to
661have at least one block must exist when documenting a type. The
662C<type-example-$number> block should contain valid Perl code and return a
663value. Each type is tested and must be recognized to exist within the package
664specified by the C<type-library> block.
665
666=head1 AUTOMATION
667
668  $test->standard;
669
670This is the equivalent of writing:
671
672  $test->package;
673  $test->document;
674  $test->libraries;
675  $test->inherits;
676  $test->attributes;
677  $test->methods;
678  $test->routines;
679  $test->functions;
680  $test->types;
681
682This framework provides a set of automated subtests based on the package
683specification, but not everything can be automated so it also provides you with
684powerful hooks into the framework for manual testing.
685
686  my $subtests = $test->subtests;
687
688  $subtests->synopsis(sub {
689    my ($tryable) = @_;
690
691    ok my $result = $tryable->result, 'result ok';
692
693    $result; # for automated testing after the callback
694  });
695
696The code examples documented can be automatically evaluated (evaled) and
697returned using a callback you provide for further testing. Because the code
698examples are returned as C<Test::Auto::Try> objects (see L<Data::Object::Try>),
699this makes capturing and testing exceptions simple, for example:
700
701  my $subtests = $test->subtests;
702
703  $subtests->synopsis(sub {
704    my ($tryable) = @_;
705
706    # catch exception thrown by the synopsis
707    $tryable->catch('Path::Find::Error', sub {
708      return $_[0];
709    });
710    # test the exception
711    ok my $result = $tryable->result, 'result ok';
712    ok $result->isa('Path::Find::Error'), 'exception caught';
713
714    $result;
715  });
716
717Additionally, another manual testing hook (with some automation) is the
718C<example> method. This hook evaluates (evals) a given example and returns the
719result as a C<Test::Auto::Try> object (see L<Data::Object::Try>). The first
720argument is the example ID (or number), for example:
721
722  my $subtests = $test->subtests;
723
724  $subtests->example(-1, 'children', 'method', sub {
725    my ($tryable) = @_;
726
727    ok my $result = $tryable->result, 'result ok';
728
729    $result; # for automated testing after the callback
730  });
731
732Finally, the lesser-used but useful manual testing hook is the C<scenario>
733method. This hook evaluates (evals) a documented scenario and returns the
734result as a C<Test::Auto::Try> object (see L<Data::Object::Try>), for example:
735
736  my $subtests = $test->subtests;
737
738  $subtests->scenario('export-path-make', sub {
739    my ($tryable) = @_;
740
741    ok my $result = $tryable->result, 'result ok';
742
743    $result; # for automated testing after the callback
744  });
745
746The test automation and document generation enabled through this framework
747makes it easy to maintain source/test/documentation parity. This also
748increases reusability and reduces the need for complicated state and test setup.
749
750=cut
751
752=head1 AUTHOR
753
754Al Newkirk, C<awncorp@cpan.org>
755
756=head1 LICENSE
757
758Copyright (C) 2011-2019, Al Newkirk, et al.
759
760This is free software; you can redistribute it and/or modify it under the terms
761of the The Apache License, Version 2.0, as elucidated in the
762L<"license file"|https://github.com/iamalnewkirk/test-auto/blob/master/LICENSE>.
763
764=head1 PROJECT
765
766L<Wiki|https://github.com/iamalnewkirk/test-auto/wiki>
767
768L<Project|https://github.com/iamalnewkirk/test-auto>
769
770L<Initiatives|https://github.com/iamalnewkirk/test-auto/projects>
771
772L<Milestones|https://github.com/iamalnewkirk/test-auto/milestones>
773
774L<Issues|https://github.com/iamalnewkirk/test-auto/issues>
775
776=cut
777