{----------------------------------------------------------------- (c) 2009-2010 Markus Dittrich, National Resource for Biomedical Supercomputing & Carnegie Mellon University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 3 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 3 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --------------------------------------------------------------------} -- | this routine tests some aspects of the reaction block -- parsing routines module Main where -- imports import Control.Monad.Writer import qualified Data.Map as M import Prelude import System.Exit -- local imports import GenericModel import PrettyPrint import InputParser import RpnData import TestHelpers import TokenParser ----------------------------------------------------------------- -- -- test data specifications -- ----------------------------------------------------------------- -- | expected values for parser events. The first -- entry in the tuple is of type Bool giving the expected -- value of the evaluated trigger expression. The second -- is a Map of expected molecule counts after the actions -- have been evaluated type ExpectedOutput = Reaction -- | set up the test data -- Format : (parse expression, expected result) type TestCase = (String, ExpectedOutput) -- | simple tests without access to local variables --- NOTE: for now we simply test if parsing succeeds simpleReactParseTests :: [TestCase] simpleReactParseTests = [ ("x + y -> z | 1e6 |", Reaction (Constant 1e6) [("y",id),("x",id)] [("x",-1),("y",-1),("z",1)]) , ("x + y + z -> w | 10.3 |", Reaction (Constant 10.3) [("z",id),("y",id),("x",id)] [("x",-1),("y",-1),("z",-1),("w",1)]) , ("x + y + z -> w | {x*y} |", Reaction (Function . RpnStack $ [Variable "x", Variable "y", BinFunc (*)]) [("z",id),("y",id),("x",id)] [("x",-1),("y",-1),("z",-1),("w",1)]) , ("2x + 2y + z -> nil | { exp(-TIME) } |", Reaction (Function . RpnStack $ [Variable "TIME", Number (-1.0) , BinFunc (*), UnaFunc exp]) [("z",id),("y",\a -> 0.5 * a * (a-1)) ,("x",\a -> 0.5 * a * (a-1))] [("x",-2),("y",-2),("z",-1)]) , ("2x + y + z -> 2x + 20y + 5z | {x+y+z } |", Reaction (Function . RpnStack $ [Variable "x", Variable "y", BinFunc (+), Variable "z", BinFunc (+)]) [("z",id),("y",id),("x",\a -> 0.5 * a * (a-1))] [("y",19),("z",4)]) , ("2x + y + z -> 2x + 20y + 5z | { x* y* z } |", Reaction (Function . RpnStack $ [Variable "x", Variable "y", BinFunc (*), Variable "z", BinFunc (*)]) [("z",id),("y",id),("x",\a -> 0.5 * a * (a-1))] [("y",19),("z",4)]) , ("2 x+ y+ z-> 2 x + 20 y + 5z|{x*y * z } |", Reaction (Function . RpnStack $ [Variable "x", Variable "y", BinFunc (*), Variable "z", BinFunc (*)]) [("z",id),("y",id),("x",\a -> 0.5 * a * (a-1))] [("y",19),("z",4)]) , ("x + y + z -> x + y + z |{ x-x+y-y+z-z }|", Reaction (Function . RpnStack $ [Number 0.0]) [("z",id),("y",id),("x",id)] []) , ("nil -> x + y + z |{ x-x+y-y+z-z }|", Reaction (Function . RpnStack $ [Number 0.0]) [] [("x",1),("y",1),("z",1)]) , ("nil -> nil |{ sqrt(2.0) } |", -- Reaction (Function . RpnStack $ [Number 2.0, UnaFunc sqrt]) Reaction (Constant 1.4142135623730951) [] []) ] ---------------------------------------------------------------- -- Molecule maps and definitions for specific simulation times ---------------------------------------------------------------- -- | testmap containing a set of molecules and their -- concentrations testMap_1 :: MoleculeMap testMap_1 = M.fromList [("x",1000),("y",2000),("z",100)] -- | a simulation time time_1 :: Double time_1 = 12.345 ---------------------------------------------------------------- -- -- main driver routines -- ---------------------------------------------------------------- -- | main test driver main :: IO () main = putStrLn "\n****** Testing Reaction Parser ******" -- check event parser >> (putStr $ color_string Cyan "\nReaction parse tests:\n") >> let reactParseOut = execWriter $ react_parser_test_driver testMap_1 time_1 simpleReactParseTests in examine_output reactParseOut >>= \reactParseStatus -> -- evaluate status and return let status = reactParseStatus in if status == True then exitWith ExitSuccess else exitWith $ ExitFailure 1 -- the trigger and its actions action check out, i.e., we apply -- them to our current state and see if we get the proper number -- of molecules. -- NOTE: We do not thread the state through all tests but always -- start with our default, otherwise it becomes very tedious -- to add/remove tests. -- This parser should be run after the proper parsing has been -- verified via event_parser_test_driver react_parser_test_driver :: MoleculeMap -> Double -> [TestCase] -> Writer [TestResult] () react_parser_test_driver _ _ [] = return () react_parser_test_driver mol t (x:xs) = let parseString = fst x expected = snd x in -- parse expression case runParser parse_reaction testModelState "" parseString of Left er -> tell [TestResult False parseString "" (show er)] Right react -> case (react == expected) of False -> tell [TestResult False parseString "N/A" "N/A"] True -> tell [TestResult True parseString "" "good parse"] >> react_parser_test_driver mol t xs