patches-vector 0.1.5.0 → 0.1.5.1
raw patch · 8 files changed
+119/−47 lines, 8 filesdep +hspecdep ~microlensPVP ok
version bump matches the API change (PVP)
Dependencies added: hspec
Dependency ranges changed: microlens
API changes (from Hackage documentation)
Files
- Data/Patch/Internal.hs +6/−39
- doctest.hs +4/−0
- patches-vector.cabal +13/−4
- test/Data/Patch/InternalSpec.hs +16/−0
- test/Spec.hs +1/−0
- test/Test/Util.hs +40/−0
- test/Test/UtilSpec.hs +39/−0
- tests.hs +0/−4
Data/Patch/Internal.hs view
@@ -15,35 +15,9 @@ import Control.Monad.ST -- $setup -- >>> import Test.QuickCheck--- >>> :{--- let--- nonEmpty :: Vector a -> Bool--- nonEmpty = (>0) . Vector.length--- editsTo :: Arbitrary a => Vector a -> Gen (Edit a)--- editsTo v = do--- i <- choose (0, Vector.length v -1)--- c <- elements [const (Insert i), \o _ -> Delete i o, Replace i]--- x <- arbitrary--- return $ c (v Vector.! i) x--- patchesFrom' :: (Eq a, Arbitrary a) => Vector a -> Gen (Patch a)--- patchesFrom' v | Vector.length v > 0 = fromList <$> listOf (editsTo v)--- patchesFrom' _ | otherwise = fromList <$> listOf (Insert 0 <$> arbitrary)--- patchesFrom :: Vector Int -> Gen (Patch Int)--- patchesFrom = patchesFrom'--- divergingPatchesFrom :: Vector Int -> Gen (Patch Int, Patch Int)--- divergingPatchesFrom v = (,) <$> patchesFrom v <*> patchesFrom v--- historyFrom d 0 = return []--- historyFrom d m = do--- p <- patchesFrom d--- r <- historyFrom (apply p d) $ m - 1--- return (p:r)--- :}+-- >>> import Test.Util -- -- >>> :set -XScopedTypeVariables--- >>> instance Arbitrary a => Arbitrary (Vector a) where arbitrary = Vector.fromList <$> listOf arbitrary------ Blah--- -- $doctest_sucks -- prop> forAll (patchesFrom d) $ \ x -> read (show x) == x@@ -53,7 +27,7 @@ -- of 'Edit', and can be converted to and from raw lists of edits using 'toList' and 'fromList' -- respectively. ----- Patches form a groupoid (a 'Monoid' with inverses, and a partial composition relation), +-- Patches form a groupoid (a 'Monoid' with inverses, and a partial composition relation), -- where the inverse element can be computed with 'inverse' and the groupoid operation -- is /composition/ of patches. Applying @p1 <> p2@ is the same as applying @p1@ /then/ -- @p2@ (see 'apply'). This composition operator may produce structurally@@ -70,7 +44,7 @@ -- -- prop> forAll (historyFrom d 3) $ \[a, b, c] -> apply (a <> (b <> c)) d == apply ((a <> b) <> c) d ----- The indices of the 'Edit' s are all based on the /original document/, so:+-- The indices of the 'Edit' s of one 'Patch' are all based on the /original document/, so: -- -- >>> Vector.toList $ apply (fromList [Insert 0 'a', Insert 1 'b']) (Vector.fromList "123") -- "a1b23"@@ -199,11 +173,6 @@ -- | Returns true if a patch can be safely applied to a document, that is, -- @applicable p d@ holds when @d@ is a valid source document for the patch @p@.------ prop> applicable mempty d--- prop> forAll (patchesFrom d) $ \p -> applicable p d--- prop> forAll (historyFrom d 2) $ \[p, q] -> applicable p d && applicable q (apply p d)--- prop> forAll (historyFrom d 2) $ \[p, q] -> applicable (p <> q) d applicable :: (Eq a) => Patch a -> Vector a -> Bool applicable (Patch s) i = all applicable' s where@@ -217,10 +186,6 @@ -- | Returns true if a patch can be validly composed with another. -- That is, @composable p q@ holds if @q@ can be validly applied after @p@.------ prop> forAll (patchesFrom d) $ \p -> composable mempty p--- prop> forAll (patchesFrom d) $ \p -> composable p mempty--- prop> forAll (historyFrom d 2) $ \[p, q] -> composable p q composable :: Eq a => Patch a -> Patch a -> Bool composable (Patch a) (Patch b) = go a b (0 :: Int) where@@ -246,6 +211,8 @@ -- | Returns the delta of the document's size when a patch is applied. -- Essentially the number of @Insert@ minus the number of @Delete@.+--+-- prop> forAll (patchesFrom d) $ \ p -> sizeChange p == Data.Vector.length (apply p d) - Data.Vector.length d sizeChange :: Patch a -> Int sizeChange (Patch s) = foldr (\c d -> d + offset c) 0 s where offset (Delete {}) = -1@@ -315,7 +282,7 @@ go [] _ [] _ = ([],[]) go xs a [] _ = (map (over index (+ a)) xs, []) go [] _ ys b = ([], map (over index (+ b)) ys)- go (x:xs) a (y:ys) b = + go (x:xs) a (y:ys) b = case comparing (^. index) x y of LT -> over _1 (over index (+ a) x:) $ go xs a (y:ys) (b + offset x) GT -> over _2 (over index (+ b) y:) $ go (x:xs) (a + offset y) ys b
+ doctest.hs view
@@ -0,0 +1,4 @@+import Test.DocTest++main :: IO ()+main = doctest ["Data/Patch/Internal.hs", "-i", "test", "-i."]
patches-vector.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: patches-vector-version: 0.1.5.0+version: 0.1.5.1 synopsis: Patches (diffs) on vectors: composable, mergeable, and invertible. description: A patch is a collection of modifications (edits) to be made to a sequence of elements. Commonly found in version control systems, patches are also a simple example of a groupoid, supporting (partial) composition@@ -32,12 +32,12 @@ exposed-modules: Data.Patch , Data.Patch.Internal build-depends: base >=4.7 && <4.9, edit-distance-vector >=1.0 && <1.1, vector >= 0.10 && < 0.12- , microlens >= 0.2 && < 0.4+ , microlens >= 0.2 && < 0.5 default-language: Haskell2010 -test-suite test-patches-vector+test-suite doctest-patches-vector type: exitcode-stdio-1.0- main-is: tests.hs+ main-is: doctest.hs build-depends: base >= 4.7 && < 4.9, QuickCheck >= 2.7 && < 2.9, patches-vector, doctest >= 0.9 && < 0.11 default-language: Haskell2010 @@ -46,3 +46,12 @@ main-is: benchmarks.hs hs-source-dirs: bm build-depends: base >= 4.7 && < 4.9, QuickCheck >= 2.7 && < 2.9, patches-vector, criterion >= 1.1 && < 1.2, vector >= 0.10 && <0.12++test-suite spec-patches-vector+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test+ other-modules: Data.Patch.InternalSpec+ , Test.Util+ , Test.UtilSpec+ build-depends: base >= 4.7 && < 4.9, QuickCheck >= 2.7 && < 2.9, patches-vector, criterion >= 1.1 && < 1.2, vector >= 0.10 && <0.12, hspec >= 2.1 && < 2.3
+ test/Data/Patch/InternalSpec.hs view
@@ -0,0 +1,16 @@++module Data.Patch.InternalSpec where++import Data.Monoid+import Test.Hspec+import Test.QuickCheck++import Data.Patch.Internal+import Test.Util ()++spec :: Spec+spec = do+ describe "applicable" $ do+ it "mempty is always applicable" $ do+ property $ \d ->+ applicable (mempty :: Patch Int) d
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Test/Util.hs view
@@ -0,0 +1,40 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Test.Util where++import Control.Applicative+import Data.Vector (Vector)+import qualified Data.Vector as Vector+import Test.QuickCheck++import Data.Patch++nonEmpty :: Vector a -> Bool+nonEmpty = (>0) . Vector.length++editsTo :: Arbitrary a => Vector a -> Gen (Edit a)+editsTo v = do+ i <- choose (0, Vector.length v -1)+ c <- elements [const (Insert i), \o _ -> Delete i o, Replace i]+ x <- arbitrary+ return $ c (v Vector.! i) x++patchesFrom' :: (Eq a, Arbitrary a) => Vector a -> Gen (Patch a)+patchesFrom' v | Vector.length v > 0 = fromList <$> listOf (editsTo v)+patchesFrom' _ | otherwise = fromList <$> listOf (Insert 0 <$> arbitrary)++patchesFrom :: Vector Int -> Gen (Patch Int)+patchesFrom = patchesFrom'++divergingPatchesFrom :: Vector Int -> Gen (Patch Int, Patch Int)+divergingPatchesFrom v = (,) <$> patchesFrom v <*> patchesFrom v++historyFrom :: Vector Int -> Int -> Gen [Patch Int]+historyFrom _ 0 = return []+historyFrom d m = do+ p <- patchesFrom d+ r <- historyFrom (apply p d) $ m - 1+ return (p:r)++instance Arbitrary a => Arbitrary (Vector a) where+ arbitrary = Vector.fromList <$> listOf arbitrary
+ test/Test/UtilSpec.hs view
@@ -0,0 +1,39 @@++module Test.UtilSpec where++import Data.Monoid+import Test.Hspec+import Test.QuickCheck++import Data.Patch.Internal+import Test.Util++spec :: Spec+spec = do+ describe "patchesFrom" $ do+ it "creates applicable patches" $ do+ property $ \d ->+ forAll (patchesFrom d) $ \p -> applicable p d++ it "creates patches that are right-composable with mempty" $ do+ property $ \d ->+ forAll (patchesFrom d) $ \p -> composable mempty p++ it "creates patches that are left-composable with mempty" $ do+ property $ \d ->+ forAll (patchesFrom d) $ \p -> composable p mempty++ describe "historyFrom" $ do+ it "creates patches that are applicable in sequence" $ do+ property $ \d ->+ forAll (historyFrom d 2) $ \[p, q] ->+ applicable p d && applicable q (apply p d)++ it "creates patches that are applicable in merged form" $ do+ property $ \d ->+ forAll (historyFrom d 2) $ \[p, q] ->+ applicable (p <> q) d++ it "creates patches that are composable" $ do+ property $ \d ->+ forAll (historyFrom d 2) $ \[p, q] -> composable p q
− tests.hs
@@ -1,4 +0,0 @@-import Test.DocTest--main :: IO ()-main = doctest ["Data/Patch/Internal.hs"]