hdiff-0.0.0: tests/Data/Digems/Patch/ThinningSpec.hs
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
module Data.Digems.Patch.ThinningSpec (spec) where
import qualified Data.Set as S
import Generics.MRSOP.Base
import Generics.MRSOP.Util
import Generics.MRSOP.Holes
import Data.Functor.Const
import Data.Exists
import Data.Digems.Patch
import Data.Digems.Diff
import Data.Digems.Patch.Show
import Data.Digems.Patch.Thinning as PT
import qualified Data.Digems.Change.Thinning as CT
import Data.Digems.MetaVar
import Data.Digems.Change
import Languages.RTree
import Languages.RTree.Diff
import Test.QuickCheck
import Test.Hspec
import Control.Monad.State
import Control.Monad.Cont
import qualified Data.Map as M
context_alpha_eq :: (EqHO ki)
=> Holes ki codes (MetaVarIK ki) at
-> Holes ki codes (MetaVarIK ki) at
-> Bool
context_alpha_eq x y = aux
where
aux :: Bool
aux = (`runCont` id) $
callCC $ \exit -> flip evalStateT M.empty $ do
holesMapM (uncurry' (check (cast exit $ False))) (holesLCP x y)
return True
cast :: (Bool -> Cont Bool b)
-> Bool -> Cont Bool (Const () a)
cast f b = (const (Const ())) <$> f b
check :: (Cont Bool (Const () at))
-> Holes ki codes (MetaVarIK ki) at
-> Holes ki codes (MetaVarIK ki) at
-> StateT (M.Map Int Int) (Cont Bool) (Const () at)
check exitF (Hole _ vx) (Hole _ vy) = do
m <- get
case M.lookup (metavarGet vx) m of
Nothing -> modify (M.insert (metavarGet vx) (metavarGet vy))
>> return (Const ())
Just vz -> if metavarGet vy /= vz
then lift exitF
else return (Const ())
check exitF _ _ = lift exitF
thin_domain_eq :: DiffMode -> Property
thin_domain_eq mode = forAll genSimilarTrees'' $ \(a , o , b)
-> let oa = digemRTreeHM mode 1 o a
ob = digemRTreeHM mode 1 o b
in case (,) <$> PT.thin oa ob <*> PT.thin ob oa of
Left err -> counterexample ("Thinning failed with: " ++ show err) False
Right (oa' , ob') ->
property $ context_alpha_eq
(domain $ distrCChange oa')
(domain $ distrCChange ob')
-----------------------------
thin_respect_spans :: DiffMode -> Property
thin_respect_spans mode = forAll genSimilarTrees'' $ \(a , o , b)
-> let oa = digemRTreeHM mode 1 o a
ob = digemRTreeHM mode 1 o b
in case PT.thin oa ob of
Left err -> counterexample ("Thinning failed with: " ++ show err) False
Right oa' -> property $ applyRTree oa' o == Right a
---------------------------
thin_pp_is_p :: DiffMode -> Property
thin_pp_is_p mode = forAll genSimilarTrees' $ \(a , b)
-> let ab = digemRTreeHM mode 1 a b
in case PT.thin ab ab of
Left err -> counterexample ("Thinning failed with: " ++ show err) False
Right ab' -> property $ patchEq ab ab'
-------------------------------
lf :: String -> RTree
lf x = x :>: []
bin :: RTree -> RTree -> RTree
bin l r = "bin" :>: [l , r]
a1 , o1 , b1 :: RTree
a1 = bin (bin (lf "w") (lf "z")) (bin (lf "x") (lf "y"))
o1 = bin (bin (lf "x") (lf "y")) (bin (lf "w") (lf "z"))
b1 = bin (bin (lf "y") (lf "x")) (bin (lf "w") (lf "z"))
oa1 = digemRTree o1 a1
ob1 = digemRTree o1 b1 `withFreshNamesFrom` oa1
coa1 = distrCChange oa1
cob1 = distrCChange ob1
---------------------
a2 , o2 , b2 :: RTree
a2 = "e" :>: ["j" :>: []]
o2 = "e" :>: ["a" :>: ["j" :>: []],"a" :>: ["j" :>: []]]
b2 = "a" :>: ["j" :>: [],"e" :>: []]
oa2 = digemRTree o2 a2
ob2 = digemRTree o2 b2 `withFreshNamesFrom` oa2
coa2 = distrCChange oa2
cob2 = distrCChange ob2
-----------------------
--
a3 , o3 , b3 :: RTree
a3 = "e" :>: ["a" :>: [], "B" :>: [], "c" :>: []]
o3 = "e" :>: ["a" :>: [], "b" :>: [], "c" :>: []]
b3 = "e" :>: ["A" :>: [], "b" :>: [], "c" :>: []]
oa3 = digemRTree o3 a3
ob3 = digemRTree o3 b3
a4 = "k" :>: ["b" :>: [],"f" :>: []]
o4 = "k" :>: ["b" :>: [],"b" :>: []]
b4 = "k" :>: ["m" :>: [],"b" :>: []]
oa4 = digemRTree o4 a4
ob4 = digemRTree o4 b4
Right coa4 = PT.thin oa4 ob4
Right cob4 = PT.thin ob4 oa4
ca = domain $ distrCChange coa4
cb = domain $ distrCChange cob4
ok = context_alpha_eq ca cb
spec :: Spec
spec = do
flip mapM_ (enumFrom (toEnum 0)) $ \m -> do
describe ("thin (" ++ show m ++ ")") $ do
it "is always possible for spans" $ property (thin_respect_spans m)
it "is symmetric w.r.t. domains" $ property (thin_domain_eq m)
it "respects: thin p p == p" $ property (thin_pp_is_p m)