packages feed

inline-r-0.7.2.0: tests/tests.hs

-- |
-- Copyright: (C) 2013 Amgen, Inc.
--
-- Tests. Run H on a number of R programs of increasing size and complexity,
-- comparing the output of H with the output of R.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Main where

import qualified Test.Constraints
import qualified Test.Event
import qualified Test.FunPtr
import qualified Test.HExp
import qualified Test.GC
import qualified Test.Regions
import qualified Test.Vector

import H.Prelude
import Language.R.HExp
import qualified Foreign.R as R
import qualified Language.R.Instance as R
    ( initialize
    , defaultConfig )
import qualified Language.R.Internal as R ( r2 )
import           Language.R.QQ

import Test.Tasty
import Test.Tasty.HUnit

import Control.Applicative
import qualified Data.ByteString.Char8 (pack)
import           Data.Vector.Generic (basicUnsafeIndexM)
import           Data.Singletons (sing)
import Foreign
import Prelude -- Silence AMP warning

tests :: TestTree
tests = testGroup "Unit tests"
  [ testCase "fromSEXP . mkSEXP" $ do
      z <- fromSEXP <$> mkSEXPIO (2 :: Double)
      (2 :: Double) @=? z
  , testCase "HEq HExp" $ do
      -- XXX ideally randomly generate input.
      let x = 2 :: Double
      R.withProtected (mkSEXPIO x) $ \z ->
        assertBool "reflexive" $
          let s = hexp z in s === s
      R.withProtected (mkSEXPIO x) $ \z ->
        assertBool "symmetric" $
          let s1 = hexp z
              s2 = hexp z
          in s1 === s2 && s2 === s1
      R.withProtected (mkSEXPIO x) $ \z ->
        assertBool "transitive" $
          let s1 = hexp z
              s2 = hexp z
              s3 = hexp z
          in s1 === s2 && s2 === s3 && s1 === s3
  , testCase "Haskell function from R" $ do
--      (("[1] 3.0" @=?) =<<) $
--        fmap ((\s -> trace s s).  show . toHVal) $ alloca $ \p -> do
      (((3::Double) @=?) =<<) $ fmap fromSEXP $
          alloca $ \p -> do
            e <- peek R.globalEnv
            R.withProtected (mkSEXPIO $ \x -> return $ x + 1 :: R s Double) $
              \sf -> R.withProtected (mkSEXPIO (2::Double)) $ \d ->
                      R.r2 (Data.ByteString.Char8.pack ".Call") sf d
                      >>= \(R.SomeSEXP s) -> R.cast  (sing :: R.SSEXPTYPE 'R.Real)
                                                     <$> R.tryEval s (R.release e) p
  , testCase "Weak Ptr test" $ runRegion $ do
      key  <- mkSEXP (return 4 :: R s Int32)
      val  <- mkSEXP (return 5 :: R s Int32)
      True <- return $ R.typeOf val == R.ExtPtr
      n    <- unhexp Nil
      rf   <- io $ R.mkWeakRef key val n True
      True <- case hexp rf of
                WeakRef a b c _ -> do
                  True <- return $ (R.unsexp a) == (R.unsexp key)
                  True <- return $ (R.unsexp b) == (R.unsexp val)
                  return $ (R.unsexp c) == (R.unsexp n)
      return ()
  , testCase "Hexp works" $
      (((42::Double) @=?) =<<) $ runRegion $ do
         y <- R.cast (sing :: R.SSEXPTYPE 'R.Real) . R.SomeSEXP
                     <$> mkSEXP (42::Double)
         case hexp y of
           Real s -> basicUnsafeIndexM s 0
  , Test.Constraints.tests
  , Test.FunPtr.tests
  , Test.HExp.tests
  , Test.GC.tests
  , Test.Regions.tests
  , Test.Vector.tests
  , Test.Event.tests
    -- This test helps compiling quasiquoters concurrently from
    -- multiple modules. This in turns helps testing for race
    -- conditions when initializing R from multiple threads.
  , testCase "qq/concurrent-initialization" $ unsafeRToIO $ [r| 1 |] >> return ()
  , testCase "sanity check " $ return ()
  ]

main :: IO ()
main = do
    _ <- R.initialize R.defaultConfig
    defaultMain tests