NAME

    Test::Auto - Test Automation

ABSTRACT

    Test Automation for Perl 5

VERSION

    0.14

SYNOPSIS

      package main;
    
      use Test::Auto;
      use Test::More;
    
      my $test = Test::Auto->new(
        't/Test_Auto.t'
      );
    
      # ...
    
      # =synopsis
      #
      # use Path::Find 'path';
      #
      # my $path = path; # get path using cwd
      #
      # =cut
    
      # $test->for('synopsis', sub {
      #   my ($tryable) = @_;
      #   ok my $result = $tryable->result;
      #
      #   # more test for the synopsis ...
      #
      #   $result
      # });
    
      # ...
    
      # $test->render('lib/Path/Find.pod');
    
      # done_testing

DESCRIPTION

    This package aims to provide, a standard for documenting Perl 5
    software projects, a framework writing tests, test automation, and
    documentation generation.

AUTOMATION

      # ...
    
      $test->for('name');

    This framework provides a set of automated subtests based on the
    package specification, but not everything can be automated so it also
    provides you with powerful hooks into the framework for manual testing.

      # ...
    
      $test->for('synopsis', sub {
        my ($tryable) = @_;
    
        ok my $result = $tryable->result, 'result ok';
    
        # must return truthy to continue
        $result;
      });

    The code examples documented can be automatically evaluated (evaled)
    and returned using a callback you provide for further testing. Because
    the code examples are returned as Venus::Try objects this makes
    capturing and testing exceptions simple, for example:

      # ...
    
      $test->for('synopsis', sub {
        my ($tryable) = @_;
    
        # catch exception thrown by the synopsis
        $tryable->catch('Path::Find::Error', sub {
          return $_[0];
        });
    
        # test the exception
        ok my $result = $tryable->result, 'result ok';
        ok $result->isa('Path::Find::Error'), 'exception caught';
    
        # must return truthy to continue
        $result;
      });

    Additionally, another manual testing hook (with some automation) is the
    example method. This hook evaluates (evals) a given example and returns
    the result as a Venus::Try object. The first argument is the example ID
    (or number), for example:

      # ...
    
      $test->for('example', 1, 'children', sub {
        my ($tryable) = @_;
    
        ok my $result = $tryable->result, 'result ok';
    
        # must return truthy to continue
        $result;
      });

    Finally, the lesser-used but useful manual testing hook is the feature
    method. This hook evaluates (evals) a documented feature and returns
    the result as a Venus::Try object, for example:

      # ...
    
      $test->for('feature', 'export-path-make', sub {
        my ($tryable) = @_;
    
        ok my $result = $tryable->result, 'result ok';
    
        # must return truthy to continue
        $result;
      });

    The test automation and documentation generation enabled through this
    framework makes it easy to maintain source/test/documentation parity.
    This also increases reusability and reduces the need for complicated
    state and test setup.

