5 Test::Builder - Parrot extension for building test modules
10 load_bytecode 'Test/Builder.pbc'
12 # create a new Test::Builder object
15 test = new [ 'Test'; 'Builder' ]
17 # plan to run ten tests
20 test.'ok'( 1, 'some test description' )
21 test.'ok'( 0, 'some test description' )
22 test.'diag'( 'the last test failed on purpose!' )
24 test.'skip'( 3, 'do not run these three tests' )
25 test.'todo'( 1, 'this is a todo test that passes', 'i am not sure' )
26 test.'todo'( 0, 'this is a todo test that fails', ' i am still not sure' )
28 test.'skip'( 4, 'cannot think of four more tests' )
30 # you must call this when you have finished!
35 Test::Builder is a pure-Parrot library for building test modules. It manages
36 test plans, formats and reports test results correctly, and has methods to
37 manage passing, failing, skip, and TODO tests. It provides a simple, single
38 backend for multiple test modules to use within your tests.
42 This class defines the following methods:
48 .namespace [ 'Test'; 'Builder' ]
50 .sub '_initialize' :load
51 load_bytecode 'Test/Builder/Test.pbc'
52 load_bytecode 'Test/Builder/Output.pbc'
53 load_bytecode 'Test/Builder/TestPlan.pbc'
57 newclass tb_class, [ 'Test'; 'Builder' ]
58 addattribute tb_class, 'output'
59 addattribute tb_class, 'testplan'
60 addattribute tb_class, 'results'
65 set_hll_global [ 'Test'; 'Builder'; '_singleton' ], 'singleton', single
68 =item C<new( args_hash )>
70 Given an optional C<Hash> of arguments, initializes the new object with the
71 provided arguments. By default, you should rarely need to pass any arguments.
72 If you do, you know why. The two allowed arguments are:
78 An object that C<does> C<Test::Builder::TestPlan> to manage the plan for this
83 An object that does C<Test::Builder::Output> to manage the output for this test
88 C<new()> will not always return the I<same> object, but every object will share
93 .sub 'init' :vtable :method
99 (output, testplan, results) = self.'_assign_default_args'( args )
100 self.'_assign_args'( output, testplan, results )
103 .sub 'init_pmc' :vtable :method
109 (output, testplan, results) = self.'_assign_default_args'( args )
110 self.'_assign_args'( output, testplan, results )
113 .sub '_assign_args' :method
118 setattribute self, 'output', output
119 setattribute self, 'testplan', testplan
120 setattribute self, 'results', results
122 results = self.'results'()
125 =item C<create( args_hash )>
127 Creates and returns a new Test::Builder object with different backend objects.
128 This probably doesn't work correctly yet, but you will probably never use it.
139 .local int is_defined
140 output = args['output']
141 is_defined = exists args['output']
142 if is_defined goto OUTPUT_DEFINED
144 .local int output_class
145 output = new [ 'Test'; 'Builder'; 'Output' ]
148 is_defined = exists args['testplan']
149 unless is_defined goto DEFAULT_TESTPLAN
151 testplan = args['testplan']
152 goto TESTPLAN_DEFINED
155 testplan = new [ 'Test'; 'Builder'; 'TestPlan' ]
158 results = new 'ResizablePMCArray'
161 test = new [ 'Test'; 'Builder' ]
163 test.'_assign_args'( output, testplan, results )
167 .sub '_assign_default_args' :method
171 single = get_hll_global [ 'Test'; 'Builder'; '_singleton' ], 'singleton'
176 .local int is_defined
178 # try for the global first
179 is_defined = isa single, [ 'Test'; 'Builder' ]
180 unless is_defined goto CREATE_ATTRIBUTES
182 output = single.'output'()
183 testplan = single.'testplan'()
184 results = single.'results'()
189 # now look in the args hash
190 is_defined = exists args['output']
191 unless is_defined goto CREATE_OUTPUT
192 output = args['output']
196 # create a Test::Builder::Output object
198 args_hash = new 'Hash'
199 output = new [ 'Test'; 'Builder'; 'Output' ], args_hash
202 # now try in the args hash
203 is_defined = exists args['testplan']
204 unless is_defined goto CREATE_TESTPLAN
205 testplan = args['testplan']
206 goto TESTPLAN_DEFINED
209 testplan = new [ 'Test'; 'Builder'; 'TestPlan' ]
212 is_defined = defined results
213 if is_defined goto RESULTS_DEFINED
214 results = new 'ResizablePMCArray'
216 # store this as the singleton
217 set_hll_global [ 'Test'; 'Builder'; '_singleton' ], 'singleton', self
220 .return( output, testplan, results )
223 .sub 'output' :method
226 getattribute output, self, "output"
231 .sub 'testplan' :method
233 testplan = getattribute self, 'testplan'
237 .sub 'results' :method
240 getattribute results, self, "results"
247 Finishes this test run. You should call this when you have finished running
248 all of the tests. I know this is awful, but this has to be here until object
249 finalization works reliably.
251 This is probably not idempotent now, so try not to call it too many times,
252 where "too many" means "more than one".
256 .sub 'finish' :method
261 output = self.'output'()
262 testplan = self.'testplan'()
263 results = self.'results'()
269 footer = testplan.'footer'( elements )
271 .local int is_defined
272 is_defined = length footer
273 unless is_defined goto DONE_PRINTING
274 output.'write'( footer )
278 # XXX - delete globals
281 =item C<plan( number_or_no_plan )>
283 Tells the object how many tests to run, either an integer greater than zero or
284 the string C<no_plan>. This will throw an exception if you have already
285 declared a plan or if you pass an invalid argument.
293 testplan = self.'testplan'()
295 eq tests, 'no_plan', write_header
300 unless num_tests goto write_header
302 testplan.'set_tests'( num_tests )
306 output = self.'output'()
309 header = testplan.'header'()
310 output.'write'( header )
319 .sub 'done_testing' :method
320 .param string tests :optional
321 .param int has_tests :opt_flag
324 testplan = self.'testplan'()
326 unless has_tests goto write_footer
330 unless num_tests goto write_footer
332 testplan.'set_tests'( num_tests )
336 output = self.'output'()
338 $S0 = testplan.'header'()
339 output.'write'( $S0 )
341 $I0 = self.'results'()
342 $S0 = testplan.'footer'( $I0 )
343 output.'write'( $S0 )
347 =item C<diag( diagnostic_message, ... )>
349 Records a diagnostic message for output.
354 .param pmc args :slurpy
357 output = self.'output'()
358 .tailcall output.'diag'( args :flat )
361 =item C<ok( passed, description )>
363 Records a test as pass or fail depending on the truth of the integer C<passed>,
364 recording it with the optional test description in C<description>.
370 .param pmc description :optional
371 .param int has_description :opt_flag
373 if has_description goto OK
374 description = new 'String'
379 results = self.'results'()
381 .local int results_count
382 results_count = results
386 test_args = new 'Hash'
387 test_args['number'] = results_count
388 test_args['passed'] = passed
389 test_args['description'] = description
391 self.'report_test'( test_args )
396 =item C<todo( passed, description, reason )>
398 Records a test as pass or fail based on the truth of the integer C<passed>, but
399 marks it as TODO so it always appears as a success. This also records the
400 optional C<description> of the test and the C<reason> you have marked it as
407 .param string description :optional
408 .param int has_description :opt_flag
409 .param string reason :optional
410 .param int has_reason :opt_flag
412 if has_description goto CHECK_REASON
416 if has_reason goto TODO
421 results = self.'results'()
423 .local int results_count
424 results_count = results
428 test_args = new 'Hash'
429 test_args['todo'] = 1
430 test_args['number'] = results_count
431 test_args['passed'] = passed
432 test_args['reason'] = reason
433 test_args['description']= description
435 self.'report_test'( test_args )
440 =item C<skip( number reason )>
442 Records C<number> of tests as skip tests, using the optional C<reason> to mark
443 why you've skipped them.
448 .param int number :optional
449 .param int has_number :opt_flag
450 .param string reason :optional
451 .param int has_reason :opt_flag
453 if has_number goto CHECK_NUMBER
457 if number > 0 goto CHECK_REASON
458 .return() # nothing to skip
461 if has_reason goto SKIP_LOOP
466 results = self.'results'()
468 .local int results_count
469 results_count = results
471 .local int loop_count
478 test_args = new 'Hash'
479 test_args['number'] = results_count
480 test_args['skip'] = 1
481 test_args['reason'] = reason
483 self.'report_test'( test_args )
485 if loop_count <= number goto LOOP
491 Skips all of the tests in a test file. You cannot call this if you have a
492 plan. This calls C<exit>; there's little point in continuing.
496 .sub 'skip_all' :method
498 testplan = self.'testplan'()
500 unless testplan goto SKIP_ALL
502 .local pmc plan_exception
503 plan_exception = new 'Exception'
504 plan_exception = 'Cannot skip_all() with a plan!'
509 output = self.'output'()
510 output.'write'( "1..0" )
514 =item C<BAILOUT( reason )>
516 Ends the test immediately, giving the string C<reason> as explanation. This
521 .sub 'BAILOUT' :method
522 .param string reason :optional
523 .param int has_reason :opt_flag
526 output = self.'output'()
529 bail_out = new ['StringBuilder']
530 bail_out = 'Bail out!'
532 unless has_reason goto WRITE_REASON
537 output.'write'( bail_out )
542 .sub 'report_test' :method
546 testplan = self.'testplan'()
549 results = self.'results'()
554 number = new 'Integer'
561 test_args['number'] = number
565 .local pmc tbt_create
566 get_hll_global tbt_create, [ 'Test'; 'Builder'; 'Test' ], 'create'
567 test = tbt_create( test_args )
570 output = self.'output'()
573 report = test.'report'()
575 output.'write'( report )
582 Written and maintained by chromatic, C<< chromatic at wgz dot org >>, based on
583 the Perl 6 port he wrote, based on the original Perl 5 version he wrote with
584 ideas from Michael G. Schwern. Please send patches, feedback, and suggestions
585 to the Perl 6 internals mailing list.
589 Copyright (C) 2005-2008, Parrot Foundation.
597 # vim: expandtab shiftwidth=4 ft=pir: