Index: runtime/parrot/library/Test/Builder.pir
===================================================================
--- runtime/parrot/library/Test/Builder.pir	(revision 10141)
+++ runtime/parrot/library/Test/Builder.pir	(working copy)
@@ -144,22 +144,22 @@
 	is_defined = exists args['testplan']
 	unless is_defined goto DEFAULT_TESTPLAN
 
-  	testplan   = args['testplan']
+	testplan   = args['testplan']
 	goto TESTPLAN_DEFINED
 
   DEFAULT_TESTPLAN:
 	testplan   = new .String
-	set testplan, ''
+	testplan   = ''
 
   TESTPLAN_DEFINED:
 
-    results    = new .ResizablePMCArray
+	results    = new .ResizablePMCArray
 	.local int test_builder_type
 
 	find_type test_builder_type, 'Test::Builder'
 	.local pmc real_init
 	.local pmc blank_init
-	real_init = find_global 'Test::Builder', '__init'
+	real_init  = find_global 'Test::Builder', '__init'
 	blank_init = find_global 'Test::Builder', '__fake_init'
 	store_global 'Test::Builder', '__init', blank_init
 
@@ -175,7 +175,7 @@
 	.param pmc args
 
 	.local pmc single
-	single = find_global 'Test::Builder::_singleton', 'singleton'
+	single     = find_global 'Test::Builder::_singleton', 'singleton'
 
 	.local pmc output
 	.local pmc testplan
@@ -186,9 +186,9 @@
 	is_defined = isa single, 'Test::Builder'
 	unless is_defined goto CREATE_ATTRIBUTES
 
-	output   = single.'output'()
-	testplan = single.'testplan'()
-	results  = single.'results'()
+	output     = single.'output'()
+	testplan   = single.'testplan'()
+	results    = single.'results'()
 
 	goto RESULTS_DEFINED
 
@@ -212,15 +212,15 @@
 	# now try in the args hash
 	is_defined = exists args['testplan']
 	unless is_defined goto CREATE_TESTPLAN
-	testplan = args['testplan']
+	testplan   = args['testplan']
 	goto TESTPLAN_DEFINED
 
   CREATE_TESTPLAN:
 	testplan   = new .String
-	set testplan, 'global_testplan'
+	testplan   = 'global_testplan'
 
   TESTPLAN_DEFINED:
-  	is_defined = defined results
+	is_defined = defined results
 	if is_defined goto RESULTS_DEFINED
 	results    = new .ResizablePMCArray
 
@@ -258,7 +258,7 @@
 	.local pmc results
 
 	classoffset offset, self, 'Test::Builder'
-	add offset, 2
+	offset += 2
 	getattribute results, self, offset
 
 	.return( results )
@@ -309,8 +309,7 @@
 =cut
 
 .sub plan method
-	.param string explanation
-	.param int    tests
+	.param string tests
 
 	.local pmc testplan
 	testplan = self.'testplan'()
@@ -322,7 +321,7 @@
 	.local int is_plan
 
 	is_plan = isa testplan, 'Test::Builder::TestPlan'
-	eq is_plan, 1, CHECK_REPLAN
+	if is_plan == 1 goto CHECK_REPLAN
 	eq_str testplan, 'global_testplan', SET_GLOBAL_TESTPLAN
 	goto CHECK_REPLAN
 
@@ -338,24 +337,28 @@
 
 	.local pmc plan_exception
 	plan_exception = new .Exception
-	set   plan_exception['_message'], 'Plan already set!'
+	plan_exception['_message'] = 'Plan already set!'
 	throw plan_exception
 
   CHECK_TESTNUM:
-	unless tests goto CHECK_EXPLANATION
+	if tests == 'no_plan' goto PLAN_NULL
 
+	.local int num_tests
+	num_tests = tests
+
+	unless num_tests goto PLAN_FAILURE
+
 	.local int plan_type
 	.local pmc args
 
 	args = new .Hash
-	set args['expect'], tests
+	args['expect'] = num_tests
 
 	find_type plan_type, 'Test::Builder::TestPlan'
 	testplan = new plan_type, args
 	goto FINISH_PLAN
 
   CHECK_EXPLANATION:
