Skip to content

Commit 19cbafe

Browse files
committed
Test diffBy against a model
1 parent e79f2ad commit 19cbafe

File tree

5 files changed

+83
-4
lines changed

5 files changed

+83
-4
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
`Pretty` datastructure is changed.
55
- Change `Expr` to use `OMap`; pretty-printing preserves field order.
66
- Add `strict` and `these` instances
7+
- Add `Eq` and `NFData (Edit a)` instances.
78
- Bump lower bounds
89

910
## 0.1

src-diff/RefDiffBy.hs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{-# LANGUAGE ScopedTypeVariables #-}
2+
module RefDiffBy (diffBy) where
3+
4+
import Data.TreeDiff.List (Edit (..))
5+
6+
import qualified Data.Primitive as P
7+
8+
diffBy :: forall a. (a -> a -> Bool) -> [a] -> [a] -> [Edit a]
9+
diffBy eq xs' ys' = reverse (getCell (lcs xn yn))
10+
where
11+
xn = length xs'
12+
yn = length ys'
13+
14+
xs = P.arrayFromListN xn xs'
15+
ys = P.arrayFromListN yn ys'
16+
17+
memo :: P.Array (Cell [Edit a])
18+
memo = P.arrayFromListN ((xn + 1) * (yn + 1))
19+
[ impl xi yi
20+
| xi <- [0 .. xn]
21+
, yi <- [0 .. yn]
22+
]
23+
24+
lcs :: Int -> Int -> Cell [Edit a]
25+
lcs xi yi = P.indexArray memo (yi + xi * (yn + 1))
26+
27+
impl :: Int -> Int -> Cell [Edit a]
28+
impl 0 0 = Cell 0 []
29+
impl 0 m = case lcs 0 (m - 1) of
30+
Cell w edit -> Cell (w + 1) (Ins (P.indexArray ys (m - 1)) : edit)
31+
impl n 0 = case lcs (n - 1) 0 of
32+
Cell w edit -> Cell (w + 1) (Del (P.indexArray xs (n - 1)) : edit)
33+
34+
impl n m = bestOfThree
35+
edit
36+
(bimap (+1) (Ins y :) (lcs n (m - 1)))
37+
(bimap (+1) (Del x :) (lcs (n - 1) m))
38+
where
39+
x = P.indexArray xs (n - 1)
40+
y = P.indexArray ys (m - 1)
41+
42+
edit
43+
| eq x y = bimap id (Cpy x :) (lcs (n - 1) (m - 1))
44+
| otherwise = bimap (+1) (Swp x y :) (lcs (n - 1) (m - 1))
45+
46+
data Cell a = Cell !Int !a
47+
48+
getCell :: Cell a -> a
49+
getCell (Cell _ x) = x
50+
51+
bestOfThree :: Cell a -> Cell a -> Cell a -> Cell a
52+
bestOfThree a@(Cell i _x) b@(Cell j _y) c@(Cell k _z)
53+
| i <= j
54+
= if i <= k then a else c
55+
56+
| otherwise
57+
= if j <= k then b else c
58+
59+
bimap :: (Int -> Int) -> (a -> b) -> Cell a -> Cell b
60+
bimap f g (Cell i x) = Cell (f i) (g x)

src/Data/TreeDiff/List.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{-# LANGUAGE ScopedTypeVariables #-}
22
-- | A list diff.
3-
module Data.TreeDiff.List (diffBy, Edit (..)) where
3+
module Data.TreeDiff.List (
4+
diffBy,
5+
Edit (..),
6+
) where
47

58
import Control.DeepSeq (NFData (..))
69

@@ -15,7 +18,7 @@ data Edit a
1518
| Del a -- ^ delete
1619
| Cpy a -- ^ copy unchanged
1720
| Swp a a -- ^ swap, i.e. delete + insert
18-
deriving Show
21+
deriving (Eq, Show)
1922

2023
instance NFData a => NFData (Edit a) where
2124
rnf (Ins x) = rnf x

tests/Tests.hs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
module Main (main) where
33

44
import Data.Proxy (Proxy (..))
5+
import Data.Word (Word8)
56
import GHC.Generics (Generic)
67
import Prelude ()
78
import Prelude.Compat
8-
import Test.QuickCheck (Property, counterexample)
9+
import Test.QuickCheck (Property, counterexample, (===))
910
import Test.Tasty (TestTree, defaultMain, testGroup)
1011
import Test.Tasty.Golden.Advanced (goldenTest)
1112
import Test.Tasty.QuickCheck (testProperty)
@@ -17,15 +18,27 @@ import qualified Text.Trifecta.Result as T (ErrInfo (..), Result (..))
1718

1819
import Data.TreeDiff
1920
import Data.TreeDiff.Golden
21+
import Data.TreeDiff.List
2022
import Data.TreeDiff.QuickCheck
2123

24+
import qualified RefDiffBy
25+
2226
main :: IO ()
2327
main = defaultMain $ testGroup "tests"
2428
[ testProperty "trifecta-pretty roundtrip" roundtripTrifectaPretty
2529
, testProperty "parsec-ansi-wl-pprint roundtrip" roundtripParsecAnsiWl
30+
, testProperty "diffBy model" diffByModel
2631
, goldenTests
2732
]
2833

34+
-------------------------------------------------------------------------------
35+
-- diffBy
36+
-------------------------------------------------------------------------------
37+
38+
diffByModel :: [Word8] -> [Word8] -> Property
39+
diffByModel xs ys =
40+
diffBy (==) xs ys === RefDiffBy.diffBy (==) xs ys
41+
2942
-------------------------------------------------------------------------------
3043
-- Roundtrip
3144
-------------------------------------------------------------------------------

tree-diff.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ test-suite tree-diff-test
143143
default-language: Haskell2010
144144
type: exitcode-stdio-1.0
145145
main-is: Tests.hs
146-
hs-source-dirs: tests
146+
hs-source-dirs: tests src-diff
147147
ghc-options: -Wall -threaded
148+
other-modules: RefDiffBy
148149

149150
-- dependencies from library
150151
build-depends:
@@ -153,6 +154,7 @@ test-suite tree-diff-test
153154
, base
154155
, base-compat
155156
, parsec
157+
, primitive
156158
, QuickCheck
157159
, tagged
158160
, tree-diff

0 commit comments

Comments
 (0)