haskus-utils-0.8.0.0: src/tests/Haskus/Tests/Utils/Solver.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TupleSections #-}
module Haskus.Tests.Utils.Solver
( testsSolver
)
where
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import Data.List
import Haskus.Utils.Solver
import Haskus.Utils.Flow
data Predi
= PredA
| PredB
| PredC
| PredD
| PredE
deriving (Show,Eq,Ord)
newtype Err
= Err String
deriving (Show,Eq,Ord)
type C = Constraint Err Predi
type R a t = RuleT Err Predi a t
data T
data NT
type family RuleT e p a s :: * where
RuleT e p a T = a
RuleT e p a NT = Rule e p a
data PD t = PD
{ pInt :: R Int t
, _pStr :: R String t
}
deriving instance Eq (PD T)
deriving instance Show (PD T)
deriving instance Ord (PD T)
deriving instance Eq (PD NT)
deriving instance Show (PD NT)
deriving instance Ord (PD NT)
instance Predicated (PD NT) where
type PredErr (PD NT) = Err
type Pred (PD NT) = Predi
type PredTerm (PD NT) = PD T
liftTerminal (PD a b) = PD (liftTerminal a) (liftTerminal b)
reducePredicates oracle (PD a b) =
initP PD PD
|> (`applyP` reducePredicates oracle a)
|> (`applyP` reducePredicates oracle b)
|> resultP
getTerminals (PD as bs) = [ PD a b | a <- getTerminals as
, b <- getTerminals bs
]
getPredicates (PD a b) = concat
[ getPredicates a
, getPredicates b
]
testsSolver :: TestTree
testsSolver = testGroup "Solver" $
[ testProperty "Constraint reduce: CBool True"
(constraintReduce oracleAll (CBool True) == (CBool True :: C))
, testProperty "Constraint reduce: CBool False"
(constraintReduce oracleAll (CBool False) == (CBool False :: C))
, testProperty "Constraint reduce: Not False"
(constraintReduce oracleAll (Not (CBool False)) == (CBool True :: C))
, testProperty "Constraint reduce: Not True"
(constraintReduce oracleAll (Not (CBool True)) == (CBool False :: C))
, testProperty "Constraint reduce: And [True,True]"
(constraintReduce oracleAll (And [CBool True,CBool True]) == (CBool True :: C))
, testProperty "Constraint reduce: And [True,False]"
(constraintReduce oracleAll (And [CBool True,CBool False]) == (CBool False :: C))
, testProperty "Constraint reduce: Or [True,True]"
(constraintReduce oracleAll (Or [CBool True,CBool True]) == (CBool True :: C))
, testProperty "Constraint reduce: Or [True,False]"
(constraintReduce oracleAll (Or [CBool True,CBool False]) == (CBool True :: C))
, testProperty "Constraint reduce: Or [False,False]"
(constraintReduce oracleAll (Or [CBool False,CBool False]) == (CBool False :: C))
, testProperty "Constraint reduce: Xor [True,False,True]"
(constraintReduce oracleAll (Xor [CBool True,CBool False,CBool True]) == (CBool False :: C))
, testProperty "Constraint reduce: Xor [True,False,False]"
(constraintReduce oracleAll (Xor [CBool True,CBool False,CBool False]) == (CBool True :: C))
, testProperty "Constraint reduce: Not (Xor [True,False,False])"
(constraintReduce oracleAll (Not (Xor [CBool True,CBool False,CBool False])) == (CBool False :: C))
, testProperty "Constraint reduce: Not (Xor [False,False,False])"
(constraintReduce oracleAll (Not (Xor [CBool False,CBool False,CBool False])) == (CBool True :: C))
, testProperty "Constraint reduce: matching oracle"
(constraintReduce oracleA (Predicate PredA) == (CBool True :: C))
, testProperty "Constraint reduce: non matching oracle"
(constraintReduce oracleB (Predicate PredA) == (CBool False :: C))
, testProperty "Constraint reduce: evalsTo 0"
(constraintReduce oracleAll (simpleRule `evalsTo` 0) == (CBool False :: C))
, testProperty "Constraint reduce: evalsTo 1"
(constraintReduce oracleAll (simpleRule `evalsTo` 1) == (CBool True :: C))
, testProperty "Constraint reduce: evals to D"
(constraintReduce oracleA (d1 `evalsTo` PD 0 "Test") == (CBool True :: C))
, testProperty "Evals to: Terminal 0"
(((Terminal 0 :: R Int NT) `evalsTo` 0) == (CBool True :: C))
, testProperty "Evals to: Terminal 1"
(((Terminal 1 :: R Int NT) `evalsTo` 0) == (CBool False :: C))
, testProperty "Predicated data: matching"
(reducePredicates oracleA d1 == Match (PD 0 "Test"))
, testProperty "Predicated data: not matching"
(case reducePredicates oracleB d1 of
NoMatch -> True
_ -> False
)
, testProperty "Predicated data: failing"
(case reducePredicates oracleC d1 of
MatchFail _ -> True
_ -> False
)
, testProperty "Predicated data: divergent"
(case reducePredicates oracleD d1 of
MatchDiverge xs -> sort xs == sort [d1 { pInt = Terminal 1}, d1 { pInt = Terminal 0}]
_ -> False
)
, testProperty "Predicated data: not terminal"
(case reducePredicates oracleAE d1 of
DontMatch _ -> True
_ -> False
)
, testProperty "Ordered non terminal 0"
(case reducePredicates oracleAB (orderedNonTerminal [(Predicate PredA, Terminal 0 :: R Int NT)
,(Predicate PredB, Terminal 1)
]) of
Match 0 -> True
_ -> False
)
, testProperty "Ordered non terminal 1"
(case reducePredicates oracleAB (orderedNonTerminal [(Predicate PredB, Terminal 1 :: R Int NT)
,(Predicate PredA, Terminal 0)
]) of
Match 1 -> True
_ -> False
)
, testProperty "Get predicates: flat"
(sort (getPredicates d1) == sort [PredA,PredC,PredD,PredE])
, testProperty "Get predicates: nested"
(sort (getPredicates d2) == sort [PredA,PredB,PredC,PredD])
, testProperty "Create predicate table: flat non terminal"
(case createPredicateTable d1 (const True) False of
Left _ -> False
Right xs -> sort (fmap (oraclePredicates . fst) xs) == sort
[ [(PredA, SetPred) , (PredC, UnsetPred), (PredD, UnsetPred), (PredE, UnsetPred)]
, [(PredA, SetPred) , (PredC, UnsetPred), (PredD, UnsetPred), (PredE, SetPred)]
, [(PredA, UnsetPred), (PredC, UnsetPred), (PredD, UnsetPred), (PredE, SetPred)]
]
)
, testProperty "Create predicate table: nested non terminal"
(case createPredicateTable d2 (const True) False of
Left _ -> False
Right xs -> sort (fmap (oraclePredicates . fst) xs) == sort
[ [(PredA,SetPred),(PredB,SetPred),(PredC,UnsetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,SetPred),(PredD,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,SetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,UnsetPred),(PredD,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,UnsetPred),(PredD,UnsetPred)]
, [(PredA,UnsetPred),(PredB,SetPred),(PredC,SetPred),(PredD,UnsetPred)]
, [(PredA,UnsetPred),(PredB,SetPred),(PredC,UnsetPred),(PredD,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredD,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred)]
]
)
, testProperty "Create full predicate table: nested non terminal"
(case createPredicateTable d2 (const True) True of
Left _ -> False
Right xs -> sort (fmap (oraclePredicates . fst) xs) == sort
[ [(PredA,SetPred),(PredB,UnsetPred),(PredC,SetPred),(PredD,SetPred)]
, [(PredA,UnsetPred),(PredB,SetPred),(PredC,UnsetPred),(PredD,SetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,UnsetPred),(PredD,SetPred)]
, [(PredA,UnsetPred),(PredB,SetPred),(PredC,SetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,SetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,SetPred),(PredC,UnsetPred),(PredD,UnsetPred)]
, [(PredA,SetPred),(PredB,UnsetPred),(PredC,UnsetPred),(PredD,UnsetPred)]
]
)
]
where
oracleAll = makeOracle (fmap (,SetPred) [PredA,PredB,PredC,PredD,PredE])
oracleA = makeOracle ((PredA,SetPred) : fmap (,UnsetPred) [PredB,PredC,PredD,PredE])
oracleB = makeOracle ((PredB,SetPred) : fmap (,UnsetPred) [PredA,PredC,PredD,PredE])
oracleC = makeOracle ((PredC,SetPred) : fmap (,UnsetPred) [PredA,PredB,PredD,PredE])
oracleD = makeOracle ((PredD,SetPred) : fmap (,UnsetPred) [PredA,PredB,PredC,PredE])
oracleAE = makeOracle ((PredA,UndefPred) : (PredD,UndefPred) : fmap (,UnsetPred) [PredB,PredC,PredE])
oracleAB = makeOracle ((PredA,SetPred) : (PredB,SetPred) : fmap (,UnsetPred) [PredC,PredD,PredE])
simpleRule :: R Int NT
simpleRule = NonTerminal
[ (CBool False, Terminal 0)
, (CBool True, Terminal 1)
]
d1 :: PD NT
d1 = PD (NonTerminal [ (Predicate PredA, Terminal 0)
, (Predicate PredC, Fail (Err "D doesn't support predicate C"))
, (Predicate PredD, Terminal 0)
, (Predicate PredD, Terminal 1)
, (Predicate PredE, Terminal 0)
])
(Terminal "Test")
d2 :: PD NT
d2 = PD (NonTerminal [ (Predicate PredA, Terminal 0)
, (Predicate PredB, NonTerminal
[ (Predicate PredC, Terminal 1)
, (Predicate PredD, Terminal 2)
])
])
(Terminal "Test")