packages feed

chuchu (empty) → 0.0.0.0

raw patch · 14 files changed

+1054/−0 lines, 14 filesdep +HUnitdep +abacatedep +basesetup-changed

Dependencies added: HUnit, abacate, base, chuchu, cmdargs, parsec, text, transformers, unix

Files

+ LICENSE view
@@ -0,0 +1,202 @@++                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.++   END OF TERMS AND CONDITIONS++   APPENDIX: How to apply the Apache License to your work.++      To apply the Apache License to your work, attach the following+      boilerplate notice, with the fields enclosed by brackets "[]"+      replaced with your own identifying information. (Don't include+      the brackets!)  The text should be enclosed in the appropriate+      comment syntax for the file format. We also recommend that a+      file or class name and description of purpose be included on the+      same "printed page" as the copyright notice for easier+      identification within third-party archives.++   Copyright [yyyy] [name of copyright owner]++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.
+ Setup.hs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main :: IO ()+main = defaultMain
+ Test/Chuchu.hs view
@@ -0,0 +1,186 @@+-- |+-- Module      :  Test.Chuchu+-- Copyright   :  (c) Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com> 2012+-- License     :  Apache 2.0 (see the file LICENSE)+--+-- Maintainer  :  Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+-- Stability   :  unstable+-- Portability :  non-portable (DeriveDataTypeable)+--+-- Chuchu is a system similar to Ruby's Cucumber for Behaviour Driven+-- Development.  It works with a language similar to Cucumber's Gherkin, which+-- is parsed using package abacate.+--+-- This module provides the main function for a test file based on Behaviour+-- Driven Development for Haskell.+--+-- Example for a Stack calculator:+--+-- @calculator.feature@:+--+-- @+--Feature: Division+--  In order to avoid silly mistakes+--  Cashiers must be able to calculate a fraction+--+--  Scenario: Regular numbers+--    Given that I have entered 3 into the calculator+--    And that I have entered 2 into the calculator+--    When I press divide+--    Then the result should be 1.5 on the screen+-- @+--+-- @calculator.hs@:+--+-- @+--import Control.Applicative+--import Control.Monad.IO.Class+--import Control.Monad.Trans.State+--import Test.Chuchu+--import Test.HUnit+--+--type CalculatorT m = StateT \[Double\] m+--+--enterNumber :: Monad m => Double -> CalculatorT m ()+--enterNumber = modify . (:)+--+--getDisplay :: Monad m => CalculatorT m Double+--getDisplay+--  = do+--    ns <- get+--    return $ head $ ns ++ [0]+--+--divide :: Monad m => CalculatorT m ()+--divide = do+--  (n1:n2:ns) <- get+--  put $ (n2 / n1) : ns+--+--defs :: Chuchu (CalculatorT IO)+--defs+--  = do+--    Given+--      ("that I have entered " *> number <* " into the calculator")+--      enterNumber+--    When "I press divide" $ const divide+--    Then ("the result should be " *> number <* " on the screen")+--      $ \\n+--        -> do+--          d <- getDisplay+--          liftIO $ d \@?= n+--+--main :: IO ()+--main = chuchuMain defs (\`evalStateT\` [])+-- @++module+  Test.Chuchu+  (chuchuMain, module Test.Chuchu.Types, module Test.Chuchu.Parser)+  where++-- base+import Control.Applicative+import Control.Monad+import System.Environment+import System.Exit+import System.IO++-- transformers+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Control.Monad.Trans.Reader++-- parsec+import Text.Parsec+import Text.Parsec.Text++-- cmdargs+import System.Console.CmdArgs++-- abacate+import Language.Abacate hiding (StepKeyword (..))++-- chuchu+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 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++type CM m a = ReaderT (Parser (m ())) m a++processAbacate :: MonadIO m => Abacate -> CM m Bool+processAbacate feature+  = do+    bCode+      <- case fBackground feature of+        Nothing -> return True+        Just background -> processBasicScenario background+    feCode <- processFeatureElements $ fFeatureElements feature+    return $ bCode && feCode++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 (FESO _)+  = liftIO (hPutStrLn stderr "Scenario Outlines are not supported yet.")+    >> return False+processFeatureElement (FES sc) = processBasicScenario $ scBasicScenario sc++processBasicScenario :: MonadIO m => BasicScenario -> CM m Bool+processBasicScenario = processSteps . bsSteps++processSteps :: MonadIO m => Steps -> CM m Bool+processSteps steps+  = do+    codes <- mapM processStep steps+    return $ and codes++processStep :: MonadIO m => Step -> CM m Bool+processStep step+  = do+    cc <- ask+    case parse cc "processStep" $ stBody step of+      Left e+        -> do+          liftIO+            $ hPutStrLn stderr+            $ "The step "+              ++ show (stBody step)+              ++ " doesn't match any step definitions I know."+              ++ show e+          return False+      Right m -> lift m >> return True++data Options+  = Options {file_ :: FilePath}+    deriving (Eq, Show, Typeable, Data)++getPath :: IO FilePath+getPath+  = do+    progName <- getProgName+    file_+      <$> cmdArgs+        (Options (def &= typ "PATH" &= argPos 0)+          &= program progName+          &= details+            ["Run test scenarios specified on the abacate file at PATH."])
+ Test/Chuchu/Email.hs view
@@ -0,0 +1,32 @@+-- |+-- Module      :  Test.Chuchu.Parsec+-- Copyright   :  (c) Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com> 2012+-- License     :  Apache 2.0 (see the file LICENSE)+--+-- Maintainer  :  Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+-- Stability   :  unstable+-- Portability :  portable+--+-- This is a very simplified parser for e-mail, which does not follow RFC5322.+-- Basically, it parses @TEXT\@TEXT@, where TEXT is @alphaNum <|> oneOf+-- "!#$%&'*+-/=?^_`{|}~."@.  It's loosely based on+-- <http://porg.es/blog/email-address-validation-simpler-faster-more-correct>.+module Test.Chuchu.Email (addrSpecSimple) where++-- base+import Control.Applicative hiding ((<|>), many, optional)++-- parsec+import Text.Parsec+import Text.Parsec.Text++-- | Parses a simplified e-mail address and return everything that was parsed as+-- a simple 'String'.+addrSpecSimple :: Parser String+addrSpecSimple = concat <$> sequence [atomWithDot, string "@", atomWithDot]++atomWithDot :: Parser String+atomWithDot = many1 atomTextWithDot++atomTextWithDot :: Parser Char+atomTextWithDot = alphaNum <|> oneOf "!#$%&'*+-/=?^_`{|}~."
+ Test/Chuchu/Parsec.hs view
@@ -0,0 +1,215 @@+{-# OPTIONS_GHC -w #-}+-- |+-- Module      :  Test.Chuchu.Parsec+-- Copyright   :  (c) Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com> 2012+-- License     :  Apache 2.0 (see the file LICENSE)+--+-- Maintainer  :  Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+-- Stability   :  unstable+-- Portability :  portable+--+-- This is from the where clause of 'makeTokenParser' with types included and+-- calls to 'lexeme' removed in the functions where this is noted.+--+-- Copyright 1999-2000, Daan Leijen; 2007, Paolo Martini. All rights reserved.+--+-- Redistribution and use in source and binary forms, with or without+-- modification, are permitted provided that the following conditions are met:+--+-- * Redistributions of source code must retain the above copyright notice,+--   this list of conditions and the following disclaimer.+--+-- * Redistributions in binary form must reproduce the above copyright+--   notice, this list of conditions and the following disclaimer in the+--   documentation and/or other materials provided with the distribution.+--+-- This software is provided by the copyright holders "as is" and any express or+-- implied warranties, including, but not limited to, the implied warranties of+-- merchantability and fitness for a particular purpose are disclaimed. In no+-- event shall the copyright holders be liable for any direct, indirect,+-- incidental, special, exemplary, or consequential damages (including, but not+-- limited to, procurement of substitute goods or services; loss of use, data,+-- or profits; or business interruption) however caused and on any theory of+-- liability, whether in contract, strict liability, or tort (including+-- negligence or otherwise) arising in any way out of the use of this software,+-- even if advised of the possibility of such damage.+++module Test.Chuchu.Parsec (stringLiteral, natFloat, int) where++-- base+import Data.Char++-- parsec+import Text.Parsec+import Text.Parsec.Text++{-# ANN module ("HLint: ignore" :: String) #-}+-- | 'lexeme' removed.+stringLiteral :: Parser String+stringLiteral   = do{ str <- between (char '"')+                                     (char '"' <?> "end of string")+                                     (many stringChar)+                    ; return (foldr (maybe id (:)) "" str)+                    }+                  <?> "literal string"++stringChar :: Parser (Maybe Char)+stringChar      =   do{ c <- stringLetter; return (Just c) }+                <|> stringEscape+                <?> "string character"+++stringLetter :: Parser Char+stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))++stringEscape :: Parser (Maybe Char)+stringEscape    = do{ char '\\'+                    ;     do{ escapeGap  ; return Nothing }+                      <|> do{ escapeEmpty; return Nothing }+                      <|> do{ esc <- escapeCode; return (Just esc) }+                    }++escapeEmpty :: Parser Char+escapeEmpty     = char '&'+++escapeGap :: Parser Char+escapeGap       = do{ many1 space+                    ; char '\\' <?> "end of string gap"+                    }++escapeCode :: Parser Char+escapeCode      = charEsc <|> charNum <|> charAscii <|> charControl+                <?> "escape code"++charControl :: Parser Char+charControl     = do{ char '^'+                    ; code <- upper+                    ; return (toEnum (fromEnum code - fromEnum 'A'))+                    }++charNum :: Parser Char+charNum         = do{ code <- decimal+                              <|> do{ char 'o'; number 8 octDigit }+                              <|> do{ char 'x'; number 16 hexDigit }+                    ; return (toEnum (fromInteger code))+                    }++charEsc :: Parser Char+charEsc         = choice (map parseEsc escMap)+                where+                  parseEsc (c,code)     = do{ char c; return code }++charAscii :: Parser Char+charAscii       = choice (map parseAscii asciiMap)+                where+                  parseAscii (asc,code) = try (do{ string asc; return code })+++-- escape code tables+escMap          = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")+asciiMap        = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)++ascii2codes     = ["BS","HT","LF","VT","FF","CR","SO","SI","EM",+                   "FS","GS","RS","US","SP"]+ascii3codes     = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL",+                   "DLE","DC1","DC2","DC3","DC4","NAK","SYN","ETB",+                   "CAN","SUB","ESC","DEL"]++ascii2          = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI',+                   '\EM','\FS','\GS','\RS','\US','\SP']+ascii3          = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK',+                   '\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK',+                   '\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']+++natFloat :: Parser (Either Integer Double)+natFloat        = do{ char '0'+                    ; zeroNumFloat+                    }+                  <|> decimalFloat++zeroNumFloat :: Parser (Either Integer Double)+zeroNumFloat    =  do{ n <- hexadecimal <|> octal+                     ; return (Left n)+                     }+                <|> decimalFloat+                <|> fractFloat 0+                <|> return (Left 0)++decimalFloat :: Parser (Either Integer Double)+decimalFloat    = do{ n <- decimal+                    ; option (Left n)+                             (fractFloat n)+                    }++fractFloat :: Integer -> Parser (Either Integer Double)+fractFloat n    = do{ f <- fractExponent n+                    ; return (Right f)+                    }++fractExponent :: Integer -> Parser Double+fractExponent n = do{ fract <- fraction+                    ; expo  <- option 1.0 exponent'+                    ; return ((fromInteger n + fract)*expo)+                    }+                <|>+                  do{ expo <- exponent'+                    ; return ((fromInteger n)*expo)+                    }+fraction :: Parser Double+fraction        = do{ char '.'+                    ; digits <- many1 digit <?> "fraction"+                    ; return (foldr op 0.0 digits)+                    }+                  <?> "fraction"+                where+                  op d f    = (f + fromIntegral (digitToInt d))/10.0++exponent' :: Parser Double+exponent'       = do{ oneOf "eE"+                    ; f <- sign+                    ; e <- decimal <?> "exponent"+                    ; return (power (f e))+                    }+                  <?> "exponent"+                where+                   power e  | e < 0      = 1.0/power(-e)+                            | otherwise  = fromInteger (10^e)++-- | 'lexeme' removed.+int :: Parser Integer+int             = do{ f <- sign+                    ; n <- nat+                    ; return (f n)+                    }++sign :: Num a => Parser (a -> a)+sign            =   (char '-' >> return negate)+                <|> (char '+' >> return id)+                <|> return id++nat :: Parser Integer+nat             = zeroNumber <|> decimal++zeroNumber :: Parser Integer+zeroNumber      = do{ char '0'+                    ; hexadecimal <|> octal <|> decimal <|> return 0+                    }+                  <?> ""++decimal :: Parser Integer+decimal         = number 10 digit++hexadecimal :: Parser Integer+hexadecimal     = do{ oneOf "xX"; number 16 hexDigit }++octal :: Parser Integer+octal           = do{ oneOf "oO"; number 8 octDigit  }++number base baseDigit+    = do{ digits <- many1 baseDigit+        ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits+        ; seq n (return n)+        }
+ Test/Chuchu/Parser.hs view
@@ -0,0 +1,56 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- |+-- Module      :  Test.Chuchu.Parser+-- Copyright   :  (c) Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com> 2012+-- License     :  Apache 2.0 (see the file LICENSE)+--+-- Maintainer  :  Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+-- Stability   :  unstable+-- Portability :  non-portable (TypeSynonymInstances, FlexibleInstances)+--+-- This modules provides some utility parsers for creating step rules.+module Test.Chuchu.Parser (number, int, text, wildcard, email) where++-- base+import Control.Applicative hiding ((<|>))+import Control.Monad+import GHC.Exts++-- parsec+import Text.Parsec+import Text.Parsec.Text++-- chuchu+import qualified Test.Chuchu.Parsec as P+import Test.Chuchu.Email++instance IsString (Parser a) where+  fromString s = void (string s) >> return undefined++-- | Parses a floating point number, with the same syntax as accepted by+-- Haskell.+number :: Parser Double+number = nofToDouble <$> P.natFloat++nofToDouble :: Either Integer Double -> Double+nofToDouble (Left i) = fromInteger i+nofToDouble (Right d) = d++-- | Parses an integer.+int :: Parser Integer+int = P.int++-- | Parses a quoted string, with the same syntax as accepted by Haskell.+text :: Parser String+text = P.stringLiteral++-- | Parses anything until the string passed as parameter, and also the string.+wildcard :: String -> Parser ()+wildcard = void . manyTill anyChar . string++-- | Parses a simplified e-mail address and return everything that was parsed as+-- a simple 'String'.  This is a very simplified parser for e-mail, which does+-- not follow RFC5322. Basically, it parses @TEXT\@TEXT@, where TEXT is+-- @alphaNum \<|> oneOf \"!#$%&\'*+-\/=?^_\`{|}~.\"@.+email :: Parser String+email = addrSpecSimple
+ Test/Chuchu/Types.hs view
@@ -0,0 +1,54 @@+-- |+-- Module      :  Test.Chuchu.Types+-- Copyright   :  (c) Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com> 2012+-- License     :  Apache 2.0 (see the file LICENSE)+--+-- Maintainer  :  Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+-- Stability   :  unstable+-- Portability :  non-portable (GADTs)+module+  Test.Chuchu.Types+  (Chuchu, ChuchuM (Given, When, Then, And, But), runChuchu)+  where++-- base+import Control.Applicative hiding ((<|>))++-- parsec+import Text.Parsec+import Text.Parsec.Text++-- | The most command 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',+-- 'Then', 'And' and 'But' are interpreted in the same way by the program.  All+-- of them receive a parser and an action to run if the parser finishes+-- correctly.+data ChuchuM m a where+  Given :: Parser a -> (a -> m ()) -> ChuchuM m ()+  When :: Parser a -> (a -> m ()) -> ChuchuM m ()+  Then :: Parser a -> (a -> m ()) -> ChuchuM m ()+  And :: Parser a -> (a -> m ()) -> ChuchuM m ()+  But :: Parser a -> (a -> m ()) -> ChuchuM m ()+  Nil :: ChuchuM m a+  Cons :: ChuchuM m b -> ChuchuM m a -> ChuchuM m a++instance Monad (ChuchuM m) where+  return _ = Nil+  step >>= k = Cons step $ k undefined++-- | Converts the Monad into a single 'Parser' that executes the specified+-- action if the parser is executed correctly.  It includes an 'eof' on the+-- parser of each step to avoid it from accepting prefixes of the desired rule.+runChuchu :: ChuchuM m a -> Parser (m ())+runChuchu Nil = unexpected "Unknown step"+runChuchu (Cons cc1 cc2) = runChuchu cc1 <|> runChuchu cc2+runChuchu (Given p f) = apply p f+runChuchu (When p f) = apply p f+runChuchu (Then p f) = apply p f+runChuchu (And p f) = apply p f+runChuchu (But p f) = apply p f++apply :: Parser a -> (a -> m ()) -> Parser (m ())+apply p f = try $ f <$> p <* eof
+ chuchu.cabal view
@@ -0,0 +1,77 @@+name: chuchu+version: 0.0.0.0+cabal-version: >= 1.8+build-type: Simple+license: OtherLicense+license-file: LICENSE+copyright: 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+author: Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+maintainer: Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+stability: experimental+homepage: http://github.com/marcotmarcot/chuchu+bug-reports: http://github.com/marcotmarcot/chuchu/issues+synopsis: Behaviour Driven Development for Haskell+description:+  Chuchu is a system similar to Ruby's Cucumber for Behaviour Driven+  Development.  It works with a language similar to Cucumber's Gherkin, which is+  parsed using package abacate.+category: Test+tested-with: GHC ==7.4.2+extra-source-files:+  tests/data/environment.feature,+  tests/data/calculator.feature,+  tests/data/prefix.feature++library+  exposed-modules:+    Test.Chuchu,+    Test.Chuchu.Types,+    Test.Chuchu.Parser+  other-modules:+    Test.Chuchu.Parsec,+    Test.Chuchu.Email+  build-depends:+    base >= 4 && < 5,+    text >= 0.11 && < 0.12,+    transformers >= 0.3 && < 0.4,+    parsec >= 3.1 && < 3.2,+    cmdargs >= 0.9 && < 0.10,+    abacate >= 0.0 && < 0.1+  extensions: DeriveDataTypeable, TypeSynonymInstances, FlexibleInstances, GADTs+  ghc-options: -Wall++Test-Suite environment+  type: exitcode-stdio-1.0+  main-is: environment.hs+  hs-source-dirs: tests+  build-depends:+    base >= 4 && < 5,+    unix >= 2.5 && < 2.6,+    chuchu,+    HUnit >= 1.2 && < 1.3+  extensions: OverloadedStrings+  ghc-options: -Wall++Test-Suite calculator+  type: exitcode-stdio-1.0+  main-is: calculator.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 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
+ tests/calculator.hs view
@@ -0,0 +1,61 @@+-- Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+--     http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++-- base+import Control.Applicative+import System.Environment++-- transformers+import Control.Monad.IO.Class+import Control.Monad.Trans.State++-- chuchu+import Test.Chuchu++-- HUnit+import Test.HUnit++type CalculatorT m = StateT [Double] m++enterNumber :: Monad m => Double -> CalculatorT m ()+enterNumber = modify . (:)++getDisplay :: Monad m => CalculatorT m Double+getDisplay+  = do+    ns <- get+    return $ head $ ns ++ [0]++divide :: Monad m => CalculatorT m ()+divide = do+  (n1:n2:ns) <- get+  put $ (n1 / n2) : ns++defs :: Chuchu (CalculatorT IO)+defs+  = do+    Given+      ("that I have entered " *> number <* " into the calculator")+      enterNumber+    When "I press divide" $ const divide+    Then ("the result should be " *> number <* " on the screen")+      $ \n+        -> do+          d <- getDisplay+          liftIO $ d @?= n++main :: IO ()+main+  = withArgs ["tests/data/calculator.feature"]+    $ chuchuMain defs (`evalStateT` [])
+ tests/data/calculator.feature view
@@ -0,0 +1,27 @@+# Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+#+# Licensed under the Apache License, Version 2.0 (the "License");+# you may not use this file except in compliance with the License.+# You may obtain a copy of the License at+#+#     http://www.apache.org/licenses/LICENSE-2.0+#+# Unless required by applicable law or agreed to in writing, software+# distributed under the License is distributed on an "AS IS" BASIS,+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+# See the License for the specific language governing permissions and+# limitations under the License.++# Of course it needs calc!+@needs_calc+@nice_feature+Feature: Division+  In order to avoid silly mistakes+  Cashiers must be able to calculate a fraction++  Scenario: Regular numbers+    Given that I have entered 2 into the calculator+    # Comment! =)+    And that I have entered 3 into the calculator+    When I press divide+    Then the result should be 1.5 on the screen
+ tests/data/environment.feature view
@@ -0,0 +1,26 @@+# Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+#+# Licensed under the Apache License, Version 2.0 (the "License");+# you may not use this file except in compliance with the License.+# You may obtain a copy of the License at+#+#     http://www.apache.org/licenses/LICENSE-2.0+#+# Unless required by applicable law or agreed to in writing, software+# distributed under the License is distributed on an "AS IS" BASIS,+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+# See the License for the specific language governing permissions and+# limitations under the License.++Feature: Environment+  In order to use the enviroment variables+  Programmers must be able to write and read environment variables++  Scenario: Write then read+    When I set the variable as "environment" into the environment+    # Comment! =)+    Then the variable should have "environment" on its content++  Scenario: E-mail variables+    When I set the  as e-mail marcotmarcot@gmail.com into the environment+    Then the  should have e-mail marcotmarcot@gmail.com on its content
+ tests/data/prefix.feature view
@@ -0,0 +1,22 @@+# Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+#+# Licensed under the Apache License, Version 2.0 (the "License");+# you may not use this file except in compliance with the License.+# You may obtain a copy of the License at+#+#     http://www.apache.org/licenses/LICENSE-2.0+#+# Unless required by applicable law or agreed to in writing, software+# distributed under the License is distributed on an "AS IS" BASIS,+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+# See the License for the specific language governing permissions and+# limitations under the License.++Feature: Don't match prefixes+  In order to write scenarios without worrying+  Programmers must be able to write steps that are prefix of others++  Scenario: Prefixes+    When I add 1+    And I add 1 2 times+    Then the result should be 3
+ tests/environment.hs view
@@ -0,0 +1,50 @@+-- Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+--     http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++-- base+import Control.Applicative+import Data.Maybe+import System.Environment hiding (getEnv)++-- unix+import System.Posix.Env++-- chuchu+import Test.Chuchu++-- HUnit+import Test.HUnit++defs :: Chuchu IO+defs+  = do+    When ("I set the " *> wildcard " as " *> text <* " into the environment")+      $ \x -> setEnv "environment" x True+    Then ("the " *> wildcard " should have " *> text <* " on its content")+      $ \n -> fromJust <$> getEnv "environment" >>= (@?= n)+    When+        ("I set the "+          *> wildcard " as e-mail "+          *> email+          <* " into the environment")+      $ \x -> setEnv "environment" x True+    Then+        ("the "+          *> wildcard " should have e-mail "+          *> email+          <* " on its content")+      $ \n -> fromJust <$> getEnv "environment" >>= (@?= n)++main :: IO ()+main = withArgs ["tests/data/environment.feature"] $ chuchuMain defs id
+ tests/prefix.hs view
@@ -0,0 +1,42 @@+-- Copyright 2012 Marco Túlio Pimenta Gontijo <marcotmarcot@gmail.com>+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+--     http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++-- base+import Control.Applicative+import System.Environment++-- transformers+import Control.Monad.IO.Class+import Control.Monad.Trans.State++-- chuchu+import Test.Chuchu++-- HUnit+import Test.HUnit++type CalculatorT m = StateT Integer m++defs :: Chuchu (CalculatorT IO)+defs+  = do+    When ("I add " *> int) $ \x -> modify (+ x)+    When ((,) <$ "I add " <*> int <* " " <*> int <* " times")+      $ \(n, x) -> modify (+ n * x)+    When ("the result should be " *> int) $ \x -> get >>= liftIO . (@?= x)++main :: IO ()+main+  = withArgs ["tests/data/prefix.feature"]+    $ chuchuMain defs (`evalStateT` 0)