Hello community, here is the log from the commit of package ghc-Diff for openSUSE:Factory checked in at 2016-10-19 13:02:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-Diff (Old) and /work/SRC/openSUSE:Factory/.ghc-Diff.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-Diff" Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-Diff/ghc-Diff.changes 2016-09-24 15:20:37.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-Diff.new/ghc-Diff.changes 2016-10-19 13:02:25.000000000 +0200 @@ -1,0 +2,5 @@ +Thu Sep 15 06:47:00 UTC 2016 - psim...@suse.com + +- Update to version 0.3.4 revision 0 with cabal2obs. + +------------------------------------------------------------------- Old: ---- 1.cabal Diff-0.3.2.tar.gz New: ---- Diff-0.3.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-Diff.spec ++++++ --- /var/tmp/diff_new_pack.CeUQ1a/_old 2016-10-19 13:02:26.000000000 +0200 +++ /var/tmp/diff_new_pack.CeUQ1a/_new 2016-10-19 13:02:26.000000000 +0200 @@ -17,22 +17,27 @@ %global pkg_name Diff +%bcond_with tests Name: ghc-%{pkg_name} -Version: 0.3.2 +Version: 0.3.4 Release: 0 Summary: O(ND) diff algorithm in haskell License: BSD-3-Clause -Group: System/Libraries +Group: Development/Languages/Other Url: https://hackage.haskell.org/package/%{pkg_name} Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz -Source1: https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/1.cabal BuildRequires: ghc-Cabal-devel -# Begin cabal-rpm deps: BuildRequires: ghc-array-devel BuildRequires: ghc-pretty-devel BuildRequires: ghc-rpm-macros BuildRoot: %{_tmppath}/%{name}-%{version}-build -# End cabal-rpm deps +%if %{with tests} +BuildRequires: ghc-QuickCheck-devel +BuildRequires: ghc-directory-devel +BuildRequires: ghc-process-devel +BuildRequires: ghc-test-framework-devel +BuildRequires: ghc-test-framework-quickcheck2-devel +%endif %description Implementation of the standard diff algorithm, and utilities for pretty @@ -51,16 +56,15 @@ %prep %setup -q -n %{pkg_name}-%{version} -cp -p %{SOURCE1} %{pkg_name}.cabal - %build %ghc_lib_build - %install %ghc_lib_install +%check +%cabal_test %post devel %ghc_pkg_recache ++++++ Diff-0.3.2.tar.gz -> Diff-0.3.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Diff-0.3.2/Diff.cabal new/Diff-0.3.4/Diff.cabal --- old/Diff-0.3.2/Diff.cabal 2015-05-04 06:32:36.000000000 +0200 +++ new/Diff-0.3.4/Diff.cabal 2016-04-23 07:21:46.000000000 +0200 @@ -1,5 +1,5 @@ name: Diff -version: 0.3.2 +version: 0.3.4 synopsis: O(ND) diff algorithm in haskell. description: Implementation of the standard diff algorithm, and utilities for pretty printing. category: Algorithms @@ -9,10 +9,10 @@ maintainer: s.clo...@gmail.com Tested-With: GHC == 7.8.4 Build-Type: Simple -Cabal-Version: >= 1.6 +Cabal-Version: >= 1.8 library - build-depends: base >= 3 && <= 6, array, pretty + build-depends: base >= 3 && <= 6, array, pretty >= 1.1 hs-source-dirs: src exposed-modules: Data.Algorithm.Diff, @@ -23,3 +23,12 @@ source-repository head type: darcs location: http://hub.darcs.net/sterlingclover/Diff + +test-suite diff-tests + type: exitcode-stdio-1.0 + hs-source-dirs: test, src + main-is: Test.hs + build-depends: base >= 3 && <= 6, array + , pretty, QuickCheck, test-framework + , test-framework-quickcheck2, process + , directory diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Diff-0.3.2/src/Data/Algorithm/DiffOutput.hs new/Diff-0.3.4/src/Data/Algorithm/DiffOutput.hs --- old/Diff-0.3.2/src/Data/Algorithm/DiffOutput.hs 2015-05-04 06:32:36.000000000 +0200 +++ new/Diff-0.3.4/src/Data/Algorithm/DiffOutput.hs 2016-04-23 07:21:45.000000000 +0200 @@ -13,14 +13,13 @@ module Data.Algorithm.DiffOutput where import Data.Algorithm.Diff import Text.PrettyPrint +import Data.Char +import Data.List import Data.Monoid (mappend) --- | pretty print the differences. The output is similar to the output of the diff utility -ppDiff :: [Diff [String]] -> String -ppDiff gdiff = - let diffLineRanges = toLineRange 1 1 gdiff - in - render (prettyDiffs diffLineRanges) ++ "\n" +-- | Converts Diffs to DiffOperations +diffToLineRanges :: [Diff [String]] -> [DiffOperation LineRange] +diffToLineRanges = toLineRange 1 1 where toLineRange :: Int -> Int -> [Diff [String]] -> [DiffOperation LineRange] toLineRange _ _ []=[] @@ -45,6 +44,14 @@ in Change (LineRange (leftLine,leftLine+linesF-1) lsF) (LineRange (rightLine,rightLine+linesS-1) lsS) : toLineRange (leftLine+linesF) (rightLine+linesS) rs +-- | pretty print the differences. The output is similar to the output of the diff utility +ppDiff :: [Diff [String]] -> String +ppDiff gdiff = + let diffLineRanges = diffToLineRanges gdiff + in + render (prettyDiffs diffLineRanges) ++ "\n" + + -- | pretty print of diff operations prettyDiffs :: [DiffOperation LineRange] -> Doc prettyDiffs [] = empty @@ -66,14 +73,59 @@ prettyLines start lins = vcat (map (\l -> char start <+> text l) lins) +-- | Parse pretty printed Diffs as DiffOperations +parsePrettyDiffs :: String -> [DiffOperation LineRange] +parsePrettyDiffs = reverse . doParse [] . lines + where + doParse diffs [] = diffs + doParse diffs s = + let (mnd,r) = parseDiff s + in case mnd of + Just nd -> doParse (nd:diffs) r + _ -> doParse diffs r + parseDiff [] = (Nothing,[]) + parseDiff (h:rs) = let + (r1,hrs1) = parseRange h + in case hrs1 of + ('d':hrs2) -> parseDel r1 hrs2 rs + ('a':hrs2) -> parseAdd r1 hrs2 rs + ('c':hrs2) -> parseChange r1 hrs2 rs + _ -> (Nothing,rs) + parseDel r1 hrs2 rs = let + (r2,_) = parseRange hrs2 + (ls,rs2) = span (isPrefixOf "<") rs + in (Just $ Deletion (LineRange r1 (map (drop 2) ls)) (fst r2), rs2) + parseAdd r1 hrs2 rs = let + (r2,_) = parseRange hrs2 + (ls,rs2) = span (isPrefixOf ">") rs + in (Just $ Addition (LineRange r2 (map (drop 2) ls)) (fst r1), rs2) + parseChange r1 hrs2 rs = let + (r2,_) = parseRange hrs2 + (ls1,rs2) = span (isPrefixOf "<") rs + in case rs2 of + ("---":rs3) -> let + (ls2,rs4) = span (isPrefixOf ">") rs3 + in (Just $ Change (LineRange r1 (map (drop 2) ls1)) (LineRange r2 (map (drop 2) ls2)), rs4) + _ -> (Nothing,rs2) + parseRange :: String -> ((LineNo, LineNo),String) + parseRange l = let + (fstLine,rs) = span isDigit l + (sndLine,rs3) = case rs of + (',':rs2) -> span isDigit rs2 + _ -> (fstLine,rs) + in ((read fstLine,read sndLine),rs3) + +-- | Line number alias type LineNo = Int +-- | Line Range: start, end and contents data LineRange = LineRange { lrNumbers :: (LineNo, LineNo) , lrContents :: [String] } - deriving (Show) + deriving (Show,Read,Eq,Ord) +-- | Diff Operation representing changes to apply data DiffOperation a = Deletion a LineNo | Addition a LineNo | Change a a - deriving (Show) \ No newline at end of file + deriving (Show,Read,Eq,Ord) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Diff-0.3.2/test/Test.hs new/Diff-0.3.4/test/Test.hs --- old/Diff-0.3.2/test/Test.hs 1970-01-01 01:00:00.000000000 +0100 +++ new/Diff-0.3.4/test/Test.hs 2016-04-23 07:21:45.000000000 +0200 @@ -0,0 +1,192 @@ +module Main where + +import Test.Framework (defaultMain, testGroup) +import Test.Framework.Providers.QuickCheck2 (testProperty) +import Test.QuickCheck +import Data.Algorithm.Diff +import Data.Algorithm.DiffOutput +import Text.PrettyPrint + +import System.IO +import System.Exit +import System.IO.Unsafe (unsafePerformIO) +import Debug.Trace (trace) +import System.Environment (getArgs) +import Data.Maybe (mapMaybe, catMaybes) +import System.Process (readProcessWithExitCode) +import System.Directory (getTemporaryDirectory) + + +main :: IO () +main = defaultMain [ testGroup "sub props" [ + slTest "empty in subs" prop_emptyInSubs, + slTest "self in subs" prop_selfInSubs, + slTest "count subs" prop_countSubs, + slTest "every sub is a sub" prop_everySubIsSub, + slTest2 "sub prop" prop_sub + ], + testGroup "diff props" [ + slTest "lcsEmpty" prop_lcsEmpty, + slTest "lcsSelf" prop_lcsSelf, + slTest2 "lcsBoth" prop_lcsBoth, + slTest2 "recover first" prop_recoverFirst, + slTest2 "recover second" prop_recoverSecond, + slTest2 "lcs" prop_lcs + ], + testGroup "output props" [ + testProperty "self generates empty" $ forAll shortLists prop_ppDiffEqual, + --testProperty "compare our lists with diff" $ forAll2 shortLists prop_ppDiffShort, + testProperty "compare random with diff" prop_ppDiffR, + testProperty "test parse" prop_parse + ] + ] + +slTest s t = testProperty s $ forAll shortLists (t :: [Bool] -> Bool) +slTest2 s t = testProperty s $ forAll2 shortLists (t :: [Bool] -> [Bool] -> Bool) + +-- We need some quick and dirty subsequence stuff for the diff tests, +-- so we build that and some tests for it. + +-- | Determines whether one list is a subsequence of another. +isSub :: (Eq a) => [a] -> [a] -> Bool +isSub [] _ = True +isSub (_:_) [] = False +isSub (x:xs) (y:ys) | x == y = isSub xs ys + | otherwise = isSub (x:xs) ys + +-- | Lists the subsequences of a list. +subs :: [a] -> [[a]] +subs [] = [[]] +subs (x:rest) = map (x:) restss ++ restss + where restss = subs rest + +prop_emptyInSubs = elem [] . subs +prop_selfInSubs xs = elem xs (subs xs) +prop_countSubs xs = length (subs xs) == 2^(length xs) +prop_sub xs ys = isSub xs ys == elem xs (subs ys) +prop_everySubIsSub xs = all (flip isSub xs) (subs xs) + + +-- | Obtains a longest common subsequence of two lists using their +-- diff. Note that there is an @lcs@ function in the +-- 'Data.Algorithm.Diff' module, but it's not exported. It's trivial +-- to reconstruct the LCS though, just by taking the 'B' elements. +diffLCS :: (Eq a) => [a] -> [a] -> [a] +diffLCS xs ys = recoverLCS $ getDiff xs ys + +-- | Recovers the (longest) common subsequence from a diff. +recoverLCS :: [Diff a] -> [a] +recoverLCS (Both x _ : xs) = x : recoverLCS xs +recoverLCS (_ : xs) = recoverLCS xs +recoverLCS [] = [] + +-- | Recovers the first list from a diff. +recoverFirst :: [Diff a] -> [a] +recoverFirst (First x : xs) = x : recoverFirst xs +recoverFirst (Both x _ : xs) = x : recoverFirst xs +recoverFirst (_ : xs) = recoverFirst xs +recoverFirst [] = [] + +-- | Recovers the second list from a diff. +recoverSecond :: [Diff a] -> [a] +recoverSecond (Second x : xs) = x : recoverSecond xs +recoverSecond (Both x _ : xs) = x : recoverSecond xs +recoverSecond (_ : xs) = recoverSecond xs +recoverSecond [] = [] + +-- | Indicates whether a list is a longest common subsequence of two +-- lists. +isLCS :: (Eq a) => [a] -> [a] -> [a] -> Bool +isLCS ss xs ys = isSub ss ys && isSub ss ys && length ss == lenLCS xs ys + +-- | Computes the length of the longest common subsequence of two +-- lists. This is a naive and inefficient recursive implementation +-- that doesn't memoize repeated sub-calls, so don't use it with large +-- lists. +lenLCS :: (Eq a) => [a] -> [a] -> Int +lenLCS [] _ = 0 +lenLCS _ [] = 0 +lenLCS (x:xs) (y:ys) | x == y = 1 + lenLCS xs ys + | otherwise = max (lenLCS (x:xs) ys) (lenLCS xs (y:ys)) + + +prop_recoverFirst xs ys = recoverFirst (getDiff xs ys) == xs +prop_recoverSecond xs ys = recoverSecond (getDiff xs ys) == ys +prop_lcs xs ys = isLCS (diffLCS xs ys) xs ys +prop_lcsEmpty xs = diffLCS xs [] == [] && diffLCS [] xs == [] +prop_lcsSelf xs = diffLCS xs xs == xs +prop_lcsBoth xs ys = all areMatch $ getDiff xs ys + where areMatch (Both x y) = x == y + areMatch _ = True + +-- | Lists of no more than twelve elements. +shortLists :: (Arbitrary a) => Gen [a] +shortLists = sized $ \n -> resize (min n 12) $ listOf arbitrary + +-- | 'forAll' where the generator is used twice. +forAll2 :: (Show a, Testable prop) => Gen a -> (a -> a -> prop) -> Property +forAll2 gen f = forAll gen $ \x -> forAll gen (f x) + +prop_ppDiffEqual xs=ppDiff (getGroupedDiff xs xs)=="\n" + +-- | truly random tests +prop_ppDiffR :: DiffInput -> Property +prop_ppDiffR (DiffInput le ri) = + let haskDiff=ppDiff $ getGroupedDiff le ri + utilDiff= unsafePerformIO (runDiff (unlines le) (unlines ri)) + in cover (haskDiff == utilDiff) 90 "exact match" $ + classify (haskDiff == utilDiff) "exact match" + (div ((length haskDiff)*100) (length utilDiff) < 110) -- less than 10% bigger + where + runDiff left right = + do leftFile <- writeTemp left + rightFile <- writeTemp right + (ecode, out, err) <- + readProcessWithExitCode "diff" [leftFile, rightFile] "" + -- putStrLn ("OUT:\n" ++ out) + -- putStrLn ("ERR:\n" ++ err) + -- putStrLn ("ECODE:\n" ++ show ecode) + case ecode of + ExitSuccess -> return out + ExitFailure 1 -> return out + ExitFailure i -> error ("'diff " ++ leftFile ++ " " ++ rightFile ++ + "' failed with exit code " ++ show i ++ + ": " ++ show err) + writeTemp s = + do dir <- getTemporaryDirectory + (fp, h) <- openTempFile dir "HTF-diff.txt" + hPutStr h s + hClose h + return fp + +-- | Check pretty printed DiffOperations can be parsed again +prop_parse :: DiffInput -> Bool +prop_parse (DiffInput le ri) = + let difflrs = diffToLineRanges $ getGroupedDiff le ri + output = render (prettyDiffs difflrs) ++ "\n" + parsed = parsePrettyDiffs output + in difflrs == parsed + +data DiffInput = DiffInput { diLeft :: [String], diRight :: [String] } + deriving (Show) + +leftDiffInput = ["1", "2", "3", "4", "", "5", "6", "7"] + +instance Arbitrary DiffInput where + arbitrary = + do let leftLines = leftDiffInput + rightLinesLines <- mapM modifyLine (leftLines ++ [""]) + return $ DiffInput leftLines + (concat rightLinesLines) + where + randomString = + do c <- elements ['a' .. 'z'] + return [c] + modifyLine :: String -> Gen [String] + modifyLine str = + do prefixLen <- frequency [(20-i, return i) | i <- [0..5]] + prefix <- mapM (const randomString) [1..prefixLen] + frequency [ (5, return (prefix ++ [str])) + , (3, return (prefix ++ ["XXX" ++ str])) + , (2, return prefix) + , (2, return [str])]