diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 cabal.sandbox.config
 *.o
 *.hi
+.stack-work
diff --git a/language-bash.cabal b/language-bash.cabal
--- a/language-bash.cabal
+++ b/language-bash.cabal
@@ -1,11 +1,11 @@
 name:               language-bash
-version:            0.6.1
+version:            0.6.2
 category:           Language
 license:            BSD3
 license-file:       LICENSE
 author:             Kyle Raftogianis
 maintainer:         Kyle Raftogianis <kylerafto@gmail.com>
-copyright:          Copyright (c) 2013-2015 Kyle Raftogianis
+copyright:          Copyright (c) 2013-2016 Kyle Raftogianis
 build-type:         Simple
 cabal-version:      >= 1.8
 homepage:           http://github.com/knrafto/language-bash/
@@ -45,7 +45,7 @@
     base         >= 4.6 && < 5,
     parsec       >= 3.0 && < 4.0,
     pretty       >= 1.0 && < 2.0,
-    transformers >= 0.2 && < 0.5
+    transformers >= 0.2 && < 0.6
 
   ghc-options: -Wall
 
@@ -61,4 +61,6 @@
     process,
     QuickCheck,
     tasty,
-    tasty-quickcheck
+    tasty-quickcheck,
+    tasty-hunit,
+    tasty-expected-failure
diff --git a/src/Language/Bash/Parse.hs b/src/Language/Bash/Parse.hs
--- a/src/Language/Bash/Parse.hs
+++ b/src/Language/Bash/Parse.hs
@@ -18,7 +18,6 @@
 import qualified Language.Bash.Cond           as Cond
 import           Language.Bash.Operator
 import           Language.Bash.Parse.Internal
-import           Language.Bash.Pretty
 import           Language.Bash.Syntax
 import           Language.Bash.Word           (fromString, unquote)
 
@@ -120,8 +119,8 @@
             heredocDelimQuoted = fromString heredocDelim /= w
         h <- heredoc (heredocOp == HereStrip) heredocDelim
         hereDocument <- if heredocDelimQuoted
-                        then heredocWord h
-                        else return (fromString h)
+                        then return (fromString h)
+                        else heredocWord h
         return Heredoc{..}
 
     redirOperator   = selectOperator operator <?> "redirection operator"
@@ -384,13 +383,12 @@
           <?> "function definition"
   where
     functionDef1 = FunctionDef
