xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Simple/lib/Test/Builder/Module.pm (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1package Test::Builder::Module;
2
3use strict;
4
5use Test::Builder 1.00;
6
7require Exporter;
8our @ISA = qw(Exporter);
9
10our $VERSION = '1.001014';
11$VERSION = eval $VERSION;      ## no critic (BuiltinFunctions::ProhibitStringyEval)
12
13
14=head1 NAME
15
16Test::Builder::Module - Base class for test modules
17
18=head1 SYNOPSIS
19
20  # Emulates Test::Simple
21  package Your::Module;
22
23  my $CLASS = __PACKAGE__;
24
25  use base 'Test::Builder::Module';
26  @EXPORT = qw(ok);
27
28  sub ok ($;$) {
29      my $tb = $CLASS->builder;
30      return $tb->ok(@_);
31  }
32
33  1;
34
35
36=head1 DESCRIPTION
37
38This is a superclass for L<Test::Builder>-based modules.  It provides a
39handful of common functionality and a method of getting at the underlying
40L<Test::Builder> object.
41
42
43=head2 Importing
44
45Test::Builder::Module is a subclass of L<Exporter> which means your
46module is also a subclass of Exporter.  @EXPORT, @EXPORT_OK, etc...
47all act normally.
48
49A few methods are provided to do the C<< use Your::Module tests => 23 >> part
50for you.
51
52=head3 import
53
54Test::Builder::Module provides an C<import()> method which acts in the
55same basic way as L<Test::More>'s, setting the plan and controlling
56exporting of functions and variables.  This allows your module to set
57the plan independent of L<Test::More>.
58
59All arguments passed to C<import()> are passed onto
60C<< Your::Module->builder->plan() >> with the exception of
61C<< import =>[qw(things to import)] >>.
62
63    use Your::Module import => [qw(this that)], tests => 23;
64
65says to import the functions C<this()> and C<that()> as well as set the plan
66to be 23 tests.
67
68C<import()> also sets the C<exported_to()> attribute of your builder to be
69the caller of the C<import()> function.
70
71Additional behaviors can be added to your C<import()> method by overriding
72C<import_extra()>.
73
74=cut
75
76sub import {
77    my($class) = shift;
78
79    # Don't run all this when loading ourself.
80    return 1 if $class eq 'Test::Builder::Module';
81
82    my $test = $class->builder;
83
84    my $caller = caller;
85
86    $test->exported_to($caller);
87
88    $class->import_extra( \@_ );
89    my(@imports) = $class->_strip_imports( \@_ );
90
91    $test->plan(@_);
92
93    $class->export_to_level( 1, $class, @imports );
94}
95
96sub _strip_imports {
97    my $class = shift;
98    my $list  = shift;
99
100    my @imports = ();
101    my @other   = ();
102    my $idx     = 0;
103    while( $idx <= $#{$list} ) {
104        my $item = $list->[$idx];
105
106        if( defined $item and $item eq 'import' ) {
107            push @imports, @{ $list->[ $idx + 1 ] };
108            $idx++;
109        }
110        else {
111            push @other, $item;
112        }
113
114        $idx++;
115    }
116
117    @$list = @other;
118
119    return @imports;
120}
121
122=head3 import_extra
123
124    Your::Module->import_extra(\@import_args);
125
126C<import_extra()> is called by C<import()>.  It provides an opportunity for you
127to add behaviors to your module based on its import list.
128
129Any extra arguments which shouldn't be passed on to C<plan()> should be
130stripped off by this method.
131
132See L<Test::More> for an example of its use.
133
134B<NOTE> This mechanism is I<VERY ALPHA AND LIKELY TO CHANGE> as it
135feels like a bit of an ugly hack in its current form.
136
137=cut
138
139sub import_extra { }
140
141=head2 Builder
142
143Test::Builder::Module provides some methods of getting at the underlying
144Test::Builder object.
145
146=head3 builder
147
148  my $builder = Your::Class->builder;
149
150This method returns the L<Test::Builder> object associated with Your::Class.
151It is not a constructor so you can call it as often as you like.
152
153This is the preferred way to get the L<Test::Builder> object.  You should
154I<not> get it via C<< Test::Builder->new >> as was previously
155recommended.
156
157The object returned by C<builder()> may change at runtime so you should
158call C<builder()> inside each function rather than store it in a global.
159
160  sub ok {
161      my $builder = Your::Class->builder;
162
163      return $builder->ok(@_);
164  }
165
166
167=cut
168
169sub builder {
170    return Test::Builder->new;
171}
172
1731;
174