2016-06-27 22:28:11 +03:00
|
|
|
{-# LANGUAGE DataKinds #-}
|
2018-12-01 03:23:29 +03:00
|
|
|
module Diffing.Interpreter.Spec (spec, afterTerm, beforeTerm) where
|
2015-12-16 22:18:09 +03:00
|
|
|
|
2018-07-20 16:56:33 +03:00
|
|
|
import Control.Applicative ((<|>))
|
2017-09-27 19:41:41 +03:00
|
|
|
import Data.Diff
|
2018-07-20 16:56:33 +03:00
|
|
|
import Data.Foldable (asum)
|
2018-07-20 17:04:34 +03:00
|
|
|
import Data.Functor.Foldable (cata)
|
2017-01-09 22:20:11 +03:00
|
|
|
import Data.Functor.Listable
|
2018-06-04 19:18:02 +03:00
|
|
|
import Data.Maybe
|
2018-09-25 19:18:51 +03:00
|
|
|
import Data.Location
|
2018-07-20 16:53:52 +03:00
|
|
|
import Data.Mergeable
|
2018-07-20 17:04:34 +03:00
|
|
|
import Data.Patch (after, before)
|
2018-05-02 19:00:15 +03:00
|
|
|
import Data.Sum
|
2017-09-27 19:37:37 +03:00
|
|
|
import Data.Term
|
2018-05-14 23:09:39 +03:00
|
|
|
import Data.These
|
2017-11-27 19:45:08 +03:00
|
|
|
import Diffing.Interpreter
|
2018-03-08 04:01:47 +03:00
|
|
|
import qualified Data.Syntax as Syntax
|
2016-09-15 00:45:23 +03:00
|
|
|
import Test.Hspec (Spec, describe, it, parallel)
|
|
|
|
import Test.Hspec.Expectations.Pretty
|
2017-01-09 22:20:11 +03:00
|
|
|
import Test.Hspec.LeanCheck
|
2018-06-04 19:18:02 +03:00
|
|
|
import Test.LeanCheck.Core
|
2018-06-29 23:17:27 +03:00
|
|
|
import SpecHelpers
|
2015-12-16 22:18:09 +03:00
|
|
|
|
|
|
|
spec :: Spec
|
2016-06-27 20:08:12 +03:00
|
|
|
spec = parallel $ do
|
2017-10-23 18:58:31 +03:00
|
|
|
describe "diffTerms" $ do
|
2015-12-16 22:18:09 +03:00
|
|
|
it "returns a replacement when comparing two unicode equivalent terms" $
|
2018-09-25 19:18:51 +03:00
|
|
|
let termA = termIn emptyAnnotation (inject (Syntax.Identifier "t\776"))
|
|
|
|
termB = termIn emptyAnnotation (inject (Syntax.Identifier "\7831")) in
|
2018-09-26 00:52:40 +03:00
|
|
|
diffTerms termA termB `shouldBe` replacing termA (termB :: Term ListableSyntax ())
|
2016-06-27 22:28:11 +03:00
|
|
|
|
|
|
|
prop "produces correct diffs" $
|
2018-09-26 00:52:40 +03:00
|
|
|
\ a b -> let diff = diffTerms a b :: Diff ListableSyntax () () in
|
2017-09-14 02:34:27 +03:00
|
|
|
(beforeTerm diff, afterTerm diff) `shouldBe` (Just a, Just b)
|
2016-06-30 20:34:31 +03:00
|
|
|
|
2017-10-23 18:58:43 +03:00
|
|
|
prop "produces identity diffs for equal terms " $
|
2018-09-26 00:52:40 +03:00
|
|
|
\ a -> let diff = diffTerms a a :: Diff ListableSyntax () () in
|
2017-10-23 16:37:47 +03:00
|
|
|
length (diffPatches diff) `shouldBe` 0
|
2016-08-11 19:23:34 +03:00
|
|
|
|
2016-08-12 19:16:48 +03:00
|
|
|
it "produces unbiased insertions within branches" $
|
2018-09-26 00:52:40 +03:00
|
|
|
let term s = termIn emptyAnnotation (inject [ termIn emptyAnnotation (inject (Syntax.Identifier s)) ]) :: Term ListableSyntax ()
|
2018-09-25 19:18:51 +03:00
|
|
|
wrap = termIn emptyAnnotation . inject in
|
|
|
|
diffTerms (wrap [ term "b" ]) (wrap [ term "a", term "b" ]) `shouldBe` merge (emptyAnnotation, emptyAnnotation) (inject [ inserting (term "a"), merging (term "b") ])
|
2017-09-28 18:24:51 +03:00
|
|
|
|
2018-06-04 19:18:02 +03:00
|
|
|
let noContext :: Term ListableSyntax a -> Bool
|
|
|
|
noContext = isNothing . project @Syntax.Context . termOut
|
|
|
|
|
|
|
|
prop "compares nodes against context" . forAll (filterT (noContext . fst) tiers) $
|
2018-09-26 00:52:40 +03:00
|
|
|
\ (a, b) -> diffTerms a (termIn emptyAnnotation (inject (Syntax.Context (pure b) a))) `shouldBe` insertF (In emptyAnnotation (inject (Syntax.Context (pure (inserting b)) (merging (a :: Term ListableSyntax ())))))
|
2017-10-23 18:58:52 +03:00
|
|
|
|
|
|
|
prop "diffs forward permutations as changes" $
|
2018-09-25 19:18:51 +03:00
|
|
|
\ a -> let wrap = termIn emptyAnnotation . inject
|
2017-10-23 18:58:52 +03:00
|
|
|
b = wrap [a]
|
|
|
|
c = wrap [a, b] in
|
2018-09-26 00:52:40 +03:00
|
|
|
diffTerms (wrap [a, b, c]) (wrap [c, a, b :: Term ListableSyntax ()]) `shouldBe` merge (emptyAnnotation, emptyAnnotation) (inject [ inserting c, merging a, merging b, deleting c ])
|
2017-10-23 18:58:52 +03:00
|
|
|
|
|
|
|
prop "diffs backward permutations as changes" $
|
2018-09-25 19:18:51 +03:00
|
|
|
\ a -> let wrap = termIn emptyAnnotation . inject
|
2017-10-23 18:58:52 +03:00
|
|
|
b = wrap [a]
|
|
|
|
c = wrap [a, b] in
|
2018-09-26 00:52:40 +03:00
|
|
|
diffTerms (wrap [a, b, c]) (wrap [b, c, a :: Term ListableSyntax ()]) `shouldBe` merge (emptyAnnotation, emptyAnnotation) (inject [ deleting a, merging b, merging c, inserting a ])
|
2018-05-14 23:09:39 +03:00
|
|
|
|
|
|
|
describe "diffTermPair" $ do
|
|
|
|
prop "produces an Insert when the first term is missing" $ do
|
2018-09-26 00:52:40 +03:00
|
|
|
\ after -> let diff = diffTermPair (That after) :: Diff ListableSyntax () () in
|
2018-05-14 23:09:39 +03:00
|
|
|
diff `shouldBe` inserting after
|
|
|
|
|
|
|
|
prop "produces a Delete when the second term is missing" $ do
|
2018-09-26 00:52:40 +03:00
|
|
|
\ before -> let diff = diffTermPair (This before) :: Diff ListableSyntax () () in
|
2018-05-14 23:09:39 +03:00
|
|
|
diff `shouldBe` deleting before
|
2018-07-20 16:52:11 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- | Recover the before state of a diff.
|
|
|
|
beforeTerm :: (Foldable syntax, Mergeable syntax) => Diff syntax ann1 ann2 -> Maybe (Term syntax ann1)
|
|
|
|
beforeTerm = cata $ \ diff -> case diff of
|
|
|
|
Patch patch -> (before patch >>= \ (In a l) -> termIn a <$> sequenceAlt l) <|> (after patch >>= asum)
|
|
|
|
Merge (In (a, _) l) -> termIn a <$> sequenceAlt l
|
|
|
|
|
|
|
|
-- | Recover the after state of a diff.
|
|
|
|
afterTerm :: (Foldable syntax, Mergeable syntax) => Diff syntax ann1 ann2 -> Maybe (Term syntax ann2)
|
|
|
|
afterTerm = cata $ \ diff -> case diff of
|
|
|
|
Patch patch -> (after patch >>= \ (In b r) -> termIn b <$> sequenceAlt r) <|> (before patch >>= asum)
|
|
|
|
Merge (In (_, b) r) -> termIn b <$> sequenceAlt r
|
2018-09-25 19:18:51 +03:00
|
|
|
|
2018-09-26 00:52:40 +03:00
|
|
|
emptyAnnotation :: ()
|
|
|
|
emptyAnnotation = ()
|