simgi-0.3: test/check_event_parser/EventParserTest.hs
{-----------------------------------------------------------------
(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 event 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 Engine
import GenericModel()
import PrettyPrint
import InputParser
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 = (Bool, M.Map String Int)
-- | 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
simpleEventParseTests :: [TestCase]
simpleEventParseTests =
[ ("z == 100 => [ x = {x} ]",
(True, M.fromList [("x",1000),("y",2000),("z",100)]))
, ("( z== 100) => [ x = {x+y}, y = {y+1} ]",
(True, M.fromList [("x",3000),("y",2001),("z",100)]))
, ("(z==121 ) => [ y=10 ]",
(False, M.fromList [("x",1000),("y",10),("z",100)]))
, ("(z==101) => [ x = {x/2.0} ]}",
(False, M.fromList [("x",500),("y",2000),("z",100)]))
, ("z == 100=>[ z= 121, x = 500, y=2000,]",
(True, M.fromList [("x",500),("y",2000),("z",121)]))
, ("( y >= 121 )=>[z=1050]",
(True, M.fromList [("x",1000),("y",2000),("z",1050)]))
, ("( z <= 100) => [ x= {sqrt(4)*100}, y = {x^2/10}]",
(True, M.fromList [("x",200),("y",4000),("z",100)]))
, ("x >= 100 => [ z= {z}, z = {2*z}, z = {3*z },]",
(True, M.fromList [("x",1000),("y",2000),("z",600)]))
, ("z < 100 => [ x= 10, y = {z}]",
(False, M.fromList [("x",10),("y",100),("z",100)]))
, ("(( x > 100)) => [ y= {x+z}]",
(True, M.fromList [("x",1000),("y",1100),("z",100)]))
, ("y == 2000 => [ x=1001 ]",
(True, M.fromList [("x",1001),("y",2000),("z",100)]))
, ("z <= 302 => [ x = 10, y = 10, z= 200, z=10 ]",
(True, M.fromList [("x",10),("y",10),("z",10)]))
, ("( y == 100 ) => [ x = 10, y = 20, ]",
(False, M.fromList [("x",10),("y",20),("z",100)]))
, ("( z == 100 )=> [ x = 10, y = 20 ]",
(True, M.fromList [("x",10),("y",20),("z",100)]))
, ("((z == 100 ) )=> [ x = 10, y = {20 + z }]",
(True, M.fromList [("x",10),("y",120),("z",100)]))
, ("x > 100 => [ x = {10*x+y}, y = {20+z^2} ]",
(True, M.fromList [("x",12000),("y",10020),("z",100)]))
, ("z == 100 => [ x = {1e6*exp(-TIME)}, y = {x}, ]",
(True, M.fromList [("x",4),("y",4),("z",100)]))
, ("( y == 100 ) => [ x = 2, x = {y^x}, y ={ x*exp(-TIME)} ]",
(False, M.fromList [("x",4000000),("y",17),("z",100)]))
, ("( z == 100 ) => [ x = {10+z}, y = {sqrt(log((x^2)))}, ]",
(True, M.fromList [("x",110),("y",3),("z",100)]))
]
----------------------------------------------------------------
-- 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 Input Parser ******"
-- check event parser
>> (putStr $ color_string Cyan "\nEvent parse tests:\n")
>> let eventParseOut = execWriter $ event_parser_test_driver
testMap_1 time_1 simpleEventParseTests
in
examine_output eventParseOut >>= \eventParseStatus ->
-- check event triggers and actions
(putStr $ color_string Cyan "\n\nEvent trigger/action tests:\n")
>> let eventActionOut = execWriter $ event_action_test_driver
testMap_1 time_1 simpleEventParseTests
in
examine_output eventActionOut >>= \eventActionStatus ->
-- evaluate status and return
let status = eventParseStatus && eventActionStatus
in
if status == True then
exitWith ExitSuccess
else
exitWith $ ExitFailure 1
-- | this driver parses the event expression and checks that
-- there are no errors (there shouldn't be any)
event_parser_test_driver :: MoleculeMap -> Double -> [TestCase]
-> Writer [TestResult] ()
event_parser_test_driver _ _ [] = return ()
event_parser_test_driver mol t (x:xs) =
let expr = fst x
expected = snd x
in
-- parse expression
case runParser parse_events testModelState "" expr of
Left er -> tell [TestResult False expr (show expected) (show er)]
Right _ ->
tell [TestResult True expr (show expected) ("good parse")]
>> event_parser_test_driver mol t xs
-- | this driver parses the event expression and checks if
-- 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
event_action_test_driver :: MoleculeMap -> Double -> [TestCase]
-> Writer [TestResult] ()
event_action_test_driver _ _ [] = return ()
event_action_test_driver mol t (x:xs) =
let expr = fst x
expectedTrigger = fst . snd $ x
expectedMols = snd . snd $ x
in
-- parse expression
case runParser parse_events testModelState "" expr of
Left er -> tell [TestResult False expr "" (show er)]
Right event ->
-- make sure the trigger expression evaluated properly
let
actions = evtActions event
outMols = execute_actions actions (SymbolTable mol M.empty) t
outTrigger = check_trigger mol t expectedTrigger event
in
case outTrigger && ((molSymbols outMols) == expectedMols) of
False -> tell [TestResult False expr
(show expectedTrigger ++ " => " ++ show expectedMols)
(show outTrigger ++ " => " ++ show (molSymbols outMols))]
True -> tell [TestResult True expr "" ("good parse")]
>> event_action_test_driver mol t xs
-- | given an Event and a MoleculeMap check that the trigger
-- evaluates to the expected value
check_trigger :: MoleculeMap -> Double -> Bool -> Event
-> Bool
check_trigger molMap t expected (Event { evtTrigger = trigger }) =
computed == expected
where
computed = compute_trigger (SymbolTable molMap M.empty) t trigger