File Coverage

blib/lib/Test/Smart.pm
Criterion Covered Total %
statement 42 45 93.3
branch 13 16 81.2
condition 4 6 66.6
subroutine 10 10 100.0
pod 5 5 100.0
total 74 82 90.2


line stmt bran cond sub pod time code
1             package Test::Smart;
2              
3 1     1   600 use strict;
  1         2  
  1         24  
4 1     1   5 use warnings;
  1         1  
  1         43  
5              
6             our $VERSION = '0.02';
7             my $CLASS = __PACKAGE__;
8             my $interface;
9              
10 1     1   5 use base 'Test::Builder::Module';
  1         2  
  1         141  
11 1     1   5 use Test::Smart::Question;
  1         1  
  1         23  
12 1     1   430 use Test::Smart::Interface;
  1         2  
  1         625  
13              
14             our @EXPORT = qw(initialize get_yes get_no);
15             our @EXPORT_OK = qw(ask answer);
16              
17             =head1 OBSOLETE
18              
19             Test::AskAnExpert is the successor module, the name is better and there have
20             been some compatability breaking changes. You don't want this.
21              
22             =head1 NAME
23              
24             Test::Smart - Test things that require Human Intelligence automatically. (By asking someone)
25              
26             =head1 SYNOPSIS
27              
28             use Test::Smart import => [qw(ask answer)],tests => 7;
29              
30             Start up the Human Interface:
31              
32             initialize("Test::Smart::Interface::Subclass",'Subclass args'...);
33            
34             Synchronously submit and wait for a yes or a no answer:
35              
36             get_yes("Question");
37             get_no("Question");
38              
39             Same, but with timeouts: (In seconds)
40              
41             get_yes("Need a fast asnwer",10);
42             get_no("Need a fast denial",10);
43              
44             Submit an asynchronous question:
45              
46             $question = ask("This could take a while");
47              
48             Check the answer:
49              
50             answer($question,'yes');
51             answer($question,'no');
52              
53             The check can timeout too:
54              
55             answer($question,'yes',10);
56              
57             =head1 DESCRIPTION
58              
59             Test::Smart aims to fill a hole in the current set of testing tools by
60             integrating an automated method for asking testing questions that computers
61             cannot easily answer like: "Is this meteorologically sound?" or "Does this
62             output fit into category x?" or "Is this distrobution quality?" and still
63             allow standard test tools to work properly in terms of generating reports,
64             locking the doors if the tests aren't passing, etc. etc.
65              
66             Test::Smart is built on Test::Builder and will play nice with Test::Simple,
67             Test::More, and anything they play nice with. To provide Smart answers to
68             conceptual questions we cheat by asking people instead of actually solving a
69             Very Hard Problem regarding machine intelligence. This requires a little more
70             overhead as we need to set up a way to talk to people, and provide them some
71             (but not too much) time to tender an answer.
72              
73             =head2 initialize($interface_name, @interface_params)
74              
75             The initialize function must be called before using any of Test::Smart's
76             functions to load a Human Interface, otherwise the default (skip when sent
77             a query) will load. To specify something other than the default pass a subclass
78             of Test::Smart::Interface. @InterfaceParameters are any Interface specific
79             parameters, consult the documentation of the Interface you're using for what
80             (if anything) to pass here.
81              
82             On error it returns false, allowing you to try multipule Interfaces in a short-
83             circuit style before giving up:
84              
85             initialize("Test::Smart::Telepathy")
86             or initialize("Test::Smart::AskLarry",say_please=>1)
87             or skip_all("No good interfaces available");
88              
89             Note that skip_all isn't required, if no Interface is specified Test::Smart will
90             use a default Interface that simply skips if its asked to test anything.
91              
92             =cut
93              
94             sub initialize {
95 4     4 1 2413 my ($interface_name,@interface_params) = @_;
96              
97 4         499 eval " require $interface_name ";
98              
99 4 50       27 return undef if $@;
100              
101 4         23 $interface = $interface_name->load(@interface_params);
102              
103 4 50       44 return 1 if defined($interface);
104 0         0 $interface = Test::Smart::Interface->load();
105 0         0 return undef;
106             }
107              
108             =head2 get_yes/get_no ($question, $name, [$Timeout])
109              
110             Test::Smart provides two methods for the programmers who don't want to muck
111             with asynchronous interaction, get_yes and get_no. get_yes passes when the question asked
112             is answered yes, get_no the opposite. They are slim wrappers arround ask and
113             answer, taking a plain text question, test name, and optionally a timeout
114             in the same way.
115              
116             =cut
117              
118             sub get_yes {
119 4     4 1 12 my ($question,$name,$timeout) = @_;
120 4         55 my $Qobj = ask($question,$name);
121 4         16 answer($Qobj,'yes',$timeout);
122             }
123              
124             sub get_no {
125 2     2 1 5 my ($question,$name,$timeout) = @_;
126 2         5 my $Qobj = ask($question,$name);
127 2         7 answer($Qobj,'no',$timeout);
128             }
129              
130             =head2 ask($question_text, $test_name)
131              
132             B This does not actually run any tests!
133              
134             ask is a very self explanatory function: it sends a question to be answered by
135             whatever is on the other side of the Interface (Test::Smart::Pass anyone?).
136             It returns a Test::Smart::Question object which is later used for retrieving
137             the answer. Since this is the factory for Test::Smart::Question objects it also
138             optionally takes the test name the question is bound to, though this can
139             be changed with the C method. If there was an error in asking the question
140             the object will have its skip parameters set so when C is called on it
141             the test will be skipped. Read the L documentation if you'd
142             like to query the object your self and do something other than skip the test
143             (like re-initialize to a different Interface and ask again, or BAIL_OUT).
144              
145             $QuestionText should be plaintext with no markup, the Interface is expected to
146             format it nicely for the human on the other side (e.g. if its an HTML interface
147             give them nice links) to make their life a little easier.
148              
149             =cut
150              
151             sub ask {
152 7     7 1 15 my ($question,$name) = @_;
153              
154             # Ask the interface
155 7         33 my $Qobj = $interface->submit($question,$name);
156              
157 7 100 66     65 return $Qobj if defined $Qobj and $Qobj->isa('Test::Smart::Question');
158              
159             # Error! The interface has failed us! Skip this question when someone
160             # looks for the answer.
161 1         9 $Qobj = Test::Smart::Question->new(question=>$question,id=>"skip",name=>$name);
162 1         7 $Qobj->skip("Interface Error: ".$interface->err);
163 1         3 return $Qobj;
164             }
165              
166             =head2 answer($question_obj, $expected, [$timeout])
167              
168             answer takes a previously asked question and waits until an answer is ready
169             or optionally $Timeout seconds have passed and then executes typical test
170             magic.
171              
172             $QuestionObj should be a Test::Smart::Question object returned by ask or
173             correctly constructed otherwise. $Expected can be any capitalization of yes or
174             no and will be checked against the answer in the question for the test.
175              
176             =cut
177              
178             sub answer {
179 9     9 1 156 my ($Qobj,$expected,$timeout) = @_;
180 9         41 my $tb = $CLASS->builder;
181 9         394 local $Test::Builder::Level = $Test::Builder::Level + 1;
182              
183             # This should be something smarter than die in the future...
184 9 50       75 die "Expecting something other than yes or no" if $expected !~ /yes|no/i;
185              
186             # Skips
187 9 100 66     69 return $tb->skip("Invalid Question") unless defined $Qobj and $Qobj->isa('Test::Smart::Question');
188 8 100       33 return $tb->skip($Qobj->skip) if defined($Qobj->skip);
189              
190             # Wait for it..
191             # Needs timestamps
192 6         96 until($interface->has_answer($Qobj)) {
193 0         0 sleep 1;
194             }
195              
196             # Get the answer and skip on error
197 6 100       19 $interface->answer($Qobj) or return $tb->skip("Interface Error: ".$interface->err);
198              
199             # The ok call checks the answer against yes or no and takes the name provided earlier.
200 5         17 my ($answer,$comment) = $Qobj->answer;
201 5 100       20 $tb->ok($answer eq $expected,$Qobj->name) or
202             $tb->diag("Got: $answer Expected: $expected\n","Commentary: $comment\n");
203             }
204              
205             =head1 EXPORTS
206              
207             By default C and C are exported, to get C and C
208             pass import => [qw(ask answer)] to the use line.
209              
210             =head1 BUGS
211              
212             This is the first version, it probably has some. Bug reports, failing tests,
213             and patches are all welcome.
214              
215             =head1 TODO
216              
217             Timeouts. I haven't done them yet, but they'll be in the next release. I promise.
218              
219             Test::Smart::Interface::CGI and Test::Smart::Interface::DBI. These would
220             probably be more useful than the current File interface which exists more to
221             prove it can be done than anything.
222              
223             =head1 SUPPORT
224              
225             All bugs should be filed via the CPAN bug tracker at
226              
227             L
228              
229             For other issues, or commercial enhancement or support, contact the author.
230              
231             =head1 SEE ALSO
232              
233             L,L
234              
235             =head1 AUTHOR
236              
237             Edgar A. Bering, Etrizor@gmail.comE
238              
239             =head1 COPYRIGHT AND LICENSE
240              
241             Copyright (C) 2007 by Edgar A. Bering
242              
243             This library is free software; you can redistribute it and/or modify
244             it under the same terms as Perl itself, either Perl version 5.8.8 or,
245             at your option, any later version of Perl 5 you may have available.
246              
247             =cut
248              
249             1;