packages feed

chuchu 0.1.2 → 0.1.3

raw patch · 7 files changed

+224/−43 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Test.Chuchu: instance Show ExecutionPlan
- Test.Chuchu: chuchuMain :: MonadIO m => Chuchu m -> (m () -> IO ()) -> IO ()
+ Test.Chuchu: chuchuMain :: (MonadIO m, Applicative m) => Chuchu m -> (m () -> IO ()) -> IO ()

Files

Test/Chuchu.hs view
@@ -83,6 +83,7 @@ import System.Environment import System.Exit import System.IO+import qualified Data.IORef as I  -- text import qualified Data.Text as T@@ -109,67 +110,116 @@ import Test.Chuchu.Types import Test.Chuchu.Parser ++----------------------------------------------------------------------++ -- | The main function for the test file.  It expects the @.feature@ file as the -- first parameter on the command line.  If you want to use it inside a library, -- consider using 'withArgs'.-chuchuMain :: MonadIO m => Chuchu m -> (m () -> IO ()) -> IO ()+chuchuMain :: (MonadIO m, Applicative m) => Chuchu m -> (m () -> IO ()) -> IO () chuchuMain cc runMIO   = do     path <- getPath     parsed <- parseFile path     case parsed of-      (Right abacate)-        -> runMIO-          $ runReaderT-            (do-              code <- processAbacate abacate-              unless code $ liftIO exitFailure)-          $ runChuchu cc-      (Left e) -> error $ "Could not parse " ++ path ++ ": " ++ show e+      Right abacate -> do+        ret <- processAbacate cc runMIO abacate+        unless ret exitFailure+      Left e -> error $ "Could not parse " ++ path ++ ": " ++ show e -type CM m a = ReaderT (Parser (m ())) m a +---------------------------------------------------------------------- -processAbacate :: MonadIO m => Abacate -> CM m Bool-processAbacate feature-  = do-    -- Print feature description.-    putDoc $ describeAbacate feature -    -- Execute features.-    bCode-      <- case fBackground feature of-        Nothing -> return True-        Just background -> processBasicScenario BackgroundKind background-    feCode <- processFeatureElements $ fFeatureElements feature-    return $ bCode && feCode+-- | An execution plan for a scenario.  Currently just a simple+-- record with a background (optional) and a scenario.+data ExecutionPlan =+  ExecutionPlan+    { epBackground :: Maybe Background+    , epScenario   :: FeatureElement+    }+  deriving (Show) ++-- | Creates an execution plan for a feature.+createExecutionPlans :: Abacate -> [ExecutionPlan]+createExecutionPlans feature =+  ExecutionPlan (fBackground feature) `map` fFeatureElements feature+++----------------------------------------------------------------------+++-- | Monad used when executing a feature's scenario.  'ReaderT'+-- is used to carry along the step parser.+type Execution m a = ReaderT (Parser (m ())) m a++ -- | Print a 'D.Doc' describing what we're currently processing.-putDoc :: MonadIO m => D.Doc -> CM m ()+putDoc :: (MonadIO m, Applicative m) => D.Doc -> m () putDoc = liftIO . D.putDoc . (D.<> D.linebreak) ++-- | Same as 'D.text' but using 'T.Text'.+t2d :: T.Text -> D.Doc+t2d = D.text . T.unpack+++-- | Run the 'Execution' monad.+runExecution :: (MonadIO m, Applicative m) =>+                Chuchu m -> (m () -> IO ()) -> Execution m () -> IO ()+runExecution cc runMIO act = runMIO $ runReaderT act $ runChuchu cc+++----------------------------------------------------------------------+++-- | Process a whole Abacate file, that is, a whole feature.+-- Runs each background+scenario combination on a different+-- instance of the 'Execution' monad.+processAbacate :: (MonadIO m, Applicative m) =>+                  Chuchu m+               -> (m () -> IO ())+               -> Abacate+               -> IO Bool+processAbacate cc runMIO feature = do+  -- Print feature description.+  putDoc $ describeAbacate feature++  -- Execute features.+  let plans = createExecutionPlans feature+  retVar <- liftIO $ I.newIORef True+  let checkRet ret = unless ret $ liftIO $ I.writeIORef retVar False+  mapM_ (runExecution cc runMIO . (>>= checkRet) . processExecutionPlan) plans+  liftIO $ I.readIORef retVar+++-- | Process a single execution plan, a combination of+-- background+scenario, inside the 'Execution' monad.+processExecutionPlan :: (MonadIO m, Applicative m) => ExecutionPlan -> Execution m Bool+processExecutionPlan (ExecutionPlan mbackground scenario) = do+  putDoc D.empty -- empty line+  (&&) <$> maybe (return True) (processBasicScenario BackgroundKind) mbackground+       <*> processFeatureElement scenario++ -- | Creates a pretty description of the feature. describeAbacate :: Abacate -> D.Doc describeAbacate feature =-  (if null (fTags feature) then id else (describeTags (fTags feature) D.<$>)) $-  D.white (t2d (fHeader feature))+  D.vsep $+  describeTags (fTags feature) ++ [D.white $ t2d $ fHeader feature] + -- | Creates a vertical list of tags.-describeTags :: Tags -> D.Doc-describeTags = D.vsep . map (D.dullcyan . ("@" D.<>) . t2d)+describeTags :: Tags -> [D.Doc]+describeTags = map (D.dullcyan . ("@" D.<>) . t2d) --- | Same as 'D.text' but using 'T.Text'.-t2d :: T.Text -> D.Doc-t2d = D.text . T.unpack +---------------------------------------------------------------------- -processFeatureElements :: MonadIO m => FeatureElements -> CM m Bool-processFeatureElements featureElements-  = do-    codes <- mapM processFeatureElement featureElements-    return $ and codes -processFeatureElement :: MonadIO m => FeatureElement -> CM m Bool+processFeatureElement :: (MonadIO m, Applicative m) => FeatureElement -> Execution m Bool processFeatureElement (FESO _)   = liftIO (hPutStrLn stderr "Scenario Outlines are not supported yet.")     >> return False@@ -179,11 +229,13 @@  data BasicScenarioKind = BackgroundKind | ScenarioKind Tags -processBasicScenario :: MonadIO m => BasicScenarioKind -> BasicScenario -> CM m Bool++processBasicScenario :: (MonadIO m, Applicative m) => BasicScenarioKind -> BasicScenario -> Execution m Bool processBasicScenario kind scenario = do   putDoc $ describeBasicScenario kind scenario   processSteps (bsSteps scenario) + -- | Creates a pretty description of the basic scenario's header. describeBasicScenario :: BasicScenarioKind -> BasicScenario -> D.Doc describeBasicScenario kind scenario =@@ -194,17 +246,20 @@           describeBasicScenarioKind (ScenarioKind _) = "Scenario:"            prettyTags BackgroundKind      = id-          prettyTags (ScenarioKind tags) = (describeTags tags D.<$>)+          prettyTags (ScenarioKind tags) = D.vsep . (describeTags tags ++) . (:[])  +---------------------------------------------------------------------- -processSteps :: MonadIO m => Steps -> CM m Bool++processSteps :: (MonadIO m, Applicative m) => Steps -> Execution m Bool processSteps steps   = do     codes <- mapM processStep steps     return $ and codes -processStep :: MonadIO m => Step -> CM m Bool++processStep :: (MonadIO m, Applicative m) => Step -> Execution m Bool processStep step   = do     cc <- ask@@ -225,8 +280,10 @@         lift m         return True + data StepResult = SuccessfulStep | UnknownStep + -- | Pretty-prints a step that has already finished executing. describeStep :: StepResult -> Step -> D.Doc describeStep result step =@@ -237,9 +294,13 @@       color UnknownStep    = D.yellow  +----------------------------------------------------------------------++ data Options   = Options {file_ :: FilePath}     deriving (Eq, Show, Typeable, Data)+  getPath :: IO FilePath getPath
Test/Chuchu/Types.hs view
@@ -30,7 +30,7 @@   fromString s = ChuchuParser (string s >> return ())  --- | The most command use case where the return value of the Monad is ignored.+-- | The most common use case where the return value of the Monad is ignored. type Chuchu m  = ChuchuM m ()  -- | The Monad on which the step rules are constructed.  'Given', 'When',
chuchu.cabal view
@@ -1,5 +1,5 @@ name: chuchu-version: 0.1.2+version: 0.1.3 cabal-version: >= 1.8 build-type: Simple license: OtherLicense@@ -20,7 +20,9 @@ extra-source-files:   tests/data/environment.feature,   tests/data/calculator.feature,-  tests/data/prefix.feature+  tests/data/prefix.feature,+  tests/data/multiple_scenarios.feature,+  tests/data/background_and_multiple_scenarios.feature  source-repository head   type:     git@@ -72,6 +74,30 @@ Test-Suite prefix   type: exitcode-stdio-1.0   main-is: prefix.hs+  hs-source-dirs: tests+  build-depends:+    base >= 4 && < 5,+    transformers >= 0.3 && < 0.4,+    chuchu,+    HUnit >= 1.2 && < 1.3+  extensions: OverloadedStrings+  ghc-options: -Wall++Test-Suite multiple_scenarios+  type: exitcode-stdio-1.0+  main-is: multiple_scenarios.hs+  hs-source-dirs: tests+  build-depends:+    base >= 4 && < 5,+    transformers >= 0.3 && < 0.4,+    chuchu,+    HUnit >= 1.2 && < 1.3+  extensions: OverloadedStrings+  ghc-options: -Wall++Test-Suite background_and_multiple_scenarios+  type: exitcode-stdio-1.0+  main-is: background_and_multiple_scenarios.hs   hs-source-dirs: tests   build-depends:     base >= 4 && < 5,
+ tests/background_and_multiple_scenarios.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Control.Applicative+import Control.Monad.Trans.State+import System.Environment+import Test.Chuchu+++type Bathroom = StateT Door IO+++data Door = Open | Locked+++defs :: Chuchu Bathroom+defs = do++  Given "that the bathroom's door is open" $ \_ ->+         put Open++  Given ("that " *> text <* " has entered the bathroom and locked the door") $ \_ -> do+    door <- get+    case door of+      Open -> put Locked+      Locked -> fail "Door was already locked."+++main :: IO ()+main =  withArgs ["tests/data/background_and_multiple_scenarios.feature"] $+        chuchuMain defs (`evalStateT` Locked)
+ tests/data/background_and_multiple_scenarios.feature view
@@ -0,0 +1,21 @@+Feature: A Background and Multiple scenarios++  This feature has a background that must be executed before the+  execution of each scenario. Both scenarios succeed when executed in+  different features and must succeed when executed in the same+  feature.++  However, due to a bug in chuchu (<= 0.1.2), the test fails if both+  scenarios are in the same feature because chuchu only executes the+  background on the beginning of the test and not before each+  scenario.+++  Background: Bathroom's door is open+    Given that the bathroom's door is open++  Scenario: Anybody can use the bathroom+    Given that "Bob" has entered the bathroom and locked the door++  Scenario: Anybody can use the bathroom+    Given that "Alice" has entered the bathroom and locked the door
+ tests/data/multiple_scenarios.feature view
@@ -0,0 +1,13 @@+Feature: Multiple scenarios++  This feature consists of two scenarios that must succeed regardless+  of being in the same feature.++  However, due to a bug in chuchu (<= 0.1.2), the scenarios succeed+  if executed individually but fail if executed together.++  Scenario: Anybody can use the bathroom+    Given that "Bob" has entered the bathroom and locked the door++  Scenario: Anybody can use the bathroom+    Given that "Alice" has entered the bathroom and locked the door
+ tests/multiple_scenarios.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Control.Applicative+import Control.Monad.Trans.State+import System.Environment+import Test.Chuchu+++type Bathroom = StateT Door IO+++data Door = Open | Locked+++defs :: Chuchu Bathroom+defs = do++  Given ("that " *> text <* " has entered the bathroom and locked the door") $ \_ -> do+    door <- get+    case door of+      Open -> put Locked+      Locked -> fail "Door was already locked."++main :: IO ()+main = withArgs ["tests/data/multiple_scenarios.feature"] $+       chuchuMain defs (`evalStateT` Open)