SPECIFICATION

      # Version 0.13+
    
      # [required]
    
      =name
      =abstract
      =includes
      =synopsis
      =description
    
      # [optional]
    
      =tagline
      =libraries
      =inherits
      =integrates
    
      # [optional; repeatable]
    
      =feature $name
      =example $name
    
      # [optional; repeatable]
    
      =attribute $name
      =signature $name
      =example-$number $name # [repeatable]
    
      # [optional; repeatable]
    
      =method $name
      =signature $name
      =example-$number $name # [repeatable]
    
      # [optional; repeatable]
    
      =function $name
      =signature $name
      =example-$number $name # [repeatable]
    
      # [optional; repeatable]
    
      =routine $name
      =signature $name
      =example-$number $name # [repeatable]

    The specification is designed to accommodate typical package
    declarations. It is used by the parser to provide the content used in
    test automation and document generation. Note: When code blocks are
    evaluated, the "redefined" warnings are now automatically disabled.

 name

      =name
    
      Path::Find
    
      =cut
    
      $test->for('name');

    The name block should contain the package name. This is tested for
    loadability.

 tagline

      =tagline
    
      Path Finder
    
      =cut
    
      $test->for('tagline');

    The tagline block should contain a tagline for the package. This is
    optional but if present is concatenated with the name during POD
    generation.

 abstract

      =abstract
    
      Find Paths using Heuristics
    
      =cut
    
      $test->for('abstract');

    The abstract block should contain a subtitle describing the package.
    This is tested for existence.

 includes

      =includes
    
      function: path
      method: children
      method: siblings
      method: new
    
      =cut
    
      $test->for('includes');

    The includes block should contain a list of function, method, and/or
    routine names in the format of $type: $name. Empty lines are ignored.
    This is tested for existence. Each function, method, and/or routine is
    tested to be documented properly, i.e. has the requisite counterparts
    (e.g. signature and at least one example block). Also, the package must
    recognize that each exists.

 synopsis

      =synopsis
    
      use Path::Find 'path';
    
      my $path = path; # get path using cwd
    
      =cut
    
      $test->for('synopsis', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    The synopsis block should contain the normative usage of the package.
    This is tested for existence. This block should be written in a way
    that allows it to be evaled successfully and should return a value.

 description

      =description
    
      interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis
      tristique sollicitudin nibh sit amet
    
      =cut
    
      $test->for('description');

    The description block should contain a thorough explanation of the
    purpose of the package. This is tested for existence.

 libraries

      =libraries
    
      Types::Standard
      Types::TypeTiny
    
      =cut
    
      $test->for('libraries');

    The libraries block should contain a list of packages, each of which is
    itself a Type::Library. These packages are tested for loadability, and
    to ensure they are type library classes.

 inherits

      =inherits
    
      Path::Tiny
    
      =cut
    
      $test->for('inherits');

    The inherits block should contain a list of parent packages. These
    packages are tested for loadability.

 integrates

      =integrates
    
      Path::Find::Upable
      Path::Find::Downable
    
      =cut
    
      $test->for('integrates');

    The integrates block should contain a list of packages that are
    involved in the behavior of the main package. These packages are not
    automatically tested.

 features

      =feature export-path-make
    
      quisque egestas diam in arcu cursus euismod quis viverra nibh
    
      =example export-path-make
    
      # given: synopsis
    
      package main;
    
      use Path::Find 'path_make';
    
      path_make 'relpath/to/file';
    
      =cut
    
      $test->for('example', 'export-path-make', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    There are situation where a package can be configured in different
    ways, especially where it exists without functions, methods or routines
    for the purpose of configuring the environment. The feature directive
    can be used to automate testing and documenting package usages and
    configurations. Describing a feature requires two blocks, i.e. feature
    $name and example $name. The feature block should contain a description
    of the feature and its purpose. The example block must exist when
    documenting a feature and should contain valid Perl code and return a
    value. The block may contain a "magic" comment in the form of given:
    synopsis or given: example $name which if present will include the
    given code example(s) with the evaluation of the current block. Each
    feature is tested and must be recognized to exist by the main package.

 attributes

      =attribute cwd
    
      quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat
    
      =signature cwd
    
      cwd(Str $path) : (Object)
    
      =cut
    
      =example-1 cwd
    
      # given: synopsis
    
      my $cwd = $path->cwd;
    
      =cut
    
      $test->for('example', 1, 'cwd', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });
    
      =example-2 cwd
    
      # given: synopsis
    
      my $cwd = $path->cwd('/path/to/file');
    
      =cut
    
      $test->for('example', 2, 'cwd', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    Describing an attribute requires at least three blocks, i.e. attribute
    $name, signature $name, and example-1 $name. The attribute block should
    contain a description of the attribute and its purpose. The signature
    block should contain a routine signature in the form of $signature :
    $return_type, where $signature is a valid typed signature and
    $return_type is any valid Type::Tiny expression. The example-$number
    block is a repeatable block, and at least one block must exist when
    documenting an attribute. The example-$number block should contain
    valid Perl code and return a value. The block may contain a "magic"
    comment in the form of given: synopsis or given: example-$number $name
    which if present will include the given code example(s) with the
    evaluation of the current block. Each attribute is tested and must be
    recognized to exist by the main package.

 methods

      =method children
    
      quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat
    
      =signature children
    
      children() : [Object]
    
      =cut
    
      =example-1 children
    
      # given: synopsis
    
      my $children = $path->children;
    
      =cut
    
      $test->for('example', 1, 'children', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });
    
      =example-2 children
    
      # given: synopsis
    
      my $filtered = $path->children(qr/lib/);
    
      =cut
    
      $test->for('example', 2, 'children', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    Describing a method requires at least three blocks, i.e. method $name,
    signature $name, and example-1 $name. The method block should contain a
    description of the method and its purpose. The signature block should
    contain a method signature in the form of $signature : $return_type,
    where $signature is a valid typed signature and $return_type is any
    valid Type::Tiny expression. The example-$number block is a repeatable
    block, and at least one block must exist when documenting a method. The
    example-$number block should contain valid Perl code and return a
    value. The block may contain a "magic" comment in the form of given:
    synopsis or given: example-$number $name which if present will include
    the given code example(s) with the evaluation of the current block.
    Each method is tested and must be recognized to exist by the main
    package.

 functions

      =function path
    
      lectus quam id leo in vitae turpis massa sed elementum tempus egestas
    
      =signature children
    
      path() : Object
    
      =cut
    
      =example-1 path
    
      package Test::Path::Find;
    
      use Path::Find;
    
      my $path = path;
    
      =cut
    
      $test->for('example', 1, 'path', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    Describing a function requires at least three blocks, i.e. function
    $name, signature $name, and example-1 $name. The function block should
    contain a description of the function and its purpose. The signature
    block should contain a function signature in the form of $signature :
    $return_type, where $signature is a valid typed signature and
    $return_type is any valid Type::Tiny expression. The example-$number
    block is a repeatable block, and at least one block must exist when
    documenting a function. The example-$number block should contain valid
    Perl code and return a value. The block may contain a "magic" comment
    in the form of given: synopsis or given: example-$number $name which if
    present will include the given code example(s) with the evaluation of
    the current block. Each function is tested and must be recognized to
    exist by the main package.

 routines

      =routine algorithms
    
      sed sed risus pretium quam vulputate dignissim suspendisse in est ante
    
      =signature algorithms
    
      algorithms() : Object
    
      =cut
    
      =example-1 algorithms
    
      # given: synopsis
    
      $path->algorithms
    
      =cut
    
      $test->for('example', 1, 'algorithms', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });
    
      =example-2 algorithms
    
      package Test::Path::Find;
    
      use Path::Find;
    
      Path::Find->algorithms;
    
      =cut
    
      $test->for('example', 2, 'algorithms', sub {
        my ($tryable) = @_;
        my $result = $tryable->result;
    
        # must return truthy to continue
        $result
      });

    Typically, a Perl subroutine is declared as a function or a method.
    Rarely, but sometimes necessary, you will need to describe a subroutine
    where the invocant is either a class or class instance. Describing a
    routine requires at least three blocks, i.e. routine $name, signature
    $name, and example-1 $name. The routine block should contain a
    description of the routine and its purpose. The signature block should
    contain a routine signature in the form of $signature : $return_type,
    where $signature is a valid typed signature and $return_type is any
    valid Type::Tiny expression. The example-$number block is a repeatable
    block, and at least one block must exist when documenting a routine.
    The example-$number block should contain valid Perl code and return a
    value. The block may contain a "magic" comment in the form of given:
    synopsis or given: example-$number $name which if present will include
    the given code example(s) with the evaluation of the current block.
    Each routine is tested and must be recognized to exist by the main
    package.

INHERITS

    This package inherits behaviors from:

    Venus::Test

FUNCTIONS

    This package provides the following functions:

 test

      test(Str $file) (Auto)

    The test function takes a file path and returns a Test::Auto object for
    use in test automation and documentation rendering. This function is
    exported automatically unless a routine of the same name already exists
    in the calling package.

    Since 0.13

    test example 1

        # given: synopsis
      
        $test = test('t/Test_Auto.t');
      
        # =synopsis
        #
        # use Path::Find 'path';
        #
        # my $path = path; # get path using cwd
        #
        # =cut
      
        # $test->for('synopsis', sub {
        #   my ($tryable) = @_;
        #   ok my $result = $tryable->result;
        #
        #   # more test for the synopsis ...
        #
        #   $result
        # });
      
        # ...
      
        # $test->render('lib/Path/Find.pod');
      
        # done_testing

METHODS

    This package provides the following methods:

 data

      data(Str $name, Any @args) (Str)

    The data method attempts to find and return the POD content based on
    the name provided. If the content cannot be found an exception is
    raised.

    Since 0.13

    data example 1

        # given: synopsis
      
        my $data = $test->data('name');
      
        # Test::Auto

    data example 2

        # given: synopsis
      
        my $data = $test->data('unknown');
      
        # Exception! isa (Test::Auto::Error)

 for

      for(Str $name | CodeRef $code, Any @args) (Any)

    The for method attempts to find the POD content based on the name
    provided and executes the corresponding predefined test, optionally
    accepting a callback which, if provided, will be passes a Venus::Try
    object containing the POD-driven test. The callback, if provided, must
    always return a true value. Note: All automated tests disable the
    "redefine" class of warnings to prevent warnings when redeclaring
    packages in examples.

    Since 0.13

    for example 1

        # given: synopsis
      
        my $data = $test->for('name');
      
        # Test::Auto

    for example 2

        # given: synopsis
      
        my $data = $test->for('synopsis');
      
        # bless({value => 't/Test_Auto.t'}, 'Test::Auto')

    for example 3

        # given: synopsis
      
        my $data = $test->for('example', 1, 'data', sub {
          my ($tryable) = @_;
          my $result = $tryable->result;
          ok length($result) > 1;
      
          $result
        });
      
        # Test::Auto

 render

      render(Str $file) (Path)

    The render method renders and writes a valid POD document, and returns
    a Venus::Path object representation the POD file specified.

    Since 0.13

    render example 1

        # given: synopsis
      
        my $path = $test->render('t/Path_Find.pod');
      
        # bless({value => 't/Path_Find.pod', 'Venus::Path'})

AUTHORS

    Awncorp, awncorp@cpan.org