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