-	eq_str explanation, 'no_plan', PLAN_NULL
 	goto PLAN_FAILURE
 
   PLAN_NULL:
@@ -367,7 +370,7 @@
   PLAN_FAILURE:
 	.local pmc plan_exception
 	plan_exception = new .Exception
-	set   plan_exception['_message'], 'Unknown test plan!'
+	plan_exception['_message'] = 'Unknown test plan!'
 	throw plan_exception
 
   FINISH_PLAN:
@@ -415,8 +418,13 @@
 
 .sub ok method
 	.param int    passed
-	.param string description
+	.param string description     :optional
+	.param int    has_description :opt_flag
 
+	if has_description goto OK
+	description = ''
+
+  OK:
 	.local pmc results
 	results = self.'results'()
 
@@ -426,9 +434,9 @@
 
 	.local pmc test_args
 	test_args = new .Hash
-	set test_args['number'],      results_count
-	set test_args['passed'],      passed
-	set test_args['description'], description
+	test_args['number']      = results_count
+	test_args['passed']      = passed
+	test_args['description'] = description
 
 	self.'report_test'( test_args )
 
@@ -446,9 +454,19 @@
 
 .sub todo method
 	.param int    passed
-	.param string description
-	.param string reason
+	.param string description     :optional
+	.param int    has_description :opt_flag
+	.param string reason          :optional
+	.param int    has_reason      :opt_flag
 
+	if has_description goto CHECK_REASON
+	description = ''
+
+  CHECK_REASON:
+	if has_reason goto TODO
+	reason = ''
+
+  TODO:
 	.local pmc results
 	results = self.'results'()
 
@@ -458,11 +476,11 @@
 
 	.local pmc test_args
 	test_args = new .Hash
-	set test_args['todo'],        1
-	set test_args['number'],      results_count
-	set test_args['passed'],      passed
-	set test_args['reason'],      reason
-	set test_args['description'], description
+	test_args['todo']       = 1
+	test_args['number']     = results_count
+	test_args['passed']     = passed
+	test_args['reason']     = reason
+	test_args['description']= description
 
 	self.'report_test'( test_args )
 
@@ -477,15 +495,21 @@
 =cut
 
 .sub skip method
-	.param int    number
-	.param string reason
+	.param int    number          :optional
+	.param int    has_number      :opt_flag
+	.param string reason          :optional
+	.param int    has_reason      :opt_flag
 
-	if number goto CHECK_REASON
+	if has_number goto CHECK_NUMBER
 	number = 1
 
+  CHECK_NUMBER:
+	if number > 0 goto CHECK_REASON
+	.return() # nothing to skip
+
   CHECK_REASON:
-    if reason goto SKIP_LOOP
-	set reason, 'skipped'
+    if has_reason goto SKIP_LOOP
+	reason = 'skipped'
 
   SKIP_LOOP:
 	.local pmc results
@@ -502,9 +526,9 @@
 
 	.local pmc test_args
 	test_args = new .Hash
-	set test_args['number'], results_count
-	set test_args['skip'],   1
-	set test_args['reason'], reason
+	test_args['number'] = results_count
+	test_args['skip']   = 1
+	test_args['reason'] = reason
 
 	self.'report_test'( test_args )
 	inc loop_count
@@ -527,7 +551,7 @@
 
 	.local pmc plan_exception
 	plan_exception = new .Exception
-	set   plan_exception['_message'], 'Cannot skip_all() with a plan!'
+	plan_exception['_message'] = 'Cannot skip_all() with a plan!'
 	throw plan_exception
 
   SKIP_ALL:
@@ -545,17 +569,18 @@
 =cut
 
 .sub BAILOUT method
-	.param string reason
+	.param string reason  :optional
+	.param int has_reason :opt_flag
 
   	.local pmc output
-	output  = self.'output'()
+	output   = self.'output'()
 
 	.local string bail_out
 	bail_out = 'Bail out!'
 
