packages feed

hashed-storage-0.3.4: Storage/Hashed/Test.hs

module Storage.Hashed.Test( tests ) where

import Prelude hiding ( read )
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.ByteString.Char8 as BS
import System.Process
import System.Directory( doesFileExist, removeFile )
import Control.Monad( forM_, when )
import Data.Maybe
import Data.Word
import Data.Bits
import Data.List( (\\), sort )
import Storage.Hashed
import Storage.Hashed.AnchoredPath
import Storage.Hashed.Tree
import Storage.Hashed.Index
import Storage.Hashed.Utils
import Storage.Hashed.Darcs

import Test.HUnit
import Test.Framework( testGroup )
import Test.QuickCheck

import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck

------------------------
-- Test Data
--

files = [ floatPath "hashed-storage.cabal"
        , floatPath "Storage/Hashed.hs"
        , floatPath "Storage/Hashed/Index.hs" ]

emptyStub = Stub (return emptyTree) Nothing

testTree =
    makeTree [ (makeName "foo", emptyStub)
             , (makeName "subtree", SubTree sub)
             , (makeName "substub", Stub getsub Nothing) ]
    where sub = makeTree [ (makeName "stub", emptyStub)
                         , (makeName "substub", Stub getsub2 Nothing)
                         , (makeName "x", SubTree emptyTree) ]
          getsub = return sub
          getsub2 = return $ makeTree [ (makeName "file", File emptyBlob) ]

---------------------------
-- Test list
--

tests = [ testGroup "darcs" darcs
        , testGroup "Storage.Hashed.Index" index
        , testGroup "Storage.Hashed.Tree" tree
        , testGroup "Storage.Hashed.Utils" utils ]

--------------------------
-- Tests
--

darcs = [ testCase "specific files" have_files
        , testCase "pristine files" have_pristine_files
        , testCase "list == darcs show manifest" darcs_manifest
        , testCase "content == darcs show contents" darcs_contents ]
    where
      check_file t f = assertBool
                       ("path " ++ show f ++ " is in tree")
                       (isJust $ find t f)
      check_files = forM_ files . check_file
      have_files = readPlainTree "." >>= expand >>= check_files
      have_pristine_files =
         readDarcsPristine "." >>= expand >>= check_files

      -- NB. When hashed-storage replace slurpies in darcs, the following 2
      -- tests become useless, since they just check our code against darcs.
      darcs_manifest = do
        f <- lines `fmap` readProcess "darcs" ["show", "files" ] ""
        t <- readDarcsPristine "." >>= expand
        forM_ (f \\ ["."]) (\x -> check_file t (floatPath x))
        forM_ (list t)
              (\x -> assertBool (show (fst x) ++ " is in darcs show files") $
                     anchorPath "." (fst x) `elem` f)
      darcs_contents = do
        t <- readDarcsPristine "." >>= expand
        sequence_ [
          do our <- read b
             darcs <- readProcess "darcs" [ "show", "contents",
                                            anchorPath "." p ] ""
             assertEqual "contents match" (BL.unpack our) darcs
         | (p, File b) <- list t ]

index = [ testCase "index listing" check_index
        , testCase "index content" check_index_content
        , testCase "index versioning" check_index_versions ]
    where pristine = readDarcsPristine "." >>= expand
          build_index =
            do x <- pristine
               exist <- doesFileExist "_darcs/index"
               when exist $ removeFile "_darcs/index"
               idx <- updateIndexFrom "_darcs/index" darcsTreeHash x >>= expand
               return (x, idx)
          check_index =
            do (pris, idx) <- build_index
               (sort $ map fst $ list idx) @?= (sort $ map fst $ list pris)
          check_blob_pair p x y =
              do a <- read x
                 b <- read y
                 assertEqual ("content match on " ++ show p) a b
          check_index_content =
            do (_, idx) <- build_index
               plain <- readPlainTree "."
               x <- sequence $ zipCommonFiles check_blob_pair plain idx
               assertBool "files match" (length x > 0)
          check_index_versions =
            do writeFile "_darcs/index" "nonsense index... do not crash!"
               pris <- pristine
               idx <- expand =<<
                        readOrUpgradeIndex "_darcs/index" darcsTreeHash pristine
               (sort $ map fst $ list idx) @?= (sort $ map fst $ list pris)

tree = [ testCase "modifyTree" check_modify
       , testCase "complex modifyTree" check_modify_complex
       , testCase "expand" check_expand
       , testCase "expandPath" check_expand_path ]
    where blob x = File $ Blob (return (BL.pack x)) (Just $ sha256 $ BL.pack x)
          name = Name . BS.pack
          check_modify =
              let t = makeTree [(name "foo", blob "bar")]
                  modify = modifyTree t (floatPath "foo") (Just $ blob "bla")
               in do x <- read $ fromJust $ findFile t (floatPath "foo")
                     y <- read $ fromJust $ findFile modify (floatPath "foo")
                     assertEqual "old version" x (BL.pack "bar")
                     assertEqual "new version" y (BL.pack "bla")
          check_modify_complex =
              let t = makeTree [ (name "foo", blob "bar")
                               , (name "bar", SubTree t1) ]
                  t1 = makeTree [ (name "foo", blob "bar") ]
                  modify = modifyTree t (floatPath "bar/foo") (Just $ blob "bla")
               in do foo <- read $ fromJust $ findFile t (floatPath "foo")
                     foo' <- read $ fromJust $ findFile modify (floatPath "foo")
                     bar_foo <- read $ fromJust $
                                findFile t (floatPath "bar/foo")
                     bar_foo' <- read $ fromJust $
                                 findFile modify (floatPath "bar/foo")
                     assertEqual "old foo" foo (BL.pack "bar")
                     assertEqual "old bar/foo" bar_foo (BL.pack "bar")
                     assertEqual "new foo" foo' (BL.pack "bar")
                     assertEqual "new bar/foo" bar_foo' (BL.pack "bla")
          no_stubs t = null [ () | (_, Stub _ _) <- list t ]
          path = floatPath "substub/substub/file"
          badpath = floatPath "substub/substub/foo"
          check_expand = do
            x <- expand testTree
            assertBool "no stubs in testTree" $ not (no_stubs testTree)
            assertBool "stubs in expanded tree" $ no_stubs x
            assertBool "path reachable" $ path `elem` (map fst $ list x)
            assertBool "badpath not reachable" $
                       badpath `notElem` (map fst $ list x)
          check_expand_path = do
            t <- expandPath testTree path
            assertBool "path reachable" $ path `elem` (map fst $ list t)
            assertBool "badpath not reachable" $
                       badpath `notElem` (map fst $ list t)

utils = [ testProperty "xlate32" prop_xlate32
        , testProperty "xlate64" prop_xlate64 ]
    where prop_xlate32 x = (xlate32 . xlate32) x == x where types = x :: Word32
          prop_xlate64 x = (xlate64 . xlate64) x == x where types = x :: Word64

instance Arbitrary Word32 where
    arbitrary = do x <- arbitrary :: Gen Int
                   return $ fromIntegral x

instance Arbitrary Word64 where
    arbitrary = do x <- arbitrary :: Gen Int
                   y <- arbitrary :: Gen Int
                   let x' = fromIntegral x
                       y' = fromIntegral y
                   return $ x' .|. (y' `shift` 32)