diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Language/Abacate.hs b/Language/Abacate.hs
new file mode 100644
--- /dev/null
+++ b/Language/Abacate.hs
@@ -0,0 +1,45 @@
+-- |
+-- Module      :  Language.Abacate
+-- 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
+--
+-- Gherkin is the language used by the Cucumber system for Behaviour Driven
+-- Development.  This package contains a parser to it, based on its BNF with
+-- minor changes.  For more information on Cucumber, check <http://cukes.info>.
+--
+-- According to
+-- <https://github.com/cucumber/gherkin/wiki/BNF/cf8696092b0e6841ba0c3cf4e2f0d3c964b9c144>.
+module
+  Language.Abacate
+  (module Language.Abacate.Types, parseFile,  parseAbacate)
+  where
+
+-- base
+import Prelude hiding (readFile)
+import Control.Applicative
+
+-- text
+import Data.Text
+import Data.Text.IO
+
+-- parsec
+import Text.Parsec
+
+-- abacate
+import Language.Abacate.Types
+import Language.Abacate.BNF
+
+-- | Parses a file with 'Abacate' code.
+parseFile :: FilePath -> IO (Either ParseError Abacate)
+parseFile path = parseAbacateWithSource path <$> readFile path
+
+-- | Parses a string with 'Abacate' code.
+parseAbacate :: Text -> Either ParseError Abacate
+parseAbacate = parseAbacateWithSource "parseAbacate"
+
+parseAbacateWithSource :: FilePath -> Text -> Either ParseError Abacate
+parseAbacateWithSource = parse abacate
diff --git a/Language/Abacate/BNF.hs b/Language/Abacate/BNF.hs
new file mode 100644
--- /dev/null
+++ b/Language/Abacate/BNF.hs
@@ -0,0 +1,251 @@
+-- |
+-- Module      :  Language.Abacate.BNF
+-- 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
+module Language.Abacate.BNF (abacate) where
+
+-- base
+import Prelude hiding (unlines)
+import Control.Applicative hiding (many, (<|>), optional)
+import Control.Monad
+
+-- text
+import Data.Text hiding (map)
+
+-- parsec
+import Text.Parsec
+import Text.Parsec.Text
+
+-- abacate
+import Language.Abacate.Types
+
+abacate :: Parser Abacate
+abacate = feature
+
+feature :: Parser Feature
+feature
+  = do
+    white
+    pBegComment <- comment
+    pTags <- tags
+    pHeader <- header
+    pBackground <- option Nothing $ Just <$> try background
+    pFeatureElements <- featureElements
+    pEndComment <- comment
+    return
+      $ Feature
+        pBegComment
+        pTags
+        pHeader
+        pBackground
+        pFeatureElements
+        pEndComment
+
+header :: Parser Header
+header
+  = strip
+    <$> pack
+    <$> manyTill anyChar
+      (lookAhead
+         $ choice
+         $ map try [void scenarioOutline, void scenario, void background])
+
+featureElements :: Parser FeatureElements
+featureElements
+  = many $ (FES <$> try scenario) <|> (FESO <$> try scenarioOutline)
+
+scenario :: Parser Scenario
+scenario
+  = do
+    pComment <- comment
+    pTags <- tags
+    scenarioKeyword
+    (name, pSteps) <- scenarioCommon
+    return $ Scenario pTags $ BasicScenario pComment name pSteps
+
+scenarioOutline :: Parser ScenarioOutline
+scenarioOutline
+  = do
+    pComment <- comment
+    pTags <- tags
+    scenarioOutlineKeyword
+    (name, pSteps) <- scenarioCommon
+    pExamplesSection <- examplesSection
+    white
+    return
+      $ ScenarioOutline pExamplesSection
+      $ Scenario pTags
+      $ BasicScenario pComment name pSteps
+
+background :: Parser Background
+background
+  = do
+    pComment <- comment
+    backgroundKeyword
+    (name, pSteps) <- scenarioCommon
+    return $ BasicScenario pComment name pSteps
+
+tags :: Parser Tags
+tags
+  = white
+    >> many
+      (do
+        pTag <- tag
+        white1
+        return pTag)
+
+tag :: Parser Tag
+tag = char '@' >> pack <$> many1 (noneOf "@\r\n\t ")
+
+comment :: Parser Comment
+comment
+  = unlines
+    <$> many
+      (do
+        pComment <- commentLine
+        white
+        return pComment)
+
+commentLine :: Parser Comment
+commentLine = gSpaces >> char '#' >> lineToEol
+
+steps :: Parser Steps
+steps = many $ try step
+
+step :: Parser Step
+step
+ = do
+   pComment <- comment
+   gSpaces
+   keyword <- stepKeyword
+   keywordSpace
+   body <- lineToEol
+   void (many1 eol) <|> eof
+   pMultilineArg <- option Nothing $ Just <$> try multilineArg
+   white
+   return $ Step pComment keyword body pMultilineArg
+
+examplesSection :: Parser ExamplesSection
+examplesSection = many $ try examples
+
+examples :: Parser Examples
+examples
+  = do
+    pComment <- comment
+    gSpaces
+    examplesKeyword
+    gSpaces
+    name <- linesToKeyword
+    eol
+    pTable <- table
+    white
+    return $ Examples pComment name pTable
+
+multilineArg :: Parser MultilineArg
+multilineArg = MAT <$> try table <|> MAPS <$> try pyString
+
+pyString :: Parser PyString
+pyString
+  = openPyString >> strip <$> pack <$> manyTill anyChar (try closePyString)
+
+openPyString :: Parser ()
+openPyString = gSpaces >> string "\"\"\"" >> gSpaces >> eol
+
+closePyString :: Parser ()
+closePyString = eol >> gSpaces >> string "\"\"\"" >> white
+
+cell :: Parser Cell
+cell
+  = do
+    pCell <- many1 (noneOf "\r\n|")
+    void (char '|')
+    return $ strip $ pack pCell
+
+row :: Parser Row
+row
+  = do
+    white
+    void $ char '|'
+    pRow <- many1 $ try cell
+    eol
+    return pRow
+
+table :: Parser Table
+table = many1 $ try row
+
+stepKeyword :: Parser StepKeyword
+stepKeyword
+  = read
+    <$> choice
+      (map (try . string . show) ([minBound .. maxBound] :: [StepKeyword]))
+
+examplesKeyword :: Parser ()
+examplesKeyword = void $ string "Examples:"
+
+scenarioOutlineKeyword :: Parser ()
+scenarioOutlineKeyword = void $ string "Scenario Outline:"
+
+scenarioKeyword :: Parser ()
+scenarioKeyword = void $ string "Scenario:"
+
+backgroundKeyword :: Parser ()
+backgroundKeyword = void $ string "Background:"
+
+linesToKeyword :: Parser Text
+linesToKeyword
+  = strip
+    <$> pack
+    <$> manyTill
+      anyChar
+      (lookAhead $ try $ eol >> gSpaces >> reservedWordsAndSymbols)
+
+reservedWordsAndSymbols :: Parser ()
+reservedWordsAndSymbols
+  = choice
+    $ map
+      try
+      [stepKeyword >> keywordSpace,
+        scenarioKeyword,
+        scenarioOutlineKeyword,
+        void table,
+        void tag,
+        void commentLine]
+
+gSpace :: Parser ()
+gSpace = void $ oneOf " \t"
+
+eol :: Parser ()
+eol = optional (char '\r') >> void (char '\n')
+
+white :: Parser ()
+white = skipMany oneWhite
+
+lineToEol :: Parser Text
+lineToEol = pack <$> many (noneOf "\r\n")
+
+keywordSpace :: Parser ()
+keywordSpace = void $ char ' '
+
+-- Not defined in BNF
+
+oneWhite :: Parser ()
+oneWhite = gSpace <|> eol
+
+white1 :: Parser ()
+white1 = skipMany1 oneWhite
+
+gSpaces :: Parser ()
+gSpaces = skipMany gSpace
+
+scenarioCommon :: Parser (Text, Steps)
+scenarioCommon
+  = do
+    gSpaces
+    name <- linesToKeyword
+    white
+    pSteps <- steps
+    return (name, pSteps)
diff --git a/Language/Abacate/Types.hs b/Language/Abacate/Types.hs
new file mode 100644
--- /dev/null
+++ b/Language/Abacate/Types.hs
@@ -0,0 +1,107 @@
+-- |
+-- Module      :  Language.Abacate.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 :  portable
+module Language.Abacate.Types where
+
+-- text
+import Data.Text
+
+-- | An Abacate file contains exactly one feature.
+type Abacate = Feature
+
+-- | For a more detailed description of features, check
+-- <https://github.com/cucumber/cucumber/wiki/Feature-Introduction>.
+data Feature
+  = Feature
+      {fBegComment :: Comment,
+        fTags :: Tags,
+        fHeader :: Header,
+        fBackground :: Maybe Background,
+        fFeatureElements :: FeatureElements,
+        fEndComment :: Comment}
+    deriving (Eq, Show)
+
+-- | The 'Header' contains the title and description of the 'Feature'.  It is
+-- usually on the format:
+--
+-- @
+-- Feature: TITLE
+--   DESCRIPTION LINE 1
+--   DESCRIPTION LINE 2
+-- @
+type Header = Text
+
+type FeatureElements = [FeatureElement]
+
+-- | A 'FeatureElement' is simply a 'Scenario' or a 'ScenarioOutline'.
+data FeatureElement
+  = FES Scenario | FESO ScenarioOutline
+    deriving (Eq, Show)
+
+-- | The 'Scenario' contains a list of 'Steps'.
+data Scenario
+  = Scenario {scTags :: Tags, scBasicScenario :: BasicScenario}
+    deriving (Eq, Show)
+
+-- | The 'Steps' of the 'ScenarioOutline' can contain placeholders which are
+-- substituted by the fields of the 'ExamplesSection'.  For more information on
+-- the 'ScenarioOutline' check
+-- <https://github.com/cucumber/cucumber/wiki/Scenario-outlines>.
+data ScenarioOutline
+  = ScenarioOutline
+      {soExamplesSection :: ExamplesSection, soScenario :: Scenario}
+    deriving (Eq, Show)
+
+-- | The 'Background' is basically a 'Scenario' without 'Tags'.  It's used to
+-- create a context for the other 'Scenario's to run, and a 'Feature' can only
+-- have one 'Background'.  For more information on the 'Background' check
+-- <https://github.com/cucumber/cucumber/wiki/Background>.
+type Background = BasicScenario
+
+-- | This is the basic type for 'Scenario', 'ScenarioOutline' and 'Background'.
+data BasicScenario
+  = BasicScenario {bsComment :: Comment, bsName :: Text, bsSteps :: Steps}
+    deriving (Eq, Show)
+
+type Tags = [Tag]
+
+-- | A 'Tag' is a textual element started with \@.
+type Tag = Text
+
+type Comment = Text
+type Steps = [Step]
+
+-- | For more information on 'Steps' check
+-- <https://github.com/cucumber/cucumber/wiki/Given-When-Then>.
+data Step
+  = Step
+      {stComment :: Comment,
+        stStepKeyword :: StepKeyword,
+        stBody :: Text,
+        stMultilineArg :: Maybe MultilineArg}
+    deriving (Eq, Show)
+
+type ExamplesSection = [Examples]
+
+-- | The 'Examples' are used to fill the value of placeholders on
+-- 'ScenarioOutline's.
+data Examples
+  = Examples {eComment :: Comment, eName :: Text, eTable :: Table}
+    deriving (Eq, Show)
+
+-- | 'Steps' can have multi-line arguments.  For more information check
+-- <https://github.com/cucumber/cucumber/wiki/Multiline-Step-Arguments>.
+data MultilineArg = MAT Table | MAPS PyString deriving (Eq, Show)
+
+type PyString = Text
+type Table = [Row]
+type Row = [Cell]
+type Cell = Text
+
+data StepKeyword
+  = Given | When | Then | And | But deriving (Eq, Bounded, Enum, Show, Read)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,4 @@
+import Distribution.Simple
+
+main :: IO ()
+main = defaultMain
diff --git a/abacate.cabal b/abacate.cabal
new file mode 100644
--- /dev/null
+++ b/abacate.cabal
@@ -0,0 +1,49 @@
+name: abacate
+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/abacate
+bug-reports: http://github.com/marcotmarcot/abacate/issues
+synopsis: Parser for a language similar to Cucumber's Gherkin
+description:
+  Gherkin is the language used by the Cucumber system for Behaviour Driven
+  Development.  This package contains a parser to it, based on its BNF with
+  minor changes.  For more information on Cucumber, check <http://cukes.info>.
+category: Language
+tested-with: GHC ==7.4.2
+extra-source-files:
+  tests/data/environment.feature,
+  tests/data/givenWhenGivenWhen.feature,
+  tests/data/calculator.feature,
+  tests/data/wrongComment.feature,
+  tests/data/complete.feature
+
+library
+  exposed-modules:
+    Language.Abacate,
+    Language.Abacate.Types
+  other-modules:
+    Language.Abacate.BNF
+  build-depends:
+    base >= 4 && < 5,
+    text >= 0.11 && < 0.12,
+    parsec >= 3.1 && < 3.2
+  ghc-options: -Wall
+
+Test-Suite abacate-test
+  type: exitcode-stdio-1.0
+  main-is: abacate.hs
+  hs-source-dirs: tests
+  build-depends:
+    base >= 4 && < 5,
+    text,
+    text >= 0.11 && < 0.12,
+    abacate >= 0.0 && <= 0.1,
+    HUnit >= 1.2 && <= 1.3
+  ghc-options: -Wall
diff --git a/tests/abacate.hs b/tests/abacate.hs
new file mode 100644
--- /dev/null
+++ b/tests/abacate.hs
@@ -0,0 +1,345 @@
+-- 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 System.Exit
+
+-- text
+import Data.Text hiding (map)
+
+-- abacate
+import Language.Abacate
+
+-- HUnit
+import Test.HUnit
+
+main :: IO ()
+main
+  = do
+    counts_ <- runTestTT tests
+    if errors counts_ + failures counts_ > 0
+      then exitFailure
+      else exitSuccess
+
+tests :: Test
+tests
+  = TestList
+    [TestCase
+        $ parseFile "tests/data/environment.feature"
+          >>= (Feature
+                empty
+                []
+                (pack
+                  $ "Feature: Environment\n"
+                    ++ "  In order to use the environment variables\n"
+                    ++ "  Programmers must be able to write and read "
+                    ++ "environment variables")
+                Nothing
+                [FES
+                  $ Scenario []
+                  $ BasicScenario
+                    empty
+                    (pack "Write then read")
+                    [Step
+                        empty
+                        When
+                        (pack "I set the variable as 3 into the environment")
+                        Nothing,
+                      Step
+                        (pack " Comment! =)\n")
+                        Then
+                        (pack "the variable should have 3 on its content")
+                        Nothing]]
+                empty
+              @=?)
+            . fromRight,
+      TestCase
+        $ parseFile "tests/data/givenWhenGivenWhen.feature"
+          >>= (Feature
+                empty
+                []
+                (pack
+                  $ "Feature: Given When Given When\n"
+                    ++ "  In order to write more complicated test cases\n"
+                    ++ "  Programmers must be able to write more than one "
+                    ++ "Given When sequence")
+                Nothing
+                [FES
+                  $ Scenario []
+                  $ BasicScenario
+                    empty
+                    (pack "Given When Given When")
+                    [Step
+                        empty
+                        Given
+                        (pack "that A is logged in")
+                        Nothing,
+                      Step
+                        empty
+                        When
+                        (pack "he goes to his user page")
+                        Nothing,
+                      Step
+                        empty
+                        Then
+                        (pack "he sees his user name")
+                        Nothing,
+                      Step
+                        empty
+                        When
+                        (pack "he clicks \"Premium\"")
+                        Nothing,
+                      Step
+                        empty
+                        Then
+                        (pack "he sees that he is a premium user")
+                        Nothing]]
+                empty
+              @=?)
+            . fromRight,
+      TestCase
+        $ parseFile "tests/data/calculator.feature"
+          >>= (Feature
+                (pack " Of course it needs calc!\n")
+                [pack "needs_calc", pack "nice_feature"]
+                (pack
+                  $ "Feature: Division\n"
+                    ++ "  In order to avoid silly mistakes\n"
+                    ++ "  Cashiers must be able to calculate a fraction")
+                Nothing
+                [FES
+                  $ Scenario []
+                  $ BasicScenario
+                    empty
+                    (pack "Regular numbers")
+                    [Step
+                        empty
+                        Given
+                        (pack "that I have entered 3 into the calculator")
+                        Nothing,
+                      Step
+                        (pack " Comment! =)\n")
+                        And
+                        (pack "that I have entered 2 into the calculator")
+                        Nothing,
+                      Step
+                        empty
+                        When
+                        (pack "I press divide")
+                        Nothing,
+                      Step
+                        empty
+                        Then
+                        (pack "the result should be 1.5 on the screen")
+                        Nothing]]
+                empty
+              @=?)
+            . fromRight,
+      TestCase
+        $ parseFile "tests/data/wrongComment.feature"
+          >>= (Feature
+                empty
+                []
+                (pack
+                  $ "Feature: Wrong Comment\n"
+                    ++ "  In order to use # inside steps\n"
+                    ++ "  Programmers must be able to write steps without "
+                    ++ "being interpreted as comments")
+                Nothing
+                [FES
+                  $ Scenario []
+                  $ BasicScenario
+                    empty
+                    (pack "User logged in sees his page")
+                    [Step
+                        empty
+                        Given
+                        (pack "that #A is logged in")
+                        Nothing,
+                      Step
+                        empty
+                        When
+                        (pack "he goes to his user page")
+                        Nothing,
+                      Step
+                        empty
+                        Then
+                        (pack "he sees his user name")
+                        Nothing]]
+                empty
+              @=?)
+            . fromRight,
+      TestCase
+        $ parseFile "tests/data/complete.feature"
+          >>= (Feature
+                empty
+                []
+                (pack
+                  $ "Feature: Complete\n"
+                    ++ "  In order to use all the syntax\n"
+                    ++ "  Users must be able to write all the syntax elements")
+                (Just
+                  $ BasicScenario
+                    (pack " Background\n")
+                    empty
+                    [Step
+                        empty
+                        Given
+                        (pack "a global administrator named \"Greg\"")
+                        Nothing,
+                      Step
+                        empty
+                        And
+                        (pack "a blog named \"Greg's anti-tax rants\"")
+                        Nothing,
+                      Step
+                        empty
+                        And
+                        (pack "a customer named \"Dr. Bill\"")
+                        Nothing,
+                      Step
+                        empty
+                        And
+                        (pack
+                          $ "a blog named \"Expensive Therapy\" owned by "
+                            ++ "\"Dr. Bill\"")
+                        Nothing])
+                [FESO
+                    $ ScenarioOutline
+                      [Examples empty empty
+                        $ map
+                          (map pack)
+                          [["start", "eat", "left"],
+                            ["12", "5", "7"],
+                            ["20", "5", "15"]]]
+                    $ Scenario []
+                    $ BasicScenario
+                      (pack " Scenario outline\n")
+                      (pack "eating")
+                      [Step
+                          empty
+                          Given
+                          (pack "there are <start> cucumbers")
+                          Nothing,
+                        Step
+                          empty
+                          When
+                          (pack "I eat <eat> cucumbers")
+                          Nothing,
+                        Step
+                          empty
+                          Then
+                          (pack "I should have <left> cucumbers")
+                          Nothing],
+                  FES
+                    $ Scenario [pack "wip"]
+                    $ BasicScenario
+                      (pack " Scenario\n")
+                      (pack
+                        $ "Delete the blue lorry, which is magic and always "
+                          ++ "raises an error")
+                      [Step
+                          empty
+                          Given
+                          (pack "the following lorries:")
+                          (Just
+                            $ MAT
+                            $ map
+                              (map pack)
+                              [["name", "colour"],
+                                ["name 1", "green"],
+                                ["name 2", "yellow"],
+                                ["name 3", "pink"],
+                                ["name 4", "blue"]]),
+                        Step
+                          empty
+                          But
+                          (pack "I delete the 4th lorry")
+                          Nothing,
+                        Step
+                          empty
+                          Given
+                          (pack
+                             "a blog post named \"Random\" with Markdown body")
+                          (Just
+                            $ MAPS
+                            $ pack
+                            $ "Some Title, Eh?\n"
+                              ++ "    ==============\n"
+                              ++ "    Here is the first paragraph of my blog "
+                              ++ "post. Lorem ipsum dolor sit amet,\n"
+                              ++ "    consectetur adipiscing elit.")],
+                  FESO
+                    $ ScenarioOutline
+                      [Examples empty empty
+                        $ map
+                          (map pack)
+                          [["Role", "details"],
+                            ["Manager",
+                              "now able to manage your employee accounts"],
+                            ["Admin",
+                              "able to manage any user account on the system"]]]
+                    $ Scenario []
+                    $ BasicScenario
+                      empty
+                      (pack "Email confirmation")
+                      [Step
+                          empty
+                          Given
+                          (pack
+                            $ "I have a user account with my name "
+                              ++ "\"Jojo Binks\"")
+                          Nothing,
+                        Step
+                          empty
+                          When
+                          (pack "an Admin grants me <Role> rights")
+                          Nothing,
+                        Step
+                          empty
+                          Then
+                          (pack "I should receive an email with the body:")
+                          (Just
+                            $ MAPS
+                            $ pack
+                            $ "Dear Jojo Binks,\n"
+                              ++ "      You have been granted <Role> rights.  "
+                              ++ "You are <details>. Please be responsible.\n"
+                              ++ "      -The Admins")],
+                  FESO
+                    $ ScenarioOutline
+                      [Examples empty empty
+                        $ map
+                          (map pack)
+                          [["x", "y"], ["2", "14"], ["10", "70"]]]
+                    $ Scenario []
+                    $ BasicScenario
+                      empty
+                      (pack "Multiplying with 7")
+                      [Step
+                          empty
+                          Given
+                          (pack "I have the numbers")
+                          (Just
+                            $ MAT
+                            $ map
+                              (map pack)
+                              [["q1", "q2", "product"], ["<x>", "7", "<y>"]])]]
+                (pack " Final comment\n")
+              @=?)
+            . fromRight]
+
+fromRight :: Show a => Either a b -> b
+fromRight (Right b) = b
+fromRight (Left a) = error $ "fromRight (Left " ++ show a ++ ")"
diff --git a/tests/data/calculator.feature b/tests/data/calculator.feature
new file mode 100644
--- /dev/null
+++ b/tests/data/calculator.feature
@@ -0,0 +1,13 @@
+# 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 3 into the calculator
+    # Comment! =)
+    And that I have entered 2 into the calculator
+    When I press divide
+    Then the result should be 1.5 on the screen
diff --git a/tests/data/complete.feature b/tests/data/complete.feature
new file mode 100644
--- /dev/null
+++ b/tests/data/complete.feature
@@ -0,0 +1,65 @@
+Feature: Complete
+  In order to use all the syntax
+  Users must be able to write all the syntax elements
+
+  # Background
+  Background:
+    Given a global administrator named "Greg"
+    And a blog named "Greg's anti-tax rants"
+    And a customer named "Dr. Bill"
+    And a blog named "Expensive Therapy" owned by "Dr. Bill"
+
+  # Scenario outline
+  Scenario Outline: eating
+    Given there are <start> cucumbers
+    When I eat <eat> cucumbers
+    Then I should have <left> cucumbers
+
+    Examples:
+      | start | eat | left |
+      |  12   |  5  |  7   |
+      |  20   |  5  |  15  |
+
+  # Scenario
+  @wip
+  Scenario: Delete the blue lorry, which is magic and always raises an error
+  Given the following lorries:
+    | name | colour |
+    | name 1 | green |
+    | name 2 | yellow |
+    | name 3 | pink |
+    | name 4 | blue |
+  But I delete the 4th lorry
+  Given a blog post named "Random" with Markdown body
+    """
+    Some Title, Eh?
+    ==============
+    Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet,
+    consectetur adipiscing elit.
+    """
+
+  Scenario Outline: Email confirmation
+    Given I have a user account with my name "Jojo Binks"
+    When an Admin grants me <Role> rights
+    Then I should receive an email with the body:
+      """
+      Dear Jojo Binks,
+      You have been granted <Role> rights.  You are <details>. Please be responsible.
+      -The Admins
+      """
+    Examples:
+      |  Role     | details                                         |
+      |  Manager  | now able to manage your employee accounts       |
+      |  Admin    | able to manage any user account on the system   |
+
+  Scenario Outline: Multiplying with 7
+    Given I have the numbers
+      | q1   | q2 | product |
+      | <x>  |  7 | <y>     |
+    Examples:
+      |  x |  y |
+      |  2 | 14 |
+      | 10 | 70 |
+
+
+# Final comment
diff --git a/tests/data/environment.feature b/tests/data/environment.feature
new file mode 100644
--- /dev/null
+++ b/tests/data/environment.feature
@@ -0,0 +1,8 @@
+Feature: Environment
+  In order to use the environment variables
+  Programmers must be able to write and read environment variables
+
+  Scenario: Write then read
+    When I set the variable as 3 into the environment
+    # Comment! =)
+    Then the variable should have 3 on its content
diff --git a/tests/data/givenWhenGivenWhen.feature b/tests/data/givenWhenGivenWhen.feature
new file mode 100644
--- /dev/null
+++ b/tests/data/givenWhenGivenWhen.feature
@@ -0,0 +1,10 @@
+Feature: Given When Given When
+  In order to write more complicated test cases
+  Programmers must be able to write more than one Given When sequence
+
+  Scenario: Given When Given When
+    Given that A is logged in
+    When he goes to his user page
+    Then he sees his user name
+    When he clicks "Premium"
+    Then he sees that he is a premium user
diff --git a/tests/data/wrongComment.feature b/tests/data/wrongComment.feature
new file mode 100644
--- /dev/null
+++ b/tests/data/wrongComment.feature
@@ -0,0 +1,8 @@
+Feature: Wrong Comment
+  In order to use # inside steps
+  Programmers must be able to write steps without being interpreted as comments
+
+  Scenario: User logged in sees his page
+    Given that #A is logged in
+    When he goes to his user page
+    Then he sees his user name