-	unless reason goto WRITE_REASON
-	concat bail_out, '  '
-	concat bail_out, reason
+	unless has_reason goto WRITE_REASON
+	bail_out .= '  '
+	bail_out .= reason
 
   WRITE_REASON:
 	output.'write'( bail_out )
@@ -575,7 +600,7 @@
 
 	.local pmc plan_exception
 	plan_exception = new .Exception
-	set   plan_exception['_message'], 'No plan set!'
+	plan_exception['_message'] = 'No plan set!'
 	throw plan_exception
 
   CREATE_TEST:
@@ -592,7 +617,7 @@
 	number = count
 	inc number
 
-	set test_args['number'], number
+	test_args['number'] = number
 
 	push results, test
 
Index: runtime/parrot/library/Test/Builder/TestPlan.pir
===================================================================
--- runtime/parrot/library/Test/Builder/TestPlan.pir	(revision 10141)
+++ runtime/parrot/library/Test/Builder/TestPlan.pir	(working copy)
@@ -45,13 +45,17 @@
 =cut
 
 .sub __init method
-	.param pmc args
+	.param pmc args     :optional
+	.param int has_args :opt_flag
 
+	unless has_args goto NULL_PLAN
+
 	.local int valid_args
 	valid_args = isa args, 'Hash'
 	if valid_args goto CHECK_ARGS
 
 	# hope this is for Test::Builder::NullPlan
+  NULL_PLAN:
 	.return()
 
   CHECK_ARGS:
Index: MANIFEST
===================================================================
--- MANIFEST	(revision 10141)
+++ MANIFEST	(working copy)
@@ -1783,6 +1783,7 @@
 t/library/perlhist.txt                            []
 t/library/sort.t                                  []
 t/library/streams.t                               []
+t/library/test_builder.t                          []
 t/library/yaml_parser_syck.t                      []
 t/native_pbc/header.t                             []
 t/native_pbc/integer.t                            []
