[Haskell-beginners] Help with TAP implemation in haskell

Patrick LeBoutillier patrick.leboutillier at gmail.com
Tue Feb 24 20:32:49 EST 2009


Hi,

As a learning exercise, I'm trying to make a Haskell module (my first)
that implements a TAP library (http://testanything.org/).

The library basically provides some functions to perform unit tests
and keeps track of some state. It also performs quite a bit of IO as
it goes a long.

As a first step I'm loosely basing my code on a Java implementation.
You can find the code here:
http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/JTap.java.

I've setup my TapState data structure and a monad transformer to be
able to keep state and do IO within the same functions:

  data TapState = TapState {
    planSet :: Bool,
    noPlan :: Bool,
    skipAll :: Bool,
    testDied :: Bool,
    expectedTests :: Int,
    executedTests :: Int,
    failedTests :: Int
  } deriving (Show)

  type TAP a = StateT TapState IO a

In the Java version there is a function called cleanup that is called
after all the tests are performed to determine the return code and
print some diagnostics:

private int cleanup(){
	int rc = 0 ;

	if (! plan_set){
		diag("Looks like your test died before it could output anything.") ;
		return rc ;
	}

	if (test_died){
		diag("Looks like your test died just after " + executed_tests + ".") ;
		return rc ;
	}

	if ((! skip_all)&&(no_plan)){
		print_plan(executed_tests) ;
	}

	if ((! no_plan)&&(expected_tests < executed_tests)) {
		diag("Looks like you planned " + expected_tests + " test" +
(expected_tests > 1 ? "s" : "") + " but ran "
			+ (executed_tests - expected_tests) + " extra.") ;
		rc = -1 ;
	}

	if ((! no_plan)&&(expected_tests > executed_tests)) {
		diag("Looks like you planned " + expected_tests + " test" +
(expected_tests > 1 ? "s" : "") + " but only ran "
			+ executed_tests + ".") ;
	}

	if (failed_tests > 0){
		diag("Looks like you failed " + failed_tests + " test" +
(failed_tests > 1 ? "s" : "") + " of " + executed_tests + ".") ;
	}

	return rc ;
}


I'm having problems implementing the equivalent of this function in
haskell. Inside a do block, is there a way to terminate the function
immediately and return a result ("return" in the imperative sense, not
the Haskell sense)? If not, must one really use deeply nested
if/then/else statements to treat these special cases? All I could come
up was this, which I find quite ugly:

_cleanup :: Int -> TAP Int
_cleanup rc = do
    ts <- get
    if (not $ planSet ts)
        then do
            diag "Looks like your test died before it could output anything."
            return rc
        else if (testDied ts)
            then do
                diag $ "Looks like your test died just after " ++
(show $ executedTests ts)
                return rc
            else ...


Thanks a lot,

Patrick

Note: If it helps, you can find my Haskell code here:
http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/tap.hs


-- 
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada


More information about the Beginners mailing list