packages feed

grisette-0.7.0.0: test/Grisette/Lib/Data/TraversableTests.hs

{-# LANGUAGE OverloadedStrings #-}

module Grisette.Lib.Data.TraversableTests (traversableFunctionTests) where

import Control.Monad.Except
  ( ExceptT (ExceptT),
    MonadError (throwError),
  )
import Grisette
  ( SymBranching (mrgIfPropagatedStrategy),
    Union,
    mrgIf,
    mrgSingle,
  )
import Grisette.Lib.Control.Monad (mrgReturn)
import Grisette.Lib.Data.Traversable
  ( mrgFor,
    mrgForAccumM,
    mrgForM,
    mrgMapAccumM,
    mrgMapM,
    mrgSequence,
    mrgSequenceA,
    mrgTraverse,
  )
import Grisette.TestUtil.NoMerge (oneNotMerged)
import Test.Framework
  ( Test,
    TestOptions' (topt_timeout),
    plusTestOptions,
    testGroup,
  )
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit ((@?=))

traversableFunctionTests :: Test
traversableFunctionTests =
  testGroup
    "Traversable"
    [ plusTestOptions (mempty {topt_timeout = Just (Just 1000000)}) $
        testGroup "mrgTraverse, mrgMapM, mrgFor, mrgForM" $ do
          (name, func0, func1) <-
            [ ("mrgTraverse", mrgTraverse, mrgTraverse),
              ("mrgMapM", mrgMapM, mrgMapM),
              ("mrgFor", flip mrgFor, flip mrgFor),
              ("mrgForM", flip mrgForM, flip mrgForM)
              ]
          return $
            testGroup
              name
              [ testCase "semantics" $ do
                  let actual =
                        func0
                          ( \(c, d, x, y, z) ->
                              ExceptT $
                                mrgIfPropagatedStrategy
                                  c
                                  (return $ Left x)
                                  ( mrgIfPropagatedStrategy
                                      d
                                      (return $ Right y)
                                      (return $ Right z)
                                  )
                          )
                          [("a", "c", 3, 4, 5), ("b", "d", 2, 3, 6)] ::
                          ExceptT Integer Union [Integer]
                  let expected = do
                        a <-
                          mrgIf
                            "a"
                            (throwError 3)
                            (mrgIf "c" (return 4) (return 5))
                        b <-
                          mrgIf
                            "b"
                            (throwError 2)
                            (mrgIf "d" (return 3) (return 6))
                        mrgSingle [a, b]
                  actual @?= expected,
                testCase "merge intermediate" $ do
                  let actual = func1 (const oneNotMerged) [1 .. 1000]
                  let expected = mrgReturn $ replicate 1000 1
                  actual @?= expected
              ],
      plusTestOptions (mempty {topt_timeout = Just (Just 1000000)}) $
        testGroup "mrgSequenceA, mrgSequence" $ do
          (name, func0, func1) <-
            [ ("mrgSequenceA", mrgSequenceA, mrgSequenceA),
              ("mrgSequence", mrgSequence, mrgSequence)
              ]
          return $
            testGroup
              name
              [ testCase "semantics" $ do
                  let actual =
                        func0
                          [ ExceptT $
                              mrgIfPropagatedStrategy
                                "a"
                                (return $ Left 3)
                                ( mrgIfPropagatedStrategy
                                    "c"
                                    (return $ Right 4)
                                    (return $ Right 5)
                                ),
                            ExceptT $
                              mrgIfPropagatedStrategy
                                "b"
                                (return $ Left 2)
                                ( mrgIfPropagatedStrategy
                                    "d"
                                    (return $ Right 3)
                                    (return $ Right 6)
                                )
                          ] ::
                          ExceptT Integer Union [Integer]
                  let expected = do
                        a <-
                          mrgIf
                            "a"
                            (throwError 3)
                            (mrgIf "c" (return 4) (return 5))
                        b <-
                          mrgIf
                            "b"
                            (throwError 2)
                            (mrgIf "d" (return 3) (return 6))
                        mrgSingle [a, b]
                  actual @?= expected,
                testCase "merge intermediate" $ do
                  let actual = func1 (replicate 1000 oneNotMerged)
                  let expected = mrgReturn $ replicate 1000 1
                  actual @?= expected
              ],
      plusTestOptions (mempty {topt_timeout = Just (Just 1000000)}) $
        testGroup "mrgMapAccumM, mrgForAccumM" $ do
          (name, func0, func1) <-
            [ ("mrgMapAccumM", mrgMapAccumM, mrgMapAccumM),
              ( "mrgForAccumM",
                \f s t -> mrgForAccumM s t f,
                \f s t -> mrgForAccumM s t f
              )
              ]
          return $
            testGroup
              name
              [ testCase "semantics" $ do
                  let actual =
                        func0 (\a b -> mrgSingle (a + b, a - b)) 0 [1 .. 1000]
                  let expected =
                        mrgReturn
                          ( 500500,
                            [(i - 1) * i `div` 2 - i | i <- [1 .. 1000]]
                          ) ::
                          Union (Integer, [Integer])
                  actual @?= expected,
                testCase "merge intermediate" $ do
                  let actual =
                        func1
                          ( \_ _ ->
                              mrgIfPropagatedStrategy
                                "a"
                                (return (1, 1))
                                (return (1, 1))
                          )
                          0
                          [1 .. 1000]
                  let expected =
                        mrgReturn (1, replicate 1000 1) ::
                          Union (Integer, [Integer])
                  actual @?= expected
              ]
    ]