Index: t/library/test_builder.t
===================================================================
--- t/library/test_builder.t	(revision 0)
+++ t/library/test_builder.t	(revision 0)
@@ -0,0 +1,468 @@
+#! perl
+# Copyright: 2001-2005 The Perl Foundation.  All Rights Reserved.
+# $Id$
+
+use strict;
+use warnings;
+use lib qw( . lib ../lib ../../lib );
+use Test::More;
+use Parrot::Test;
+
+
+=head1 NAME
+
+t/library/test_builder.t - Test::Builder tests
+
+=head1 SYNOPSIS
+
+	% prove t/library/test_builder.t
+
+=cut
+
+
+my $lib= 'Test/Builder.pir';
+my $ns= 'Test::Builder';
+my @methods= qw/
+	output testplan results finish plan diag 
+	ok todo skip skip_all BAILOUT report_test
+/;
+
+my $PRE=<<PRE;
+.sub 'main' :main
+    load_bytecode "$lib"
+
+	.local pmc test
+	.local int class_type
+
+	class_type = find_type "$ns"
+	test = new class_type
+
+PRE
+
+my $POST=<<'POST';
+
+	goto OK
+NOK:print "not "
+OK: print "ok\n"
+END:
+.end
+POST
+
+
+## 1
+pir_output_is(<<CODE.$POST, <<'OUT', "load_bytecode");
+.sub 'main' :main
+    load_bytecode "$lib"
+CODE
+ok
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "new - isa");
+	.local int isa_builder
+	isa_builder = isa test, "$ns"
+	unless isa_builder goto NOK
+CODE
+ok
+OUT
+
+
+for my $method ( @methods )
+{
+	pir_output_is($PRE.<<CODE.$POST, <<'OUT', "can do '$method'");
+	\$I0 = can test, '$method'
+	unless \$I0 goto NOK
+CODE
+ok
+OUT
+}
+
+
+## TODO: output testplan results finish
+
+
+## plan
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "plan 1 - valid");
+	test.'plan'(1)
+
+	test.'ok'(1)
+
+	test.'finish'()
+	goto END
+CODE
+1..1
+ok 1
+OUT
+
+
+pir_output_like($PRE.<<CODE.$POST, <<'OUT', "plan 0 - invalid");
+	test.'plan'(0)
+	test.'finish'()
+	goto END
+CODE
+/Unknown test plan!/
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "no_plan - valid");
+	test.'plan'('no_plan')
+	test.'finish'()
+	goto END
+CODE
+1..0
+OUT
+
+
+## ok
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "ok");
+	test.'plan'(4)
+
+	test.'ok'(0)
+	test.'ok'(0, 'ok with description')
+	test.'ok'(1)
+	test.'ok'(1, 'ok with description')
+
+	test.'finish'()
+	goto END
+CODE
+1..4
+not ok 1
+not ok 2 - ok with description
+ok 3
+ok 4 - ok with description
+OUT
+
+
+## todo
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "todo");
+	test.'plan'(6)
+
+	test.'todo'(0)
+	test.'todo'(0, 'todo with description')
+	test.'todo'(0, 'todo with description', 'testing reason')
+	test.'todo'(1)
+	test.'todo'(1, 'todo with description')
+	test.'todo'(1, 'todo with description', 'testing reason')
+
+	test.'finish'()
+	goto END
+CODE
+1..6
+not ok 1 # TODO
+not ok 2 # TODO todo with description
+not ok 3 # TODO todo with description
+ok 4 # TODO
+ok 5 # TODO todo with description
+ok 6 # TODO todo with description
+OUT
+
+
+## diag
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "diag after ok");
+	test.'plan'('1')
+
+	test.'ok'(1)
+	test.'diag'('diag message')
+
+	test.'finish'()
+	goto END
+CODE
+1..1
+ok 1
+# diag message
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "diag before ok");
+	test.'plan'('1')
+
+	test.'diag'('diag message')
+	test.'ok'(1)
+
+	test.'finish'()
+	goto END
+CODE
+1..1
+# diag message
+ok 1
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "diag with no_plan after ok");
+	test.'plan'('no_plan')
+
+	test.'ok'(1)
+	test.'diag'('diag message')
+
+	test.'finish'()
+	goto END
+CODE
+ok 1
+# diag message
+1..1
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "diag with no_plan before ok");
+	test.'plan'('no_plan')
+
+	test.'diag'('diag message')
+	test.'ok'(1)
+
+	test.'finish'()
+	goto END
+CODE
+# diag message
+ok 1
+1..1
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "diag with no_plan & no tests");
+	test.'plan'('no_plan')
+
+	test.'diag'('diag message')
+
+	test.'finish'()
+	goto END
+CODE
+# diag message
+1..0
+OUT
+
+
+## skip
+
+=for comment
+
+ use Test::More qw/ no_plan /;
+ SKIP:{ skip; }
+
+=cut
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "skip 0 - defaults to 1", todo => 'unexpected results');
+	test.'plan'('no_plan')
+
+	test.'skip'()
+
+	test.'finish'()
+	goto END
+CODE
+ok 1 #skip skipped
+1..1
+OUT
+
+
+=for comment
+
+ use Test::More 'no_plan';
+ SKIP:{ skip '', 1; ok(1); }
+ SKIP:{ skip '', 1; ok(0); }
+ SKIP:{ skip '', 1; ok(1, 'skip me'); }
+ SKIP:{ skip '', 1; ok(0, 'skip me too'); }
+ SKIP:{ skip '', 2; ok(0); ok(1); }
+ SKIP:{ skip '', 2; ok(0, 'skip me'); ok(1, 'skip me too'); }
+
+=cut
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "skip 0 - invalid", todo => 'unexpected results');
+	test.'plan'('no_plan')
+
+	# skip a passing test
+	test.'skip'(1)
+	test.'ok'(1)
+
+	# skip a failing test
+	test.'skip'(1)
+	test.'ok'(0)
+
+	# skip a passing test (with skip description )
+	test.'skip'(1, 'skip me')
+	test.'ok'(1)
+
+	# skip a failing test (with skip description )
+	test.'skip'(1, 'skip me too')
+	test.'ok'(0)
+
+	# skip multiple tests
+	test.'skip'(2)
+	test.'ok'(0)
+	test.'ok'(1)
+
+	# skip multiple tests (with skip description)
+	test.'skip'(2)
+	test.'ok'(0, 'skip me')
+	test.'ok'(1, 'skip me too')
+
+	test.'finish'()
+	goto END
+CODE
+ok 1 # skip skipped
+ok 2 # skip skipped
+ok 3 # skip skipped
+ok 4 # skip skipped
+ok 5 # skip skipped
+ok 6 # skip skipped
+ok 7 # skip skipped
+ok 8 # skip skipped
+1..8
+OUT
+
+
+=for comment
+
+ use Test::More tests => 8;
+ SKIP:{ skip '', 1; ok(1); }
+ SKIP:{ skip '', 1; ok(0); }
+ SKIP:{ skip '', 1; ok(1, 'skip me'); }
+ SKIP:{ skip '', 1; ok(0, 'skip me too'); }
+ SKIP:{ skip '', 2; ok(0); ok(1); }
+ SKIP:{ skip '', 2; ok(0, 'skip me'); ok(1, 'skip me too'); }
+
+=cut
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "skip 0 - invalid", todo => 'unexpected results');
+	test.'plan'(8)
+
+	# skip a passing test
+	test.'skip'(1)
+	test.'ok'(1)
+
+	# skip a failing test
+	test.'skip'(1)
+	test.'ok'(0)
+
+	# skip a passing test (with skip description )
+	test.'skip'(1, 'skip me')
+	test.'ok'(1)
+
+	# skip a failing test (with skip description )
+	test.'skip'(1, 'skip me too')
+	test.'ok'(0)
+
+	# skip multiple tests
+	test.'skip'(2)
+	test.'ok'(0)
+	test.'ok'(1)
+
+	# skip multiple tests (with skip description)
+	test.'skip'(2)
+	test.'ok'(0, 'skip me')
+	test.'ok'(1, 'skip me too')
+
+	test.'finish'()
+	goto END
+CODE
+1..8
+ok 1 # skip skipped
+ok 2 # skip skipped
+ok 3 # skip skipped
+ok 4 # skip skipped
+ok 5 # skip skipped
+ok 6 # skip skipped
+ok 7 # skip skipped
+ok 8 # skip skipped
+OUT
+
+
+## skip_all
+
+=for comment
+
+ use Test::More 'skip_all';
+
+=cut
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "skip_all", todo => 'unexpected results');
+	test.'skip_all'()
+CODE
+1..0
+OUT
+
+
+=for comment
+
+ use Test::More 'skip_all';
+ ok(1);
+ ok(0);
+
+=cut
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "skip_all", todo => 'unexpected results');
+	test.'skip_all'()
+
+	test.'ok'(1)
+	test.'ok'(0)
+CODE
+1..0
+OUT
+
+
+## BAILOUT
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT no args");
+	test.'BAILOUT'()
+CODE
+Bail out!
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT with string arg");
+	test.'BAILOUT'('Bad luck, dude.')
+CODE
+Bail out!  Bad luck, dude.
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT with number arg");
+	test.'BAILOUT'(0)
+CODE
+Bail out!  0
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT with tests before");
+	test.'plan'(2)
+	test.'ok'(1)
+	test.'ok'(0)
+	test.'BAILOUT'('Bad luck, dude.')
+CODE
+1..2
+ok 1
+not ok 2
+Bail out!  Bad luck, dude.
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT with tests after");
+	test.'plan'(2)
+	test.'BAILOUT'('Bad luck, dude.')
+	test.'ok'(1)
+	test.'ok'(0)
+CODE
+1..2
+Bail out!  Bad luck, dude.
+OUT
+
+
+pir_output_is($PRE.<<CODE.$POST, <<'OUT', "BAILOUT with tests before and after");
+	test.'plan'(4)
+	test.'ok'(1)
+	test.'ok'(0)
+	test.'BAILOUT'('Bad luck, dude.')
+	test.'ok'(1)
+	test.'ok'(0)
+CODE
+1..4
+ok 1
+not ok 2
+Bail out!  Bad luck, dude.
+OUT
+
+
+## TODO: report_test
+
+
+## don't forget to change the number of tests!
+BEGIN { plan tests => 35; }
+
+# vim: ft=imc :
