-- HUnit unit tests for Data.FsmActions.ActionMatrix -- Copyright (c) 2009 Andy Gimblett - http://www.cs.swan.ac.uk/~csandy/ -- BSD Licence (see http://www.opensource.org/licenses/bsd-license.php) module Tests.Data.FsmActions.ActionMatrix ( tests, egF ) where import Control.Monad.Error import System.IO.Error (mkIOError, userErrorType) import Test.HUnit.Base import Data.FsmActions import Data.FsmActions.ActionMatrix egFpaths :: [(Char, FilePath)] egFpaths = [('a', "doc/examples/bigActionMatrices/egF/a.actionmx") ,('b', "doc/examples/bigActionMatrices/egF/b.actionmx") ,('c', "doc/examples/bigActionMatrices/egF/c.actionmx") ,('d', "doc/examples/bigActionMatrices/egF/d.actionmx") ,('e', "doc/examples/bigActionMatrices/egF/e.actionmx") ,('f', "doc/examples/bigActionMatrices/egF/f.actionmx") ,('g', "doc/examples/bigActionMatrices/egF/g.actionmx") ,('h', "doc/examples/bigActionMatrices/egF/h.actionmx") ,('i', "doc/examples/bigActionMatrices/egF/i.actionmx") ,('j', "doc/examples/bigActionMatrices/egF/j.actionmx") ] egF :: IO (FSM Char) egF = parseFsmActionMxFiles egFpaths singleton :: String singleton = "1" singletonAction :: Action singletonAction = mkDAction [0] duoDet :: String duoDet = "0,1\n1,0" duoDetAction :: Action duoDetAction = mkDAction [1,0] duoNon :: String duoNon = "1,1\n1,0" duoNonAction :: Action duoNonAction = mkAction [[0,1],[0]] trailing1 :: String trailing1 = duoNon ++ "\n" trailingn :: String trailingn = duoNon ++ "\n\n\n\n\n\n\n" combi :: [(String, String)] combi = [("a", duoDet), ("b", duoNon)] -- Utility test-builder functions. -- Test that parsing a (valid) action matrix string yields the -- expected action. testParse :: String -> String -> Action -> Test testParse n s a = n ~: parseActionMx s ~?= Right a -- Lift testParse to a list of test cases. testParses :: [(String, String, Action)] -> Test testParses = test . map (foo testParse) where foo :: (a -> b -> c -> d) -> (a, b, c) -> d foo f (x,y,z) = f x y z -- Test that parsing a (valid) action matrix string and pretty -- pretting it yields the original string. testParsePP :: String -> String -> Test testParsePP n s = n ~: liftM printActionMx (parseActionMx s) ~?= Right s -- Lift testParsePP to an action matrix string in a file testParseFilePP :: FilePath -> Test testParseFilePP fpath = test [do s <- readFile fpath assertBool fpath $ liftM printActionMx (parseActionMx s) == Right s ] -- Test parsing an entire FSM from multiple action strings. testParseFsm :: String -> [(String, String)] -> FSM String -> Test testParseFsm name parts fsm = name ~: parseFsmActionMxs parts ~?= Right fsm -- Actual test suites -- Test simple parses of single actions. testSimple :: Test testSimple = testParses [("singleton", singleton, singletonAction) ,("duoDet", duoDet, duoDetAction) ,("duoNon", duoNon, duoNonAction) ,("trailing1", trailing1, duoNonAction) ,("trailingn", trailingn, duoNonAction) ] -- Test parsing FSMs from lists of symbols & actions. testCombi :: Test testCombi = test [testParseFsm "one" combi $ fromList [("a", duoDetAction), ("b", duoNonAction)] ] -- Test some "complex properties" of parsed actions. testComplex :: Test testComplex = test ["tiny" ~: do a <- parseActionMxFile "doc/examples/tiny.actionmatrix" assertBool "nondet" $ not $ isDAction a assertBool "isnorm" $ a == normaliseAction a assertBool "length" $ length (destinationSets a) == 3 ,"moon" ~: do a <- parseActionMxFile "doc/examples/tiny.actionmatrix" let f = fromList [('a', a)] assertBool "3 states" $ length (states f) == 3 ,"egF" ~: do f <- egF assertBool "norm" $ f == normalise f assertBool "10 actions" $ length (alphabet f) == 10 assertBool "425 states" $ length (states f) == 425 ] where -- | Read an action matrix from a specified file, and parse -- it into an 'Data.FsmActions.Action'. Moved out from -- Data/FsmActions/ActionMatrix.hs because it's not needed -- there any more. parseActionMxFile :: FilePath -> IO Action parseActionMxFile p = do contents <- readFile p let act = parseActionMx contents case act of Right a -> return a Left e -> throwError (mkIOError userErrorType (show e) Nothing (Just p)) -- Test parsing then pretty-printing. testPP :: Test testPP = test ([testParsePP "ppDet" duoDet ,testParsePP "ppNon" duoNon ] ++ map (testParseFilePP . snd) egFpaths) -- Master test suite. tests :: Test tests = test ["simple" ~: testSimple ,"combi" ~: testCombi ,"complex" ~: testComplex ,"parsePP" ~: testPP ]