[commit: packages/binary] master: Add test to check error position and remaining input. (6076e2f)

git at git.haskell.org git at git.haskell.org
Sun Dec 14 17:54:29 UTC 2014


Repository : ssh://git@git.haskell.org/binary

On branch  : master
Link       : http://git.haskell.org/packages/binary.git/commitdiff/6076e2f5882fe742111ccae0ad080e5b8b713f0e

>---------------------------------------------------------------

commit 6076e2f5882fe742111ccae0ad080e5b8b713f0e
Author: Lennart Kolmodin <kolmodin at gmail.com>
Date:   Sun Mar 23 20:54:08 2014 +0400

    Add test to check error position and remaining input.


>---------------------------------------------------------------

6076e2f5882fe742111ccae0ad080e5b8b713f0e
 tests/Action.hs | 101 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 76 insertions(+), 25 deletions(-)

diff --git a/tests/Action.hs b/tests/Action.hs
index f32d748..d26c776 100644
--- a/tests/Action.hs
+++ b/tests/Action.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BangPatterns, PatternGuards #-}
 module Action where
 
 import           Control.Applicative
@@ -16,7 +16,8 @@ import qualified Data.Binary.Get                      as Binary
 
 tests :: [Test]
 tests = [ testProperty "action" prop_action
-        , testProperty "label" prop_label ]
+        , testProperty "label" prop_label
+        , testProperty "fail" prop_fail ]
 
 data Action
   = Actions [Action]
@@ -125,6 +126,8 @@ prop_action =
         case Binary.runGet (eval allInput actions) lbs of
           () -> True
 
+-- | When a decoder aborts with 'fail', check that all relevant uses of 'label'
+-- are respected.
 prop_label :: Property
 prop_label =
   forAllShrink (gen_actions True) shrink $ \ actions ->
@@ -132,36 +135,84 @@ prop_label =
       L.length lbs >= fromIntegral (max_len actions) ==>
         let allInput = B.concat (L.toChunks lbs) in
         case Binary.runGetOrFail (eval allInput actions) lbs of
-          Left (inp, off, msg) ->
-            let labels = case collectLabels actions of
-                           Just labels -> labels
+          Left (_inp, _off, msg) ->
+            let lbls = case collectLabels actions of
+                           Just lbls' -> lbls'
                            Nothing -> error "expected labels"
-                expectedMsg | null labels = "fail"
-                            | otherwise = concat $ intersperse "\n" ("fail":labels)
+                expectedMsg | null lbls = "fail"
+                            | otherwise = concat $ intersperse "\n" ("fail":lbls)
             in if (msg == expectedMsg)
-                 then label ("labels: " ++ show (length labels)) True
+                 then label ("labels: " ++ show (length lbls)) True
                  else error (show msg ++ " vs. " ++ show expectedMsg)
-          Right (inp, off, value) -> label "test case without 'fail'" True
+          Right (_inp, _off, _value) -> label "test case without 'fail'" True
 
+-- | When a decoder aborts with 'fail', check the fail position and
+-- remaining input.
+prop_fail :: Property
+prop_fail =
+  forAllShrink (gen_actions True) shrink $ \ actions ->
+    forAll arbitrary $ \ lbs ->
+      L.length lbs >= fromIntegral (max_len actions) ==>
+        let allInput = B.concat (L.toChunks lbs) in
+        case Binary.runGetOrFail (eval allInput actions) lbs of
+          Left (inp, off, _msg) ->
+            case () of
+              _ | Just off /= findFailPosition actions ->
+                    error ("fail position incorrect, expected " ++
+                           show (findFailPosition actions) ++
+                           " but got " ++ show off)
+                | inp /= L.drop (fromIntegral off) lbs ->
+                    error "remaining output incorrect"
+                | otherwise -> property True
+          Right (_inp, _off, _value) -> label "test case without 'fail'" True
+
+-- | Collect all the labels up to a 'fail', or Nothing if the
+-- decoder will not fail.
 collectLabels :: [Action] -> Maybe [String]
 collectLabels = go []
   where
-    go labels [] = Nothing
-    go labels (Fail:xs) = Just labels
-    go labels (Label str a:xs) =
-      case go (str:labels) a of
-        Just labels' -> Just labels'
-        Nothing -> go labels xs
-    go labels (Try a b:xs) =
-      case (go labels a, go labels b) of
-        (Just _, Just labels') -> Just labels'
-        (Just _, Nothing) -> go labels xs
-        (Nothing, _) -> go labels xs
-    go labels (Actions a:xs) = go labels (a++xs)
-    go labels (LookAhead a:xs) = go labels (a++xs)
-    go labels (LookAheadM _ a:xs) = go labels (a++xs)
-    go labels (LookAheadE _ a:xs) = go labels (a++xs)
-    go labels (_:xs) = go labels xs
+    go _ [] = Nothing
+    go lbls (Fail:_) = Just lbls
+    go lbls (Label str a:xs) =
+      case go (str:lbls) a of
+        Just lbls' -> Just lbls'
+        Nothing -> go lbls xs
+    go lbls (Try a b:xs) =
+      case (go lbls a, go lbls b) of
+        (Just _, Just lbls') -> Just lbls'
+        (Just _, Nothing) -> go lbls xs
+        (Nothing, _) -> go lbls xs
+    go lbls (Actions a:xs) = go lbls (a++xs)
+    go lbls (LookAhead a:xs) = go lbls (a++xs)
+    go lbls (LookAheadM _ a:xs) = go lbls (a++xs)
+    go lbls (LookAheadE _ a:xs) = go lbls (a++xs)
+    go lbls (_:xs) = go lbls xs
+
+-- | Finds at which byte offset the decoder will fail,
+-- or Nothing if it won't fail.
+findFailPosition :: [Action] -> Maybe Binary.ByteOffset
+findFailPosition = either (const Nothing) Just . go (0::Binary.ByteOffset)
+  where
+    go pos [] = Left pos
+    go pos (x:xs) =
+      case x of
+        Actions a -> go pos (a++xs)
+        GetByteString n -> go (pos + fromIntegral n) xs
+        BytesRead -> go pos xs
+        Fail -> Right pos
+        Label _ a -> go pos (a++xs)
+        LookAhead a -> either (const (go pos xs)) Right (go pos a)
+        LookAheadM consume a ->
+          let pos' False = go pos (LookAhead a : xs)
+              pos' True = go pos (a++xs)
+          in pos' consume
+        LookAheadE consume a ->
+          let pos' False = go pos (LookAhead a : xs)
+              pos' True = go pos (a++xs)
+          in pos' consume
+        Try a b
+          | Left pos' <- go pos a -> go pos' xs
+          | otherwise -> go pos (b++xs)
 
 -- | Evaluate (run) the model.
 -- First argument is all the input that will be used when executing



More information about the ghc-commits mailing list