packages feed

grisette-0.7.0.0: test/Grisette/Core/Data/Class/ExtractSymTests.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

module Grisette.Core.Data.Class.ExtractSymTests
  ( extractSymTests,
  )
where

import Control.Monad.Except (ExceptT (ExceptT))
import Control.Monad.Identity
  ( Identity (Identity),
    IdentityT (IdentityT),
  )
import Control.Monad.Trans.Maybe (MaybeT (MaybeT))
import qualified Control.Monad.Writer.Lazy as WriterLazy
import qualified Control.Monad.Writer.Strict as WriterStrict
import qualified Data.ByteString as B
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.Generics (Generic)
import GHC.Stack (HasCallStack)
import Generics.Deriving (Default (Default))
import Grisette
  ( ExtractSym (extractSym),
    ITEOp (symIte),
    LogicalOp (symNot, (.&&), (.||)),
    SymBool,
    SymEq ((.==)),
    SymbolSetOps (emptySet),
    SymbolSetRep (buildSymbolSet),
  )
import Grisette.Core.Data.Class.TestValues
  ( isymBool,
    isymbolBool,
    ssymBool,
    ssymbolBool,
    symTrue,
  )
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.HUnit (Assertion, (@?=))
import Test.QuickCheck (ioProperty)

data A = A1 | A2 SymBool | A3 SymBool SymBool
  deriving (Generic, Show, Eq)
  deriving (ExtractSym) via (Default A)

concreteExtractSymOkProp ::
  (HasCallStack, ExtractSym a) => (a, a) -> Assertion
concreteExtractSymOkProp x = extractSym x @?= emptySet

