quickcheck property for parsing of content identifier logs

This commit is contained in:
Joey Hess 2019-02-21 12:22:50 -04:00
parent 7c25cc7715
commit 936aee6a60
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
7 changed files with 40 additions and 16 deletions

View file

@ -6,6 +6,7 @@
-} -}
module Logs.ContentIdentifier ( module Logs.ContentIdentifier (
module X,
recordContentIdentifier, recordContentIdentifier,
getContentIdentifiers, getContentIdentifiers,
) where ) where
@ -15,7 +16,7 @@ import Logs
import Logs.MapLog import Logs.MapLog
import Types.Remote (ContentIdentifier) import Types.Remote (ContentIdentifier)
import qualified Annex.Branch import qualified Annex.Branch
import Logs.ContentIdentifier.Pure import Logs.ContentIdentifier.Pure as X
import qualified Annex import qualified Annex
import qualified Data.Map as M import qualified Data.Map as M

View file

@ -7,11 +7,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Logs.ContentIdentifier.Pure module Logs.ContentIdentifier.Pure where
( ContentIdentifierLog
, parseLog
, buildLog
) where
import Annex.Common import Annex.Common
import Logs.MapLog import Logs.MapLog
@ -28,11 +24,14 @@ import Data.ByteString.Builder
type ContentIdentifierLog = MapLog UUID [ContentIdentifier] type ContentIdentifierLog = MapLog UUID [ContentIdentifier]
buildLog :: ContentIdentifierLog -> Builder buildLog :: ContentIdentifierLog -> Builder
buildLog = buildMapLog buildUUID valuebuilder buildLog = buildMapLog buildUUID buildContentIdentifierList
buildContentIdentifierList :: [ContentIdentifier] -> Builder
buildContentIdentifierList l = case l of
[] -> mempty
[c] -> buildcid c
(c:cs) -> buildcid c <> charUtf8 ' ' <> buildContentIdentifierList cs
where where
valuebuilder [] = mempty
valuebuilder [c] = buildcid c
valuebuilder (c:cs) = buildcid c <> charUtf8 ' ' <> valuebuilder cs
buildcid (ContentIdentifier c) buildcid (ContentIdentifier c)
| S8.any (`elem` [' ', '\r', '\n']) c || "!" `S8.isPrefixOf` c = | S8.any (`elem` [' ', '\r', '\n']) c || "!" `S8.isPrefixOf` c =
charUtf8 '!' <> byteString (toB64' c) charUtf8 '!' <> byteString (toB64' c)
@ -41,7 +40,10 @@ buildLog = buildMapLog buildUUID valuebuilder
parseLog :: L.ByteString -> ContentIdentifierLog parseLog :: L.ByteString -> ContentIdentifierLog
parseLog = parseMapLog parseLog = parseMapLog
(toUUID <$> A.takeByteString) (toUUID <$> A.takeByteString)
(reverse . catMaybes <$> valueparser []) parseContentIdentifierList
parseContentIdentifierList :: A.Parser [ContentIdentifier]
parseContentIdentifierList = reverse . catMaybes <$> valueparser []
where where
valueparser l = do valueparser l = do
b <- A8.takeWhile1 (/= ' ') b <- A8.takeWhile1 (/= ' ')
@ -54,3 +56,7 @@ parseLog = parseMapLog
_ <- A8.char ' ' _ <- A8.char ' '
valueparser (cid:l) valueparser (cid:l)
) )
prop_parse_build_contentidentifier_log :: ContentIdentifierLog -> Bool
prop_parse_build_contentidentifier_log l =
parseLog (toLazyByteString (buildLog l)) == l

View file

@ -20,6 +20,7 @@ module Logs.MapLog (
import Common import Common
import Annex.VectorClock import Annex.VectorClock
import Logs.Line import Logs.Line
import Utility.QuickCheck
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
@ -32,6 +33,9 @@ data LogEntry v = LogEntry
, value :: v , value :: v
} deriving (Eq, Show) } deriving (Eq, Show)
instance Arbitrary v => Arbitrary (LogEntry v) where
arbitrary = LogEntry <$> arbitrary <*> arbitrary
type MapLog f v = M.Map f (LogEntry v) type MapLog f v = M.Map f (LogEntry v)
buildMapLog :: (f -> Builder) -> (v -> Builder) -> MapLog f v -> Builder buildMapLog :: (f -> Builder) -> (v -> Builder) -> MapLog f v -> Builder

View file

@ -122,6 +122,5 @@ instance Arbitrary LogLine where
arbinfo = (encodeBS <$> arbitrary) `suchThat` arbinfo = (encodeBS <$> arbitrary) `suchThat`
(\b -> C8.notElem '\n' b && C8.notElem '\r' b) (\b -> C8.notElem '\n' b && C8.notElem '\r' b)
prop_parse_build_log :: [LogLine] -> Bool prop_parse_build_presence_log :: [LogLine] -> Bool
prop_parse_build_log l = parseLog (toLazyByteString (buildLog l)) == l prop_parse_build_presence_log l = parseLog (toLazyByteString (buildLog l)) == l

