blew several hours on getting the decodeGitFile 100% right with quickcheck
This commit is contained in:
parent
82056a7921
commit
9e5985ff98
1 changed files with 64 additions and 12 deletions
76
GitRepo.hs
76
GitRepo.hs
|
@ -36,7 +36,11 @@ module GitRepo (
|
||||||
inRepo,
|
inRepo,
|
||||||
notInRepo,
|
notInRepo,
|
||||||
stagedFiles,
|
stagedFiles,
|
||||||
checkAttr
|
checkAttr,
|
||||||
|
decodeGitFile,
|
||||||
|
encodeGitFile,
|
||||||
|
|
||||||
|
prop_idempotent_encode
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Monad (unless)
|
import Monad (unless)
|
||||||
|
@ -51,6 +55,9 @@ import qualified Data.Map as Map hiding (map, split)
|
||||||
import Network.URI
|
import Network.URI
|
||||||
import Maybe
|
import Maybe
|
||||||
import Char
|
import Char
|
||||||
|
import Text.Printf
|
||||||
|
import Data.Word (Word8)
|
||||||
|
import Codec.Binary.UTF8.String (encode)
|
||||||
|
|
||||||
import Utility
|
import Utility
|
||||||
|
|
||||||
|
@ -332,25 +339,70 @@ checkAttr repo attr files = do
|
||||||
decodeGitFile :: String -> FilePath
|
decodeGitFile :: String -> FilePath
|
||||||
decodeGitFile [] = []
|
decodeGitFile [] = []
|
||||||
decodeGitFile f@(c:s)
|
decodeGitFile f@(c:s)
|
||||||
| c == '"' = unescape middle
|
| c == '"' = unescape ("", middle)
|
||||||
| otherwise = f
|
| otherwise = f
|
||||||
where
|
where
|
||||||
e = "\\"
|
|
||||||
middle = take (length s - 1) s
|
middle = take (length s - 1) s
|
||||||
unescape v = foldl (++) beginning $ map decode $ split e rest
|
unescape (b, []) = b
|
||||||
|
unescape (b, v) = b ++ beginning ++ unescape (decode rest)
|
||||||
where
|
where
|
||||||
pair = span (/= '\\') v
|
pair = span (/= '\\') v
|
||||||
beginning = fst pair
|
beginning = fst pair
|
||||||
rest = snd pair
|
rest = snd pair
|
||||||
decode [] = ""
|
isescape c = c == '\\'
|
||||||
decode n
|
decode (e:n1:n2:n3:rest)
|
||||||
| length num == 3 = (chr $ readoctal num):rest
|
| isescape e && alloctal = (fromoctal, rest)
|
||||||
| otherwise = e++n
|
where
|
||||||
|
alloctal = isOctDigit n1 &&
|
||||||
|
isOctDigit n2 &&
|
||||||
|
isOctDigit n3
|
||||||
|
fromoctal = [chr $ readoctal (n1:n2:n3:[])]
|
||||||
|
readoctal o = read $ "0o" ++ o :: Int
|
||||||
|
decode (e:nc:rest)
|
||||||
|
| isescape e = ([echar nc], rest)
|
||||||
where
|
where
|
||||||
pair = span isOctDigit n
|
-- special character escapes
|
||||||
num = fst pair
|
echar 'a' = '\a'
|
||||||
rest = snd pair
|
echar 'b' = '\b'
|
||||||
readoctal o = read $ "0o" ++ o :: Int
|
echar 'f' = '\f'
|
||||||
|
echar 'n' = '\n'
|
||||||
|
echar 'r' = '\r'
|
||||||
|
echar 't' = '\t'
|
||||||
|
echar 'v' = '\v'
|
||||||
|
echar x = x
|
||||||
|
decode n = ("", n)
|
||||||
|
|
||||||
|
{- Should not need to use this, except for testing decodeGitFile. -}
|
||||||
|
encodeGitFile :: FilePath -> String
|
||||||
|
encodeGitFile s = (foldl (++) "\"" (map echar s)) ++ "\""
|
||||||
|
where
|
||||||
|
e c = "\\" ++ [c]
|
||||||
|
echar '\a' = e 'a'
|
||||||
|
echar '\b' = e 'b'
|
||||||
|
echar '\f' = e 'f'
|
||||||
|
echar '\n' = e 'n'
|
||||||
|
echar '\r' = e 'r'
|
||||||
|
echar '\t' = e 't'
|
||||||
|
echar '\v' = e 'v'
|
||||||
|
echar '\\' = e '\\'
|
||||||
|
echar '"' = e '"'
|
||||||
|
echar x
|
||||||
|
| ord x < 0x20 = e_num x -- low ascii
|
||||||
|
| ord x >= 256 = e_utf x
|
||||||
|
| ord x > 0x7E = e_num x -- high ascii
|
||||||
|
| otherwise = [x] -- printable ascii
|
||||||
|
where
|
||||||
|
showoctal i = "\\" ++ (printf "%03o" i)
|
||||||
|
e_num c = showoctal $ ord c
|
||||||
|
-- unicode character is decomposed to Word8
|
||||||
|
-- and each is shown with e_num
|
||||||
|
e_utf c = foldl (++) "" $ map showoctal $
|
||||||
|
(encode [c] :: [Word8])
|
||||||
|
|
||||||
|
|
||||||
|
{- for quickcheck -}
|
||||||
|
prop_idempotent_encode :: String -> Bool
|
||||||
|
prop_idempotent_encode s = s == (decodeGitFile $ encodeGitFile s)
|
||||||
|
|
||||||
{- Finds the current git repository, which may be in a parent directory. -}
|
{- Finds the current git repository, which may be in a parent directory. -}
|
||||||
repoFromCwd :: IO Repo
|
repoFromCwd :: IO Repo
|
||||||
|
|
Loading…
Reference in a new issue