packages feed

matlab-0.3.0.0: test/Test/Engine.hs

{-# LANGUAGE QuasiQuotes            #-}
{-# LANGUAGE ScopedTypeVariables    #-}
{-# LANGUAGE TemplateHaskell        #-}

module Test.Engine where

import Control.Exception (SomeException, assert, try)
import Data.Either (isLeft, isRight, lefts)
import Foreign.Matlab
import Foreign.Matlab.Engine
import Foreign.Matlab.Engine.Wrappers
import Language.Haskell.TH (Q, runIO)
import Language.Haskell.TH.Syntax (lift)
import Path
import Test.Util

engineTests = runEngineTests ""

runEngineTests :: String -> IO ()
runEngineTests host = do
  putStrLn "-- Starting engine --"
  eng <- newEngine host
  putStrLn "-- Engine created --"
  let testPath = repoDir </> testRel
  addpath eng testPath
  runLocalMatFun eng
  cosOfPi eng
  testIsMNull eng
  testGetFirstLast eng
  testAbstractValueUse eng
  testTypedAbstractValueUse eng
  testGetByteStreamFromArray eng
  testGetArrayFromByteStream eng
  testCellGet eng
  testClearVar eng

cosOfPi :: Engine -> IO ()
cosOfPi eng = do
  putStrLn "\n-- cos pi --"
  x <- createMXScalar (pi :: MDouble)
  cosBody eng "cos" x

runLocalMatFun :: Engine -> IO ()
runLocalMatFun eng = do
  putStrLn "\n-- mtest: cos pi --"
  x <- createMXScalar (pi :: MDouble)
  cosBody eng "mtest" x

cosBody :: Engine -> String -> MXArray MDouble -> IO ()
cosBody eng cosFun x = do
  [y] <- engineEvalFun eng cosFun [EvalArray x] 1
  mxArrayClass y >>= print
  Just y <- castMXArray y
  y <- mxScalarGet y
  print (y :: MDouble)

testIsMNull :: Engine -> IO ()
testIsMNull eng = do
  putStrLn $ "\n-- testIsMNull --"
  xa <- createMXScalar (1.0 :: MDouble)
  let xaRes = assert (isMNull xa == False) xa
  xaResEi <- mxArrayGetFirst xaRes
  putStrLn $ "  xaResEi is Right: " <> (show xaResEi)
  xae :: MXArray MChar <- createMXArray []
  freeMXArray xae
  mxLen <- mxArrayLength xae
  mxDims <- mxArraySize xae
  putStrLn $ "length is " <> (show mxLen) <> " dims are " <> (show $ mxDims)
  let xaeRes = assert (isMNull xae == False) xae
  xaeResEi <- mxArrayGetFirst xaeRes
  putStrLn $ "  xaeResEi is Left: " <> (show xaeResEi)

testGetFirstLast :: Engine -> IO ()
testGetFirstLast eng = do
  putStrLn $ "\n-- testGetFirstLast --"
  let testVal :: MDouble = 1.0
  xa <- createMXScalar testVal
  xfEi <- mxArrayGetFirst xa
  xlEi <- mxArrayGetLast xa
  let xRes = assert (xlEi == Right 1.0 && xfEi == xlEi) xfEi
  putStrLn $ "  xRes is : " <> (show xRes)
  threeArray :: MXArray MDouble <- fromListIO [5.0, 6.0, 7.0]
  txfEi <- mxArrayGetFirst threeArray
  txlEi <- mxArrayGetLast threeArray
  let txfRes = assert (txfEi == Right 5.0) txfEi
  putStrLn $ "  txfRes is : " <> (show txfRes)
  let txlRes = assert (txlEi == Right 7.0) txlEi
  putStrLn $ "  txlRes is : " <> (show txlRes)
  
testAbstractValueUse :: Engine -> IO ()
testAbstractValueUse eng = do
  putStrLn $ "\n-- testAbstractValueUse --"
  sOut <- makeTestStruct eng
  sSum <- useTestStruct eng sOut
  let sSumRes = assert (sSum == 7.0) sSum
  putStrLn $ "  struct sum is: " <> (show sSumRes)

makeTestStruct :: Engine -> IO MAnyArray
makeTestStruct eng = do
  [res] <- engineEvalFun eng "makeTestStruct" [] 1
  pure res

useTestStruct :: Engine -> MAnyArray -> IO MDouble
useTestStruct eng sIn = do
  [res] <- engineEvalFun eng "useTestStruct" [EvalArray sIn] 1
  mxArrMay <- castMXArray res
  case mxArrMay of
    Just mxArr -> mxScalarGet mxArr
    Nothing -> pure 0.0


newtype MyAbsType = MyAbsType { unMyAbsType :: MAnyArray }

-- |Similar to testAbstractValueUse, but instead of using
-- |MAnyArray, we use newtypes for better type safety
testTypedAbstractValueUse :: Engine -> IO ()
testTypedAbstractValueUse eng = do
  putStrLn $ "\n-- testTypedAbstractValueUse --"
  sOut <- makeTestStructTyped eng
  sSum <- useTestStructTyped eng sOut
  let sSumRes = assert (sSum == 7.0) sSum
  putStrLn $ "  struct sum is: " <> (show sSumRes)

makeTestStructTyped :: Engine -> IO MyAbsType
makeTestStructTyped eng = MyAbsType <$> (makeTestStruct eng)

useTestStructTyped :: Engine -> MyAbsType -> IO MDouble
useTestStructTyped eng (MyAbsType sIn) = useTestStruct eng sIn

testGetByteStreamFromArray :: Engine -> IO ()
testGetByteStreamFromArray eng = do
  putStrLn $ "\n-- testGetByteStreamFromArray --"
  sOutBSMatlab <- makeTestStructByteStream eng
  sOut <- makeTestStruct eng
  Right sOutBSHaskell <- getByteStreamFromArray eng sOut
  let bsSum = sum $ fromIntegral <$> (assert (sOutBSMatlab == sOutBSHaskell) sOutBSHaskell)
  putStrLn $ " bytestream sum is: " <> (show bsSum)

testGetArrayFromByteStream :: Engine -> IO ()
testGetArrayFromByteStream eng = do
  putStrLn $ "\n-- testGetArrayFromByteStream --"
  sOutBS <- makeTestStructByteStream eng
  sOutFromBS <- getArrayFromByteStream eng sOutBS
  sOut <- makeTestStruct eng
  sSumFromBS <- useTestStruct eng sOutFromBS
  sSum <- useTestStruct eng sOut
  let sSumRes = assert (sSumFromBS == sSum) sSumFromBS
  putStrLn $ " deserialized struct sum is: " <> (show sSumRes)

makeTestStructByteStream :: Engine -> IO [MUint8]
makeTestStructByteStream eng = do
  [res] <- engineEvalFun eng "makeTestStructByteStream" [] 1
  mxArrMay <- castMXArray res
  case mxArrMay of
    Just mxArr -> mxArrayGetAll mxArr
    Nothing -> pure []

-- TODO: display cell array and extracted values in test
testCellGet :: Engine -> IO ()
testCellGet eng = do
  putStrLn "\n-- testCellGet --"
  [ca] <- engineEvalFun eng "mcellTest" [] 1
  Just (ca :: MXArray MCell) <- castMXArray ca
  caLen <- mxArrayLength ca
  let caLenMsg = assert (caLen == 6) "cell array has length 6"
  putStrLn caLenMsg
  dCells :: [MXArray MDouble] <- mxCellGetArraysOfType ca
  let dCellsMsg = assert (length dCells == 4) "cell array has 4 double arrays"
  putStrLn dCellsMsg
  dVals :: [MDouble] <- mxCellGetAllOfType ca
  let dValsMsg = assert (length dVals == 4) "cell array has 4 double values"
  putStrLn dValsMsg

testClearVar :: Engine -> IO ()
testClearVar eng = do
  putStrLn $ "\n-- testClearVar --"
  let foopi = "foopi"
  x <- createMXScalar (pi :: MDouble)
  engineSetVar eng foopi x
  ei1 :: Either SomeException MAnyArray <- try $ engineGetVar eng foopi
  putStrLn $ assert (isRight ei1) "  Can clearVar once"
  clearVar eng foopi
  ei2 :: Either SomeException MAnyArray <- try $ engineGetVar eng foopi
  putStrLn $ assert (isLeft ei2) $
    " Can't clearVar twice: " <> (show $ lefts [ei2])
  putStrLn "  Finished testClearVar"


testRel :: Path Rel Dir
testRel = $(mkRelDir "test")

repoDir :: Path Abs Dir
repoDir = $(mkAbsDir getRepoDirStatic)