View file

@ -48,6 +48,7 @@ import qualified Logs.Remote
import qualified Logs.Unused import qualified Logs.Unused
import qualified Logs.Transfer import qualified Logs.Transfer
import qualified Logs.Presence import qualified Logs.Presence
import qualified Logs.ContentIdentifier
import qualified Logs.PreferredContent import qualified Logs.PreferredContent
import qualified Types.MetaData import qualified Types.MetaData
import qualified Remote import qualified Remote
@ -175,7 +176,8 @@ properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck"
, testProperty "prop_segment_regressionTest" Utility.Misc.prop_segment_regressionTest , testProperty "prop_segment_regressionTest" Utility.Misc.prop_segment_regressionTest
, testProperty "prop_read_write_transferinfo" Logs.Transfer.prop_read_write_transferinfo , testProperty "prop_read_write_transferinfo" Logs.Transfer.prop_read_write_transferinfo
, testProperty "prop_read_show_inodecache" Utility.InodeCache.prop_read_show_inodecache , testProperty "prop_read_show_inodecache" Utility.InodeCache.prop_read_show_inodecache
, testProperty "prop_parse_build_log" Logs.Presence.prop_parse_build_log , testProperty "prop_parse_build_presence_log" Logs.Presence.prop_parse_build_presence_log
, testProperty "prop_parse_build_contentidentifier_log" Logs.ContentIdentifier.prop_parse_build_contentidentifier_log
, testProperty "prop_read_show_TrustLevel" Types.TrustLevel.prop_read_show_TrustLevel , testProperty "prop_read_show_TrustLevel" Types.TrustLevel.prop_read_show_TrustLevel
, testProperty "prop_parse_build_TrustLevelLog" Logs.Trust.prop_parse_build_TrustLevelLog , testProperty "prop_parse_build_TrustLevelLog" Logs.Trust.prop_parse_build_TrustLevelLog
, testProperty "prop_hashes_stable" Utility.Hash.prop_hashes_stable , testProperty "prop_hashes_stable" Utility.Hash.prop_hashes_stable

View file

@ -45,6 +45,7 @@ import Utility.Metered
import Git.Types (RemoteName) import Git.Types (RemoteName)
import Utility.SafeCommand import Utility.SafeCommand
import Utility.Url import Utility.Url
import Utility.QuickCheck
type RemoteConfigKey = String type RemoteConfigKey = String
@ -246,7 +247,7 @@ data ExportActions a = ExportActions
{- An identifier for content stored on a remote. It should be reasonably {- An identifier for content stored on a remote. It should be reasonably
- short since it is stored in the git-annex branch. -} - short since it is stored in the git-annex branch. -}
newtype ContentIdentifier = ContentIdentifier S.ByteString newtype ContentIdentifier = ContentIdentifier S.ByteString
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show, Arbitrary)
{- Some remotes may support importing a history of versions of content that {- Some remotes may support importing a history of versions of content that
- is stored in them. This is equivilant to a git commit history. -} - is stored in them. This is equivilant to a git commit history. -}
@ -256,6 +257,7 @@ data ContentHistory t
{ contentHistoryCurrent :: t { contentHistoryCurrent :: t
, contentHistoryPrev :: [ContentHistory t] , contentHistoryPrev :: [ContentHistory t]
} }
deriving (Show)
data ImportActions a = ImportActions data ImportActions a = ImportActions
-- Finds the current set of files that are stored in the remote, -- Finds the current set of files that are stored in the remote,

View file

@ -14,10 +14,12 @@ import qualified Data.Map as M
import qualified Data.UUID as U import qualified Data.UUID as U
import Data.Maybe import Data.Maybe
import Data.String import Data.String
import Data.Char
import Data.ByteString.Builder import Data.ByteString.Builder
import qualified Data.Semigroup as Sem import qualified Data.Semigroup as Sem
import Utility.FileSystemEncoding import Utility.FileSystemEncoding
import Utility.QuickCheck
import qualified Utility.SimpleProtocol as Proto import qualified Utility.SimpleProtocol as Proto
-- A UUID is either an arbitrary opaque string, or UUID info may be missing. -- A UUID is either an arbitrary opaque string, or UUID info may be missing.
@ -81,3 +83,11 @@ type UUIDDescMap = M.Map UUID UUIDDesc
instance Proto.Serializable UUID where instance Proto.Serializable UUID where
serialize = fromUUID serialize = fromUUID
deserialize = Just . toUUID deserialize = Just . toUUID
instance Arbitrary UUID where
arbitrary = frequency [(1, return NoUUID), (3, UUID <$> arb)]
where
-- Avoid non-ascii because fully arbitrary
-- strings may not be encoded using the filesystem
-- encoding, which is normally applied to all input.
arb = encodeBS <$> arbitrary `suchThat` all isAscii