extractSymTests :: Test
extractSymTests =
  testGroup
    "ExtractSym"
    [ testGroup
        "Common types"
        [ testGroup
            "SymBool"
            [ testCase "con" $
                extractSym symTrue @?= emptySet,
              testCase "ssym" $
                extractSym (ssymBool "a")
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "isym" $
                extractSym (isymBool "a" 1)
                  @?= buildSymbolSet (isymbolBool "a" 1),
              testCase "And" $
                extractSym (ssymBool "a" .&& isymBool "b" 1)
                  @?= buildSymbolSet (ssymbolBool "a", isymbolBool "b" 1),
              testCase "Or" $
                extractSym (ssymBool "a" .|| isymBool "b" 1)
                  @?= buildSymbolSet (ssymbolBool "a", isymbolBool "b" 1),
              testCase "Equal" $
                extractSym (ssymBool "a" .== isymBool "b" 1)
                  @?= buildSymbolSet (ssymbolBool "a", isymbolBool "b" 1),
              testCase "ITE" $
                extractSym
                  (symIte (ssymBool "a") (isymBool "b" 1) (ssymBool "c"))
                  @?= buildSymbolSet
                    ( ssymbolBool "a",
                      isymbolBool "b" 1,
                      ssymbolBool "c"
                    ),
              testCase "Not" $
                extractSym (symNot $ isymBool "a" 1)
                  @?= buildSymbolSet (isymbolBool "a" 1)
            ],
          testProperty "Bool" $
            ioProperty . concreteExtractSymOkProp @Bool,
          testProperty "Integer" $
            ioProperty . concreteExtractSymOkProp @Integer,
          testProperty "Char" $
            ioProperty . concreteExtractSymOkProp @Char,
          testProperty "Int" $ ioProperty . concreteExtractSymOkProp @Int,
          testProperty "Int8" $
            ioProperty . concreteExtractSymOkProp @Int8,
          testProperty "Int16" $
            ioProperty . concreteExtractSymOkProp @Int16,
          testProperty "Int32" $
            ioProperty . concreteExtractSymOkProp @Int32,
          testProperty "Int64" $
            ioProperty . concreteExtractSymOkProp @Int64,
          testProperty "Word" $
            ioProperty . concreteExtractSymOkProp @Word,
          testProperty "Word8" $
            ioProperty . concreteExtractSymOkProp @Word8,
          testProperty "Word16" $
            ioProperty . concreteExtractSymOkProp @Word16,
          testProperty "Word32" $
            ioProperty . concreteExtractSymOkProp @Word32,
          testProperty "Word64" $
            ioProperty . concreteExtractSymOkProp @Word64,
          testGroup
            "[SymBool]"
            [ testCase "[]" $
                extractSym ([] :: [SymBool]) @?= emptySet,
              testCase "[v]" $
                extractSym [ssymBool "a"]
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "[v1, v2]" $
                extractSym [ssymBool "a", ssymBool "b"]
                  @?= buildSymbolSet (ssymbolBool "a", ssymbolBool "b")
            ],
          testGroup
            "Maybe SymBool"
            [ testCase "Nothing" $
                extractSym (Nothing :: Maybe SymBool) @?= emptySet,
              testCase "Just v" $
                extractSym (Just (ssymBool "a"))
                  @?= buildSymbolSet (ssymbolBool "a")
            ],
          testGroup
            "Either SymBool SymBool"
            [ testCase "Left v" $
                extractSym
                  (Left (ssymBool "a") :: Either SymBool SymBool)
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "Right v" $
                extractSym
                  (Right (ssymBool "a") :: Either SymBool SymBool)
                  @?= buildSymbolSet (ssymbolBool "a")
            ],
          testGroup
            "MaybeT Maybe SymBool"
            [ testCase "MaybeT Nothing" $
                extractSym (MaybeT Nothing :: MaybeT Maybe SymBool)
                  @?= emptySet,
              testCase "MaybeT (Just Nothing)" $
                extractSym (MaybeT (Just Nothing) :: MaybeT Maybe SymBool)
                  @?= emptySet,
              testCase "MaybeT (Just (Just v))" $
                extractSym (MaybeT (Just (Just (ssymBool "a"))))
                  @?= buildSymbolSet (ssymbolBool "a")
            ],
          testGroup
            "ExceptT SymBool Maybe SymBool"
            [ testCase "ExceptT Nothing" $
                extractSym
                  (ExceptT Nothing :: ExceptT SymBool Maybe SymBool)
                  @?= emptySet,
              testCase "ExceptT (Just (Left v))" $
                extractSym
                  ( ExceptT (Just (Left (ssymBool "a"))) ::
                      ExceptT SymBool Maybe SymBool
                  )
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "ExceptT (Just (Right v))" $
                extractSym
                  ( ExceptT (Just (Right (ssymBool "a"))) ::
                      ExceptT SymBool Maybe SymBool
                  )
                  @?= buildSymbolSet (ssymbolBool "a")
            ],
          testGroup
            "WriterT SymBool Maybe SymBool"
            [ testGroup
                "Lazy"
                [ testCase "WriterT Nothing" $
                    extractSym
                      ( WriterLazy.WriterT Nothing ::
                          WriterLazy.WriterT SymBool Maybe SymBool
                      )
                      @?= emptySet,
                  testCase "WriterT (Just (v1, v2))" $
                    extractSym
                      ( WriterLazy.WriterT
                          (Just (ssymBool "a", ssymBool "b")) ::
                          WriterLazy.WriterT SymBool Maybe SymBool
                      )
                      @?= buildSymbolSet (ssymbolBool "a", ssymbolBool "b")
                ],
              testGroup
                "Strict"
                [ testCase "WriterT Nothing" $
                    extractSym
                      ( WriterStrict.WriterT Nothing ::
                          WriterStrict.WriterT SymBool Maybe SymBool
                      )
                      @?= emptySet,
                  testCase "WriterT (Just (v1, v2))" $
                    extractSym
                      ( WriterStrict.WriterT
                          (Just (ssymBool "a", ssymBool "b")) ::
                          WriterStrict.WriterT SymBool Maybe SymBool
                      )
                      @?= buildSymbolSet (ssymbolBool "a", ssymbolBool "b")
                ]
            ],
          testProperty "()" (ioProperty . concreteExtractSymOkProp @()),
          testCase "(,)" $
            extractSym (ssymBool "a", ssymBool "b")
              @?= buildSymbolSet (ssymbolBool "a", ssymbolBool "b"),
          testCase "(,,)" $
            extractSym (ssymBool "a", ssymBool "b", ssymBool "c")
              @?= buildSymbolSet
                (ssymbolBool "a", ssymbolBool "b", ssymbolBool "c"),
          testGroup
            "ByteString"
            [ testCase "\"\"" $
                extractSym ("" :: B.ByteString) @?= emptySet,
              testCase "\"a\"" $
                extractSym ("a" :: B.ByteString) @?= emptySet
            ],
          testCase "Identity SymBool" $
            extractSym (Identity (ssymBool "a"))
              @?= buildSymbolSet (ssymbolBool "a"),
          testGroup
            "IdentityT (Either SymBool) SymBool"
            [ testCase "Identity (Left v)" $
                extractSym
                  ( IdentityT $ Left (ssymBool "a") ::
                      IdentityT (Either SymBool) SymBool
                  )
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "Identity (Right v)" $
                extractSym
                  ( IdentityT $ Right (ssymBool "a") ::
                      IdentityT (Either SymBool) SymBool
                  )
                  @?= buildSymbolSet (ssymbolBool "a")
            ]
        ],
      testGroup
        "deriving ExtractSym for ADT"
        [ testGroup
            "Simple ADT"
            [ testCase "A1" $
                extractSym A1 @?= emptySet,
              testCase "A2" $
                extractSym (A2 (ssymBool "a"))
                  @?= buildSymbolSet (ssymbolBool "a"),
              testCase "A3" $
                extractSym (A3 (ssymBool "a") (ssymBool "b"))
                  @?= buildSymbolSet (ssymbolBool "a", ssymbolBool "b")
            ]
        ]
    ]