-               <$> try (word "function" *> (prettyText <$> anyWord)
+               <$> try (word "function" *> name
                         <* optional functionParens <* newlineList)
                <*> functionBody
 
     functionDef2 = FunctionDef
-               <$> try ((prettyText <$> unreservedWord)
-                        <*  functionParens <* newlineList)
+               <$> try (name <* functionParens <* newlineList)
                <*> functionBody
 
     functionParens = operator "(" <* operator ")"
diff --git a/src/Language/Bash/Parse/Word.hs b/src/Language/Bash/Parse/Word.hs
--- a/src/Language/Bash/Parse/Word.hs
+++ b/src/Language/Bash/Parse/Word.hs
@@ -154,10 +154,10 @@
 
 -- | Parse an arithmetic expression.
 arith :: Stream s m Char => ParsecT s u m String
-arith = B.toString <$> parens <?> "arithmetic expression"
+arith = B.toString <$> arithPart <?> "arithmetic expression"
   where
-    parens = B.many inner
-    inner  = B.matchedPair '(' ')' parens
+    arithPart = B.many inner
+    inner     = B.noneOf "()" <|> B.char '(' <+> arithPart <+> B.char ')'
 
 -- | Parse a parenthesized substitution.
 subst :: Stream s m Char => ParsecT s u m String
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -1,22 +1,29 @@
 module Main (main) where
 
-import Control.Applicative
-import System.Process           (readProcess)
-import Test.QuickCheck
-import Test.QuickCheck.Monadic
-import Test.Tasty
-import Test.Tasty.QuickCheck
-import Text.Parsec              (parse)
+import           Control.Applicative ((<$>))
+import           System.Process           (readProcess)
+import           Test.QuickCheck
+import           Test.QuickCheck.Monadic  as QCM
+import           Test.Tasty
+import           Test.Tasty.QuickCheck
+import           Test.Tasty.HUnit
+import           Test.Tasty.ExpectedFailure (expectFail)
+import           Text.Parsec              (parse)
+import           Text.Parsec.Error (ParseError)
 
-import Language.Bash.Expand     (braceExpand)
-import Language.Bash.Parse.Word (word)
-import Language.Bash.Word       (unquote)
 
+import qualified Language.Bash.Parse      as Parse
+import           Language.Bash.Syntax
+import qualified Language.Bash.Cond       as Cond
+import           Language.Bash.Word
+import           Language.Bash.Expand     (braceExpand)
+import           Language.Bash.Parse.Word (word)
+
 -- TODO sequence
 braceExpr :: Gen String
 braceExpr = concat <$> listOf charset
   where
-    charset = oneof $
+    charset = oneof
         [ elements ["{", ",", "}"]
         , elements ["\\ ", "\\{", "\\,", "\\}"]
         , (:[]) <$> elements ['a'..'z']
@@ -37,10 +44,73 @@
 prop_expandsLikeBash = monadicIO $ forAllM braceExpr $ \str -> do
     bash <- run $ expandWithBash str
     let check = unwords . filter (not . null) $ testExpand str
-    assert (bash == check)
+    run $ putStrLn bash
+    run $ putStrLn check
+    QCM.assert (bash == check)
 
+properties :: TestTree
+properties = testGroup "Properties" [testProperty "brace expansion" prop_expandsLikeBash]
+
+testMatches :: (Eq a, Show a) => TestName -> Either Text.Parsec.Error.ParseError a -> a -> TestTree
+testMatches name parsed expected = testCase name $
+           case parsed of
+               Left err -> assertFailure $ "parseError: " ++ show err
+               Right ans -> expected @=? ans
+
+wrapCommand :: Command -> List
+wrapCommand c = List [Statement (Last Pipeline {timed = False, timedPosix = False, inverted = False, commands = [c]}) Sequential]
+
+tp :: TestName -> Command -> TestTree
+tp source expected = testMatches (filter ((/=) '\n') source)
+                                 (Parse.parse "source" source)
+                                 (wrapCommand expected)
+
+expandString :: String -> [Span]
+expandString = map Char
+
+unittests :: TestTree
+unittests = testGroup "Unit tests"
+  [
+    testMatches "testTest"
+      (Cond.parseTestExpr ["!", "-e", "\"asd\""])
+      (Cond.Not (Cond.Unary Cond.FileExists "\"asd\""))
+  , tp "\"$(ls)\""
+      (Command (SimpleCommand [] [[Double [CommandSubst "ls"]]]) [])
+  , tp "arguments=()"
+      (Command (SimpleCommand [Assign (Parameter "arguments" Nothing) Equals (RArray [])] []) [])
+  , tp "cat <<EOF\nasd\\`\nEOF"
+       (Command
+        (SimpleCommand [] [expandString "cat"])
+        [Heredoc {heredocOp = Here,
+                  heredocDelim = "EOF",
+                  heredocDelimQuoted = False,
+                  hereDocument = [Char 'a',Char 's',Char 'd',Escape '`',
+                                  Char '\n']}])
+  , tp "cat <<\"EOF\"\nasd\\`\nEOF"
+       (Command
+        (SimpleCommand [] [expandString "cat"])
+        [Heredoc {heredocOp = Here,
+                  heredocDelim = "EOF",
+                  heredocDelimQuoted = True,
+                  hereDocument = expandString "asd\\`\n"}])
+  , tp "echo $((2 + 2))"
+       (Command
+        (SimpleCommand [] [expandString "echo", [ArithSubst "2 + 2"]])
+        [])
+  , tp "((2 + 2))"
+       (Command (Arith "2 + 2") [])
+  , tp "echo $(((2 + 2)))"
+       (Command
+        (SimpleCommand [] [expandString "echo", [ArithSubst "(2 + 2)"]])
+        [])
+  ]
+
+failingtests :: TestTree
+failingtests = testGroup "Failing tests" (map expectFail
+  [])
+
 tests :: TestTree
-tests = testProperty "brace expansion" prop_expandsLikeBash
+tests = testGroup "Tests" [properties, unittests, failingtests]
 
 main :: IO ()
 main = defaultMain tests
