diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+0.5.13:
+	* Add QuasiQuoters absdir, reldir, absfile, relfile
 0.5.11:
 	* Add replaceExtension and fileExtension
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
 # Path
 
+[![Travis Build Status](https://travis-ci.org/commercialhaskell/path.svg)](https://travis-ci.org/commercialhaskell/path)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/commercialhaskell/path?svg=true)](https://ci.appveyor.com/project/chrisdone/path)
+[![Hackage](https://img.shields.io/hackage/v/path.svg)](https://hackage.haskell.org/package/path)
+[![Stackage LTS](http://stackage.org/package/path/badge/lts)](http://stackage.org/lts/package/path)
+[![Stackage Nightly](http://stackage.org/package/path/badge/nightly)](http://stackage.org/nightly/package/path)
+
 Support for well-typed paths in Haskell.
 
 * [Motivation](#motivation)
@@ -213,6 +219,16 @@
 $(mkRelFile "chris/x.txt")
 ```
 
+With the [QuasiQuotes](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#ghc-flag--XQuasiQuotes)
+language extension, paths can be written as follows:
+
+```haskell
+[absdir|/home/chris|]
+[reldir|chris|]
+[absfile|/home/chris/x.txt|]
+[relfile|chris/x.txt|]
+```
+
 These will run at compile-time and underneath use the appropriate parser.
 
 ### Overloaded strings
@@ -267,7 +283,7 @@
 absolute. You can’t append two absolute paths, for example:
 
 ```haskell
-λ> $(mkAbsDir "/home/chris") </> $(mkAbsDir "/home/chris")
+λ> [absdir|/home/chris|]</>[absdir|/home/chris|]
 <interactive>:23:31-55:
     Couldn't match type ‘Abs’ with ‘Rel’
 ```
@@ -298,7 +314,7 @@
 "/home/chris/"
 λ> toFilePath $(mkRelDir "foo//bar")
 "foo/bar/"
-λ> $(mkAbsDir "/home/chris//") </> $(mkRelDir "foo//bar")
+λ> [absdir|/home/chris//|]</>[reldir|foo//bar|]
 "/home/chris/foo/bar/"
 ```
 
@@ -308,9 +324,9 @@
 prevents improper appending:
 
 ```haskell
-λ> $(mkAbsDir "/home/chris/") </> $(mkRelFile "foo//bar")
+λ> [absdir|/home/chris/|]</>[relfile|foo//bar|]
 "/home/chris/foo/bar"
-λ> $(mkAbsFile "/home/chris") </> $(mkRelFile "foo//bar")
+λ> [absfile|/home/chris|]</>[relfile|foo//bar|]
 <interactive>:35:1-26:
     Couldn't match type ‘File’ with ‘Dir’
 ```
diff --git a/path.cabal b/path.cabal
--- a/path.cabal
+++ b/path.cabal
@@ -1,15 +1,15 @@
 name:                path
-version:             0.5.12
+version:             0.5.13
 synopsis:            Support for well-typed paths
 description:         Support for well-typed paths.
 license:             BSD3
 license-file:        LICENSE
 author:              Chris Done <chrisdone@fpcomplete.com>
 maintainer:          Chris Done <chrisdone@fpcomplete.com>
-copyright:           2015–2016 FP Complete
-category:            Filesystem
+copyright:           2015–2017 FP Complete
+category:            System, Filesystem
 build-type:          Simple
-cabal-version:       >=1.8
+cabal-version:       >=1.10
 extra-source-files:  README.md, CHANGELOG
 
 flag validity
@@ -18,52 +18,55 @@
   description: Enable validity tests.
 
 library
-  hs-source-dirs:    src/
+  hs-source-dirs:    src
   ghc-options:       -Wall -O2
   exposed-modules:   Path, Path.Internal
-  build-depends:     base >= 4 && <5
-                   , exceptions
-                   , filepath < 1.2.0.1 || >= 1.3
-                   , template-haskell
+  build-depends:     aeson
+                   , base       >= 4.7     && < 5
                    , deepseq
-                   , aeson
-                   , hashable >= 1.2 && < 1.3
+                   , exceptions >= 0.4     && < 0.9
+                   , filepath   < 1.2.0.1  || >= 1.3
+                   , hashable   >= 1.2     && < 1.3
+                   , template-haskell
+  default-language:  Haskell2010
 
 test-suite test
-    type: exitcode-stdio-1.0
-    main-is: Main.hs
-    hs-source-dirs: test
-    build-depends: HUnit
-                 , QuickCheck
-                 , aeson
-                 , base
-                 , bytestring
-                 , filepath
-                 , hspec
-                 , mtl
-                 , path
+  type:              exitcode-stdio-1.0
+  main-is:           Main.hs
+  other-modules:     Posix
+                   , Windows
+  hs-source-dirs:    test
+  build-depends:     aeson
+                   , base       >= 4.7     && < 5
+                   , bytestring
+                   , filepath   < 1.2.0.1  || >= 1.3
+                   , hspec      >= 2.0     && < 3
+                   , mtl        >= 2.0     && < 3
+                   , path
+  default-language:  Haskell2010
 
 test-suite validity-test
-    if !flag(validity)
-      buildable: False
-    type: exitcode-stdio-1.0
-    main-is: ValidityTest.hs
-    other-modules: Path.Gen
-    hs-source-dirs: test
-    if flag(validity)
-      build-depends: HUnit
-                   , QuickCheck
+  if !flag(validity)
+    buildable: False
+  type:              exitcode-stdio-1.0
+  main-is:           ValidityTest.hs
+  other-modules:     Path.Gen
+  hs-source-dirs:    test
+  if flag(validity)
+    build-depends:   QuickCheck
                    , aeson
-                   , base >= 4.9 && < 5
+                   , base       >= 4.9 && < 5
                    , bytestring
-                   , filepath
+                   , filepath   < 1.2.0.1  || >= 1.3
                    , genvalidity >= 0.3 && < 0.4
                    , genvalidity-hspec >= 0.3 && < 0.4
-                   , hspec
-                   , mtl
+                   , hspec      >= 2.0     && < 3
+                   , mtl        >= 2.0     && < 3
                    , path
-                   , validity >= 0.3.1.1 && < 0.4
+                   , validity   >= 0.3.1.1 && < 0.4
+  default-language:  Haskell2010
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
 
 source-repository head
-    type:     git
-    location: https://github.com/chrisdone/path.git
+  type:              git
+  location:          https://github.com/commercialhaskell/path.git
diff --git a/src/Path.hs b/src/Path.hs
--- a/src/Path.hs
+++ b/src/Path.hs
@@ -1,13 +1,4 @@
--- |
--- Module      :  Path
--- Copyright   :  © 2015–2016 FP Complete
--- License     :  BSD 3 clause
---
--- Maintainer  :  Chris Done <chrisdone@fpcomplete.com>
--- Stability   :  experimental
--- Portability :  portable
---
--- Support for well-typed paths.
+-- | Support for well-typed paths.
 
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE TemplateHaskell #-}
@@ -23,17 +14,20 @@
   ,Rel
   ,File
   ,Dir
-   -- * Parsing
-  ,parseAbsDir
-  ,parseRelDir
-  ,parseAbsFile
-  ,parseRelFile
-  ,PathParseException
-  -- * Constructors
-  ,mkAbsDir
-  ,mkRelDir
-  ,mkAbsFile
-  ,mkRelFile
+  -- * QuasiQuoters
+  -- | Using the following requires the QuasiQuotes language extension.
+  --
+  -- __For Windows users__, the QuasiQuoters are especially beneficial because they
+  -- prevent Haskell from treating @\\@ as an escape character.
+  -- This makes Windows paths easier to write.
+  --
+  -- @
+  -- [absfile|C:\\chris\\foo.txt|]
+  -- @
+  ,absdir
+  ,reldir
+  ,absfile
+  ,relfile
   -- * Operations
   ,(</>)
   ,stripDir
@@ -43,24 +37,37 @@
   ,dirname
   ,fileExtension
   ,setFileExtension
+   -- * Parsing
+  ,parseAbsDir
+  ,parseRelDir
+  ,parseAbsFile
+  ,parseRelFile
+  ,PathParseException
   -- * Conversion
   ,toFilePath
   ,fromAbsDir
   ,fromRelDir
   ,fromAbsFile
   ,fromRelFile
+  -- * TemplateHaskell constructors
+  -- | These require the TemplateHaskell language extension.
+  ,mkAbsDir
+  ,mkRelDir
+  ,mkAbsFile
+  ,mkRelFile
   )
   where
 
 import           Control.Exception (Exception)
+import           Control.Monad
 import           Control.Monad.Catch (MonadThrow(..))
 import           Data.Aeson (FromJSON (..))
 import qualified Data.Aeson.Types as Aeson
-import           Data.Coerce
 import           Data.Data
 import           Data.List
 import           Data.Maybe
 import           Language.Haskell.TH
+import           Language.Haskell.TH.Quote (QuasiQuoter(..))
 import           Path.Internal
 import qualified System.FilePath as FilePath
 
@@ -117,7 +124,193 @@
   deriving (Show,Typeable)
 instance Exception PathParseException
 
+
 --------------------------------------------------------------------------------
+-- QuasiQuoters
+
+qq :: (String -> Q Exp) -> QuasiQuoter
+qq quoteExp' =
+  QuasiQuoter
+  { quoteExp  = quoteExp'
+  , quotePat  = \_ ->
+      fail "illegal QuasiQuote (allowed as expression only, used as a pattern)"
+  , quoteType = \_ ->
+      fail "illegal QuasiQuote (allowed as expression only, used as a type)"
+  , quoteDec  = \_ ->
+      fail "illegal QuasiQuote (allowed as expression only, used as a declaration)"
+  }
+
+-- | Construct a 'Path' 'Abs' 'Dir' using QuasiQuotes.
+--
+-- @
+-- [absdir|/|]
+--
+-- [absdir|\/home\/chris|]
+-- @
+--
+-- Remember: due to the nature of absolute paths a path like @[absdir|\/home\/chris|]@
+-- may compile on your platform, but it may not compile on another
+-- platform (Windows).
+--
+-- @since 0.5.13
+absdir :: QuasiQuoter
+absdir = qq mkAbsDir
+
+-- | Construct a 'Path' 'Rel' 'Dir' using QuasiQuotes.
+--
+-- @
+-- [absdir|\/home|]\<\/>[reldir|chris|]
+-- @
+--
+-- @since 0.5.13
+reldir :: QuasiQuoter
+reldir = qq mkRelDir
+
+-- | Construct a 'Path' 'Abs' 'File' using QuasiQuotes.
+--
+-- @
+-- [absfile|\/home\/chris\/foo.txt|]
+-- @
+--
+-- Remember: due to the nature of absolute paths a path like @[absdir|\/home\/chris\/foo.txt|]@
+-- may compile on your platform, but it may not compile on another
+-- platform (Windows).
+--
+-- @since 0.5.13
+absfile :: QuasiQuoter
+absfile = qq mkAbsFile
+
+-- | Construct a 'Path' 'Rel' 'File' using QuasiQuotes.
+--
+-- @
+-- [absdir|\/home\/chris|]\<\/>[relfile|foo.txt|]
+-- @
+--
+-- @since 0.5.13
+relfile :: QuasiQuoter
+relfile = qq mkRelFile
+
+--------------------------------------------------------------------------------
+-- Operations
+
+-- | Append two paths.
+--
+-- The following cases are valid and the equalities hold:
+--
+-- @$(mkAbsDir x) \<\/> $(mkRelDir y) = $(mkAbsDir (x ++ \"/\" ++ y))@
+--
+-- @$(mkAbsDir x) \<\/> $(mkRelFile y) = $(mkAbsFile (x ++ \"/\" ++ y))@
+--
+-- @$(mkRelDir x) \<\/> $(mkRelDir y) = $(mkRelDir (x ++ \"/\" ++ y))@
+--
+-- @$(mkRelDir x) \<\/> $(mkRelFile y) = $(mkRelFile (x ++ \"/\" ++ y))@
+--
+-- The following are proven not possible to express:
+--
+-- @$(mkAbsFile …) \<\/> x@
+--
+-- @$(mkRelFile …) \<\/> x@
+--
+-- @x \<\/> $(mkAbsFile …)@
+--
+-- @x \<\/> $(mkAbsDir …)@
+--
+(</>) :: Path b Dir -> Path Rel t -> Path b t
+(</>) (Path a) (Path b) = Path (a ++ b)
+
+-- | Strip directory from path, making it relative to that directory.
+-- Throws 'Couldn'tStripPrefixDir' if directory is not a parent of the path.
+--
+-- The following properties hold:
+--
+-- @stripDir x (x \<\/> y) = y@
+--
+-- Cases which are proven not possible:
+--
+-- @stripDir (a :: Path Abs …) (b :: Path Rel …)@
+--
+-- @stripDir (a :: Path Rel …) (b :: Path Abs …)@
+--
+-- In other words the bases must match.
+--
+stripDir :: MonadThrow m
+         => Path b Dir -> Path b t -> m (Path Rel t)
+stripDir (Path p) (Path l) =
+  case stripPrefix p l of
+    Nothing -> throwM (Couldn'tStripPrefixDir p l)
+    Just "" -> throwM (Couldn'tStripPrefixDir p l)
+    Just ok -> return (Path ok)
+
+-- | Is p a parent of the given location? Implemented in terms of
+-- 'stripDir'. The bases must match.
+--
+-- The following properties hold:
+--
+-- @not (x \`isParentOf\` x)@
+--
+-- @x \`isParentOf\` (x \<\/\> y)@
+--
+isParentOf :: Path b Dir -> Path b t -> Bool
+isParentOf p l =
+  isJust (stripDir p l)
+
+-- | Take the absolute parent directory from the absolute path.
+--
+-- The following properties hold:
+--
+-- @parent (x \<\/> y) == x@
+--
+-- On the root, getting the parent is idempotent:
+--
+-- @parent (parent \"\/\") = \"\/\"@
+--
+parent :: Path Abs t -> Path Abs Dir
+parent (Path fp) =
+  Path (normalizeDir (FilePath.takeDirectory (FilePath.dropTrailingPathSeparator fp)))
+
+-- | Extract the file part of a path.
+--
+-- The following properties hold:
+--
+-- @filename (p \<\/> a) == filename a@
+--
+filename :: Path b File -> Path Rel File
+filename (Path l) =
+  Path (FilePath.takeFileName l)
+
+-- | Extract the last directory name of a path.
+--
+-- The following properties hold:
+--
+-- @dirname (p \<\/> a) == dirname a@
+--
+dirname :: Path b Dir -> Path Rel Dir
+dirname (Path l) =
+  Path (last (FilePath.splitPath l))
+
+-- | Get extension from given file path.
+--
+-- @since 0.5.11
+fileExtension :: Path b File -> String
+fileExtension = FilePath.takeExtension . toFilePath
+
+-- | Replace\/add extension to given file path. Throws if the
+-- resulting filename does not parse.
+--
+-- @since 0.5.11
+setFileExtension :: MonadThrow m
+  => String            -- ^ Extension to set
+  -> Path b File       -- ^ Old file name
+  -> m (Path b File)   -- ^ New file name with the desired extension
+setFileExtension ext (Path path) =
+  if FilePath.isAbsolute path
+    then liftM coercePath (parseAbsFile (FilePath.replaceExtension path ext))
+    else liftM coercePath (parseRelFile (FilePath.replaceExtension path ext))
+  where coercePath :: Path a b -> Path a' b'
+        coercePath (Path a) = Path a
+
+
+--------------------------------------------------------------------------------
 -- Parsers
 
 -- | Convert an absolute 'FilePath' to a normalized absolute dir 'Path'.
@@ -154,7 +347,6 @@
      not (null filepath) &&
      filepath /= "." &&
      normalizeFilePath filepath /= curDirNormalizedFP &&
-     filepath /= ".." &&
      FilePath.isValid filepath
      then return (Path (normalizeDir filepath))
      else throwM (InvalidRelDir filepath)
@@ -213,25 +405,39 @@
     (FilePath.isAbsolute filepath || FilePath.hasTrailingPathSeparator filepath) &&
   not (null filepath) &&
   not (hasParentDir filepath) &&
-  filepath /= "." && filepath /= ".." && FilePath.isValid filepath
+  filepath /= "." && FilePath.isValid filepath
 
--- | Helper function: check if the filepath has any parent directories in it.
--- This handles the logic of checking for different path separators on Windows.
-hasParentDir :: FilePath -> Bool
-hasParentDir filepath' =
-     ("/.." `isSuffixOf` filepath) ||
-     ("/../" `isInfixOf` filepath) ||
-     ("../" `isPrefixOf` filepath)
-  where
-    filepath =
-        case FilePath.pathSeparator of
-            '/' -> filepath'
-            x   -> map (\y -> if x == y then '/' else y) filepath'
+--------------------------------------------------------------------------------
+-- Conversion
 
+-- | Convert to a 'FilePath' type.
+--
+-- All directories have a trailing slash, so if you want no trailing
+-- slash, you can use 'System.FilePath.dropTrailingPathSeparator' from
+-- the filepath package.
+toFilePath :: Path b t -> FilePath
+toFilePath (Path l) = l
+
+-- | Convert absolute path to directory to 'FilePath' type.
+fromAbsDir :: Path Abs Dir -> FilePath
+fromAbsDir = toFilePath
+
+-- | Convert relative path to directory to 'FilePath' type.
+fromRelDir :: Path Rel Dir -> FilePath
+fromRelDir = toFilePath
+
+-- | Convert absolute path to file to 'FilePath' type.
+fromAbsFile :: Path Abs File -> FilePath
+fromAbsFile = toFilePath
+
+-- | Convert relative path to file to 'FilePath' type.
+fromRelFile :: Path Rel File -> FilePath
+fromRelFile = toFilePath
+
 --------------------------------------------------------------------------------
 -- Constructors
 
--- | Make a 'Path Abs Dir'.
+-- | Make a 'Path' 'Abs' Dir'.
 --
 -- Remember: due to the nature of absolute paths this (e.g. @\/home\/foo@)
 -- may compile on your platform, but it may not compile on another
@@ -243,7 +449,7 @@
     Right (Path str) ->
       [|Path $(return (LitE (StringL str))) :: Path Abs Dir|]
 
--- | Make a 'Path Rel Dir'.
+-- | Make a 'Path' 'Rel' 'Dir'.
 mkRelDir :: FilePath -> Q Exp
 mkRelDir s =
   case parseRelDir s of
@@ -251,7 +457,7 @@
     Right (Path str) ->
       [|Path $(return (LitE (StringL str))) :: Path Rel Dir|]
 
--- | Make a 'Path Abs File'.
+-- | Make a 'Path' 'Abs' 'File'.
 --
 -- Remember: due to the nature of absolute paths this (e.g. @\/home\/foo@)
 -- may compile on your platform, but it may not compile on another
@@ -263,7 +469,7 @@
     Right (Path str) ->
       [|Path $(return (LitE (StringL str))) :: Path Abs File|]
 
--- | Make a 'Path Rel File'.
+-- | Make a 'Path' 'Rel' 'File'.
 mkRelFile :: FilePath -> Q Exp
 mkRelFile s =
   case parseRelFile s of
@@ -271,151 +477,8 @@
     Right (Path str) ->
       [|Path $(return (LitE (StringL str))) :: Path Rel File|]
 
---------------------------------------------------------------------------------
--- Conversion
 
--- | Convert to a 'FilePath' type.
---
--- All directories have a trailing slash, so if you want no trailing
--- slash, you can use 'System.FilePath.dropTrailingPathSeparator' from
--- the filepath package.
-toFilePath :: Path b t -> FilePath
-toFilePath (Path l) = l
-
--- | Convert absolute path to directory to 'FilePath' type.
-fromAbsDir :: Path Abs Dir -> FilePath
-fromAbsDir = toFilePath
-
--- | Convert relative path to directory to 'FilePath' type.
-fromRelDir :: Path Rel Dir -> FilePath
-fromRelDir = toFilePath
-
--- | Convert absolute path to file to 'FilePath' type.
-fromAbsFile :: Path Abs File -> FilePath
-fromAbsFile = toFilePath
-
--- | Convert relative path to file to 'FilePath' type.
-fromRelFile :: Path Rel File -> FilePath
-fromRelFile = toFilePath
-
 --------------------------------------------------------------------------------
--- Operations
-
--- | Append two paths.
---
--- The following cases are valid and the equalities hold:
---
--- @$(mkAbsDir x) \<\/> $(mkRelDir y) = $(mkAbsDir (x ++ \"/\" ++ y))@
---
--- @$(mkAbsDir x) \<\/> $(mkRelFile y) = $(mkAbsFile (x ++ \"/\" ++ y))@
---
--- @$(mkRelDir x) \<\/> $(mkRelDir y) = $(mkRelDir (x ++ \"/\" ++ y))@
---
--- @$(mkRelDir x) \<\/> $(mkRelFile y) = $(mkRelFile (x ++ \"/\" ++ y))@
---
--- The following are proven not possible to express:
---
--- @$(mkAbsFile …) \<\/> x@
---
--- @$(mkRelFile …) \<\/> x@
---
--- @x \<\/> $(mkAbsFile …)@
---
--- @x \<\/> $(mkAbsDir …)@
---
-(</>) :: Path b Dir -> Path Rel t -> Path b t
-(</>) (Path a) (Path b) = Path (a ++ b)
-
--- | Strip directory from path, making it relative to that directory.
--- Throws 'Couldn'tStripPrefixDir' if directory is not a parent of the path.
---
--- The following properties hold:
---
--- @stripDir x (x \<\/> y) = y@
---
--- Cases which are proven not possible:
---
--- @stripDir (a :: Path Abs …) (b :: Path Rel …)@
---
--- @stripDir (a :: Path Rel …) (b :: Path Abs …)@
---
--- In other words the bases must match.
---
-stripDir :: MonadThrow m
-         => Path b Dir -> Path b t -> m (Path Rel t)
-stripDir (Path p) (Path l) =
-  case stripPrefix p l of
-    Nothing -> throwM (Couldn'tStripPrefixDir p l)
-    Just "" -> throwM (Couldn'tStripPrefixDir p l)
-    Just ok -> return (Path ok)
-
--- | Is p a parent of the given location? Implemented in terms of
--- 'stripDir'. The bases must match.
---
--- The following properties hold:
---
--- @not (x `isParentOf` x)@
---
--- @x `isParentOf` (x \<\/\> y)@
---
-isParentOf :: Path b Dir -> Path b t -> Bool
-isParentOf p l =
-  isJust (stripDir p l)
-
--- | Take the absolute parent directory from the absolute path.
---
--- The following properties hold:
---
--- @parent (x \<\/> y) == x@
---
--- On the root, getting the parent is idempotent:
---
--- @parent (parent \"\/\") = \"\/\"@
---
-parent :: Path Abs t -> Path Abs Dir
-parent (Path fp) =
-  Path (normalizeDir (FilePath.takeDirectory (FilePath.dropTrailingPathSeparator fp)))
-
--- | Extract the file part of a path.
---
--- The following properties hold:
---
--- @filename (p \<\/> a) == filename a@
---
-filename :: Path b File -> Path Rel File
-filename (Path l) =
-  Path (FilePath.takeFileName l)
-
--- | Extract the last directory name of a path.
---
--- The following properties hold:
---
--- @dirname (p \<\/> a) == dirname a@
---
-dirname :: Path b Dir -> Path Rel Dir
-dirname (Path l) =
-  Path (last (FilePath.splitPath l))
-
--- | Get extension from given file path.
---
--- @since 0.5.11
-fileExtension :: Path b File -> String
-fileExtension = FilePath.takeExtension . toFilePath
-
--- | Replace\/add extension to given file path. Throws if the
--- resulting filename does not parse.
---
--- @since 0.5.11
-setFileExtension :: MonadThrow m
-  => String            -- ^ Extension to set
-  -> Path b File       -- ^ Old file name
-  -> m (Path b File)   -- ^ New file name with the desired extension
-setFileExtension ext (Path path) =
-  if FilePath.isAbsolute path
-    then fmap coerce (parseAbsFile (FilePath.replaceExtension path ext))
-    else fmap coerce (parseRelFile (FilePath.replaceExtension path ext))
-
---------------------------------------------------------------------------------
 -- Internal functions
 
 curDirNormalizedFP :: FilePath
@@ -436,3 +499,4 @@
             = normalizeLeadingSeparators (sep:xs)
         normalizeLeadingSeparators x = x
 #endif
+
diff --git a/src/Path/Internal.hs b/src/Path/Internal.hs
--- a/src/Path/Internal.hs
+++ b/src/Path/Internal.hs
@@ -4,16 +4,25 @@
 -- | Internal types and functions.
 
 module Path.Internal
-  (Path(..))
+  ( Path(..)
+  , hasParentDir
+  )
   where
 
 import Control.DeepSeq (NFData (..))
 import Data.Aeson (ToJSON (..))
 import Data.Data
 import Data.Hashable
+import Data.List
+import qualified System.FilePath as FilePath
 
 -- | Path of some base and type.
 --
+-- The type variables are:
+--
+--   * @b@ — base, the base location of the path; absolute or relative.
+--   * @t@ — type, whether file or directory.
+--
 -- Internally is a string. The string can be of two formats only:
 --
 -- 1. File format: @file.txt@, @foo\/bar.txt@, @\/foo\/bar.txt@
@@ -40,7 +49,7 @@
 instance Ord (Path b t) where
   compare (Path x) (Path y) = compare x y
 
--- | Same as 'Path.toFilePath'.
+-- | Same as 'show . Path.toFilePath'.
 --
 -- The following property holds:
 --
@@ -61,3 +70,17 @@
 
 instance Hashable (Path b t) where
   hashWithSalt n (Path path) = hashWithSalt n path
+
+-- | Helper function: check if the filepath has any parent directories in it.
+-- This handles the logic of checking for different path separators on Windows.
+hasParentDir :: FilePath -> Bool
+hasParentDir filepath' =
+     (filepath' == "..") ||
+     ("/.." `isSuffixOf` filepath) ||
+     ("/../" `isInfixOf` filepath) ||
+     ("../" `isPrefixOf` filepath)
+  where
+    filepath =
+        case FilePath.pathSeparator of
+            '/' -> filepath'
+            x   -> map (\y -> if x == y then '/' else y) filepath'
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,279 +1,15 @@
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE CPP #-}
 
--- | Test suite.
+module Main (main) where
 
-module Main where
+#ifdef mingw32_HOST_OS
+import Windows (spec)
+#else
+import Posix (spec)
+#endif
 
-import Control.Applicative
-import Control.Monad
-import Data.Aeson
-import qualified Data.ByteString.Lazy.Char8 as LBS
-import Data.Maybe
-import Path
-import Path.Internal
 import Test.Hspec
-import Test.QuickCheck
 
 -- | Test suite entry point, returns exit failure if any test fails.
 main :: IO ()
 main = hspec spec
-
--- | Test suite.
-spec :: Spec
-spec =
-  do describe "Parsing: Path Abs Dir" parseAbsDirSpec
-     describe "Parsing: Path Rel Dir" parseRelDirSpec
-     describe "Parsing: Path Abs File" parseAbsFileSpec
-     describe "Parsing: Path Rel File" parseRelFileSpec
-     describe "Operations: (</>)" operationAppend
-     describe "Operations: stripDir" operationStripDir
-     describe "Operations: isParentOf" operationIsParentOf
-     describe "Operations: parent" operationParent
-     describe "Operations: filename" operationFilename
-     describe "Operations: dirname" operationDirname
-     describe "Restrictions" restrictions
-     describe "Aeson Instances" aesonInstances
-
--- | Restricting the input of any tricks.
-restrictions :: Spec
-restrictions =
-  do -- These ~ related ones below are now lifted:
-     -- https://github.com/chrisdone/path/issues/19
-     parseSucceeds "~/" (Path "~/")
-     parseSucceeds "~/foo" (Path "~/foo/")
-     parseSucceeds "~/foo/bar" (Path "~/foo/bar/")
-     --
-     parseFails "../"
-     parseFails ".."
-     parseFails "."
-     parseFails "/.."
-     parseFails "/foo/../bar/"
-     parseFails "/foo/bar/.."
-     parseFailsPending "/hello/\n/world"
-     parseFailsPending "white/\r/space"
-  where parseFails x =
-          it (show x ++ " should be rejected")
-             (isNothing (void (parseAbsDir x) <|>
-                         void (parseRelDir x) <|>
-                         void (parseAbsFile x) <|>
-                         void (parseRelFile x)))
-        parseFailsPending x =
-          it (show x ++ " should be rejected")
-             pending
-        parseSucceeds x with =
-          parserTest parseRelDir x (Just with)
-
--- | The 'dirname' operation.
-operationDirname :: Spec
-operationDirname = do
-  it
-    "dirname ($(mkAbsDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
-    (dirname ($(mkAbsDir "/home/chris/") </> $(mkRelDir "bar")) ==
-     dirname $(mkRelDir "bar"))
-  it
-    "dirname ($(mkRelDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
-    (dirname ($(mkRelDir "home/chris/") </> $(mkRelDir "bar")) ==
-     dirname $(mkRelDir "bar"))
-
--- | The 'filename' operation.
-operationFilename :: Spec
-operationFilename =
-  do it "filename ($(mkAbsDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
-          (filename ($(mkAbsDir "/home/chris/") </>
-                             $(mkRelFile "bar.txt")) ==
-                                      filename $(mkRelFile "bar.txt"))
-
-     it "filename ($(mkRelDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
-             (filename ($(mkRelDir "home/chris/") </>
-                                $(mkRelFile "bar.txt")) ==
-                                         filename $(mkRelFile "bar.txt"))
-
--- | The 'parent' operation.
-operationParent :: Spec
-operationParent =
-  do it "parent (parent </> child) == parent"
-        (parent ($(mkAbsDir "/foo") </>
-                    $(mkRelDir "bar")) ==
-         $(mkAbsDir "/foo"))
-     it "parent \"\" == \"\""
-        (parent $(mkAbsDir "/") ==
-         $(mkAbsDir "/"))
-     it "parent (parent \"\") == \"\""
-        (parent (parent $(mkAbsDir "/")) ==
-         $(mkAbsDir "/"))
-
--- | The 'isParentOf' operation.
-operationIsParentOf :: Spec
-operationIsParentOf =
-  do it "isParentOf parent (parent </> child) (unit test)"
-        (isParentOf
-           $(mkAbsDir "///bar/")
-           ($(mkAbsDir "///bar/") </>
-            $(mkRelFile "bar/foo.txt")))
-
-     it "isParentOf parent (parent </> child) (unit test)"
-        (isParentOf
-           $(mkRelDir "bar/")
-           ($(mkRelDir "bar/") </>
-            $(mkRelFile "bob/foo.txt")))
-
--- | The 'stripDir' operation.
-operationStripDir :: Spec
-operationStripDir =
-  do it "stripDir parent (parent </> child) = child (unit test)"
-        (stripDir $(mkAbsDir "///bar/")
-                  ($(mkAbsDir "///bar/") </>
-                   $(mkRelFile "bar/foo.txt")) ==
-         Just $(mkRelFile "bar/foo.txt"))
-
-     it "stripDir parent (parent </> child) = child (unit test)"
-        (stripDir $(mkRelDir "bar/")
-                  ($(mkRelDir "bar/") </>
-                   $(mkRelFile "bob/foo.txt")) ==
-         Just $(mkRelFile "bob/foo.txt"))
-
-     it "stripDir parent parent = _|_"
-        (stripDir $(mkAbsDir "/home/chris/foo")
-                  $(mkAbsDir "/home/chris/foo") ==
-         Nothing)
-
--- | The '</>' operation.
-operationAppend :: Spec
-operationAppend =
-  do it "AbsDir + RelDir = AbsDir"
-        ($(mkAbsDir "/home/") </>
-         $(mkRelDir "chris") ==
-         $(mkAbsDir "/home/chris/"))
-     it "AbsDir + RelFile = AbsFile"
-        ($(mkAbsDir "/home/") </>
-         $(mkRelFile "chris/test.txt") ==
-         $(mkAbsFile "/home/chris/test.txt"))
-     it "RelDir + RelDir = RelDir"
-        ($(mkRelDir "home/") </>
-         $(mkRelDir "chris") ==
-         $(mkRelDir "home/chris"))
-     it "RelDir + RelFile = RelFile"
-        ($(mkRelDir "home/") </>
-         $(mkRelFile "chris/test.txt") ==
-         $(mkRelFile "home/chris/test.txt"))
-
--- | Tests for the tokenizer.
-parseAbsDirSpec :: Spec
-parseAbsDirSpec =
-  do failing ""
-     failing "./"
-     failing "foo.txt"
-     succeeding "/" (Path "/")
-     succeeding "//" (Path "/")
-     succeeding "///foo//bar//mu/" (Path "/foo/bar/mu/")
-     succeeding "///foo//bar////mu" (Path "/foo/bar/mu/")
-     succeeding "///foo//bar/.//mu" (Path "/foo/bar/mu/")
-
-  where failing x = parserTest parseAbsDir x Nothing
-        succeeding x with = parserTest parseAbsDir x (Just with)
-
--- | Tests for the tokenizer.
-parseRelDirSpec :: Spec
-parseRelDirSpec =
-  do failing ""
-     failing "/"
-     failing "//"
-     succeeding "~/" (Path "~/") -- https://github.com/chrisdone/path/issues/19
-     failing "/"
-     failing "./"
-     failing "././"
-     failing "//"
-     failing "///foo//bar//mu/"
-     failing "///foo//bar////mu"
-     failing "///foo//bar/.//mu"
-     succeeding "..." (Path ".../")
-     succeeding "foo.bak" (Path "foo.bak/")
-     succeeding "./foo" (Path "foo/")
-     succeeding "././foo" (Path "foo/")
-     succeeding "./foo/./bar" (Path "foo/bar/")
-     succeeding "foo//bar//mu//" (Path "foo/bar/mu/")
-     succeeding "foo//bar////mu" (Path "foo/bar/mu/")
-     succeeding "foo//bar/.//mu" (Path "foo/bar/mu/")
-
-  where failing x = parserTest parseRelDir x Nothing
-        succeeding x with = parserTest parseRelDir x (Just with)
-
--- | Tests for the tokenizer.
-parseAbsFileSpec :: Spec
-parseAbsFileSpec =
-  do failing ""
-     failing "./"
-     failing "/."
-     failing "/foo/bar/."
-     failing "~/"
-     failing "./foo.txt"
-     failing "/"
-     failing "//"
-     failing "///foo//bar//mu/"
-     succeeding "/..." (Path "/...")
-     succeeding "/foo.txt" (Path "/foo.txt")
-     succeeding "///foo//bar////mu.txt" (Path "/foo/bar/mu.txt")
-     succeeding "///foo//bar/.//mu.txt" (Path "/foo/bar/mu.txt")
-
-  where failing x = parserTest parseAbsFile x Nothing
-        succeeding x with = parserTest parseAbsFile x (Just with)
-
--- | Tests for the tokenizer.
-parseRelFileSpec :: Spec
-parseRelFileSpec =
-  do failing ""
-     failing "/"
-     failing "//"
-     failing "~/"
-     failing "/"
-     failing "./"
-     failing "a/."
-     failing "a/../b"
-     failing "a/.."
-     failing "../foo.txt"
-     failing "//"
-     failing "///foo//bar//mu/"
-     failing "///foo//bar////mu"
-     failing "///foo//bar/.//mu"
-     succeeding "a.." (Path "a..")
-     succeeding "..." (Path "...")
-     succeeding "foo.txt" (Path "foo.txt")
-     succeeding "./foo.txt" (Path "foo.txt")
-     succeeding "././foo.txt" (Path "foo.txt")
-     succeeding "./foo/./bar.txt" (Path "foo/bar.txt")
-     succeeding "foo//bar//mu.txt" (Path "foo/bar/mu.txt")
-     succeeding "foo//bar////mu.txt" (Path "foo/bar/mu.txt")
-     succeeding "foo//bar/.//mu.txt" (Path "foo/bar/mu.txt")
-
-  where failing x = parserTest parseRelFile x Nothing
-        succeeding x with = parserTest parseRelFile x (Just with)
-
--- | Parser test.
-parserTest :: (Show a1,Show a,Eq a1)
-           => (a -> Maybe a1) -> a -> Maybe a1 -> SpecWith ()
-parserTest parser input expected =
-  it ((case expected of
-         Nothing -> "Failing: "
-         Just{} -> "Succeeding: ") ++
-      "Parsing " ++
-      show input ++
-      " " ++
-      case expected of
-        Nothing -> "should fail."
-        Just x -> "should succeed with: " ++ show x)
-     (actual `shouldBe` expected)
-  where actual = parser input
-
--- | Tests for the 'ToJSON' and 'FromJSON' instances
---
--- Can't use overloaded strings due to some weird issue with bytestring-0.9.2.1 / ghc-7.4.2:
--- https://travis-ci.org/sjakobi/path/jobs/138399072#L989
-aesonInstances :: Spec
-aesonInstances =
-  do it "Decoding \"[\"/foo/bar\"]\" as a [Path Abs Dir] should succeed." $
-       eitherDecode (LBS.pack "[\"/foo/bar\"]") `shouldBe` Right [Path "/foo/bar/" :: Path Abs Dir]
-     it "Decoding \"[\"/foo/bar\"]\" as a [Path Rel Dir] should fail." $
-       decode (LBS.pack "[\"/foo/bar\"]") `shouldBe` (Nothing :: Maybe [Path Rel Dir])
-     it "Encoding \"[\"/foo/bar/mu.txt\"]\" should succeed." $
-       encode [Path "/foo/bar/mu.txt" :: Path Abs File] `shouldBe` (LBS.pack "[\"/foo/bar/mu.txt\"]")
diff --git a/test/Path/Gen.hs b/test/Path/Gen.hs
--- a/test/Path/Gen.hs
+++ b/test/Path/Gen.hs
@@ -6,6 +6,7 @@
 
 import qualified System.FilePath as FilePath
 
+import           Data.Maybe (mapMaybe)
 import           Data.List (isInfixOf)
 import           Data.Validity
 import           Data.GenValidity
@@ -18,8 +19,7 @@
     =  FilePath.isAbsolute fp
     && not (FilePath.hasTrailingPathSeparator fp)
     && FilePath.isValid fp
-    && not (".." `isInfixOf` fp)
-    && not (containsLineBreaks fp)
+    && not (hasParentDir fp)
     && (parseAbsFile fp == Just p)
 
 instance Validity (Path Rel File) where
@@ -28,9 +28,7 @@
     && not (FilePath.hasTrailingPathSeparator fp)
     && FilePath.isValid fp
     && fp /= "."
-    && fp /= ".."
-    && not (".." `isInfixOf` fp)
-    && not (containsLineBreaks fp)
+    && not (hasParentDir fp)
     && (parseRelFile fp == Just p)
 
 instance Validity (Path Abs Dir) where
@@ -38,8 +36,7 @@
     =  FilePath.isAbsolute fp
     && FilePath.hasTrailingPathSeparator fp
     && FilePath.isValid fp
-    && not (".." `isInfixOf` fp)
-    && not (containsLineBreaks fp)
+    && not (hasParentDir fp)
     && (parseAbsDir fp == Just p)
 
 instance Validity (Path Rel Dir) where
@@ -49,32 +46,49 @@
     && FilePath.isValid fp
     && not (null fp)
     && fp /= "."
-    && fp /= ".."
-    && not (".." `isInfixOf` fp)
-    && not (containsLineBreaks fp)
+    && not (hasParentDir fp)
     && (parseRelDir fp == Just p)
 
-
-containsLineBreaks :: String -> Bool
-containsLineBreaks s = any (`elem` s) "\n\r"
-
 instance GenUnchecked (Path Abs File) where
-  genUnchecked = Path <$> arbitrary
+  genUnchecked = Path <$> genFilePath
 
 instance GenValid (Path Abs File)
 
 instance GenUnchecked (Path Rel File) where
-  genUnchecked = Path <$> arbitrary
+  genUnchecked = Path <$> genFilePath
 
 instance GenValid (Path Rel File)
 
 instance GenUnchecked (Path Abs Dir) where
-  genUnchecked = Path <$> arbitrary
+  genUnchecked = Path <$> genFilePath
 
 instance GenValid (Path Abs Dir)
 
 instance GenUnchecked (Path Rel Dir) where
-  genUnchecked = Path <$> arbitrary
+  genUnchecked = Path <$> genFilePath
 
 instance GenValid (Path Rel Dir)
 
+-- | Generates 'FilePath's with a high occurence of @'.'@, @'\/'@ and
+-- @'\\'@ characters. The resulting 'FilePath's are not guaranteed to
+-- be valid.
+genFilePath :: Gen FilePath
+genFilePath = listOf genPathyChar
+
+genPathyChar :: Gen Char
+genPathyChar = frequency [(2, arbitrary), (1, elements "./\\")]
+
+shrinkValidAbsFile :: Path Abs File -> [Path Abs File]
+shrinkValidAbsFile = shrinkValidWith parseAbsFile
+
+shrinkValidAbsDir :: Path Abs Dir -> [Path Abs Dir]
+shrinkValidAbsDir = shrinkValidWith parseAbsDir
+
+shrinkValidRelFile :: Path Rel File -> [Path Rel File]
+shrinkValidRelFile = shrinkValidWith parseRelFile
+
+shrinkValidRelDir :: Path Rel Dir -> [Path Rel Dir]
+shrinkValidRelDir = shrinkValidWith parseRelDir
+
+shrinkValidWith :: (FilePath -> Maybe (Path a b)) -> Path a b -> [Path a b]
+shrinkValidWith fun (Path s) = mapMaybe fun $ shrink s
diff --git a/test/Posix.hs b/test/Posix.hs
new file mode 100644
--- /dev/null
+++ b/test/Posix.hs
@@ -0,0 +1,291 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE QuasiQuotes #-}
+
+-- | Test suite.
+
+module Posix (spec) where
+
+import Control.Applicative
+import Control.Monad
+import Data.Aeson
+import qualified Data.ByteString.Lazy.Char8 as LBS
+import Data.Maybe
+import Path
+import Path.Internal
+import Test.Hspec
+
+-- | Test suite (Posix version).
+spec :: Spec
+spec =
+  do describe "Parsing: Path Abs Dir" parseAbsDirSpec
+     describe "Parsing: Path Rel Dir" parseRelDirSpec
+     describe "Parsing: Path Abs File" parseAbsFileSpec
+     describe "Parsing: Path Rel File" parseRelFileSpec
+     describe "Operations: (</>)" operationAppend
+     describe "Operations: stripDir" operationStripDir
+     describe "Operations: isParentOf" operationIsParentOf
+     describe "Operations: parent" operationParent
+     describe "Operations: filename" operationFilename
+     describe "Operations: dirname" operationDirname
+     describe "Restrictions" restrictions
+     describe "Aeson Instances" aesonInstances
+     describe "QuasiQuotes" quasiquotes
+
+-- | Restricting the input of any tricks.
+restrictions :: Spec
+restrictions =
+  do -- These ~ related ones below are now lifted:
+     -- https://github.com/chrisdone/path/issues/19
+     parseSucceeds "~/" (Path "~/")
+     parseSucceeds "~/foo" (Path "~/foo/")
+     parseSucceeds "~/foo/bar" (Path "~/foo/bar/")
+     parseSucceeds "a.." (Path "a../")
+     parseSucceeds "..a" (Path "..a/")
+     --
+     parseFails "../"
+     parseFails ".."
+     parseFails "."
+     parseFails "/.."
+     parseFails "/foo/../bar/"
+     parseFails "/foo/bar/.."
+  where parseFails x =
+          it (show x ++ " should be rejected")
+             (isNothing (void (parseAbsDir x) <|>
+                         void (parseRelDir x) <|>
+                         void (parseAbsFile x) <|>
+                         void (parseRelFile x)))
+        parseSucceeds x with =
+          parserTest parseRelDir x (Just with)
+
+-- | The 'dirname' operation.
+operationDirname :: Spec
+operationDirname = do
+  it
+    "dirname ($(mkAbsDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
+    (dirname ($(mkAbsDir "/home/chris/") </> $(mkRelDir "bar")) ==
+     dirname $(mkRelDir "bar"))
+  it
+    "dirname ($(mkRelDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
+    (dirname ($(mkRelDir "home/chris/") </> $(mkRelDir "bar")) ==
+     dirname $(mkRelDir "bar"))
+
+-- | The 'filename' operation.
+operationFilename :: Spec
+operationFilename =
+  do it "filename ($(mkAbsDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
+          (filename ($(mkAbsDir "/home/chris/") </>
+                             $(mkRelFile "bar.txt")) ==
+                                      filename $(mkRelFile "bar.txt"))
+
+     it "filename ($(mkRelDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
+             (filename ($(mkRelDir "home/chris/") </>
+                                $(mkRelFile "bar.txt")) ==
+                                         filename $(mkRelFile "bar.txt"))
+
+-- | The 'parent' operation.
+operationParent :: Spec
+operationParent =
+  do it "parent (parent </> child) == parent"
+        (parent ($(mkAbsDir "/foo") </>
+                    $(mkRelDir "bar")) ==
+         $(mkAbsDir "/foo"))
+     it "parent \"\" == \"\""
+        (parent $(mkAbsDir "/") ==
+         $(mkAbsDir "/"))
+     it "parent (parent \"\") == \"\""
+        (parent (parent $(mkAbsDir "/")) ==
+         $(mkAbsDir "/"))
+
+-- | The 'isParentOf' operation.
+operationIsParentOf :: Spec
+operationIsParentOf =
+  do it "isParentOf parent (parent </> child) (unit test)"
+        (isParentOf
+           $(mkAbsDir "///bar/")
+           ($(mkAbsDir "///bar/") </>
+            $(mkRelFile "bar/foo.txt")))
+
+     it "isParentOf parent (parent </> child) (unit test)"
+        (isParentOf
+           $(mkRelDir "bar/")
+           ($(mkRelDir "bar/") </>
+            $(mkRelFile "bob/foo.txt")))
+
+-- | The 'stripDir' operation.
+operationStripDir :: Spec
+operationStripDir =
+  do it "stripDir parent (parent </> child) = child (unit test)"
+        (stripDir $(mkAbsDir "///bar/")
+                  ($(mkAbsDir "///bar/") </>
+                   $(mkRelFile "bar/foo.txt")) ==
+         Just $(mkRelFile "bar/foo.txt"))
+
+     it "stripDir parent (parent </> child) = child (unit test)"
+        (stripDir $(mkRelDir "bar/")
+                  ($(mkRelDir "bar/") </>
+                   $(mkRelFile "bob/foo.txt")) ==
+         Just $(mkRelFile "bob/foo.txt"))
+
+     it "stripDir parent parent = _|_"
+        (stripDir $(mkAbsDir "/home/chris/foo")
+                  $(mkAbsDir "/home/chris/foo") ==
+         Nothing)
+
+-- | The '</>' operation.
+operationAppend :: Spec
+operationAppend =
+  do it "AbsDir + RelDir = AbsDir"
+        ($(mkAbsDir "/home/") </>
+         $(mkRelDir "chris") ==
+         $(mkAbsDir "/home/chris/"))
+     it "AbsDir + RelFile = AbsFile"
+        ($(mkAbsDir "/home/") </>
+         $(mkRelFile "chris/test.txt") ==
+         $(mkAbsFile "/home/chris/test.txt"))
+     it "RelDir + RelDir = RelDir"
+        ($(mkRelDir "home/") </>
+         $(mkRelDir "chris") ==
+         $(mkRelDir "home/chris"))
+     it "RelDir + RelFile = RelFile"
+        ($(mkRelDir "home/") </>
+         $(mkRelFile "chris/test.txt") ==
+         $(mkRelFile "home/chris/test.txt"))
+
+-- | Tests for the tokenizer.
+parseAbsDirSpec :: Spec
+parseAbsDirSpec =
+  do failing ""
+     failing "./"
+     failing "foo.txt"
+     succeeding "/" (Path "/")
+     succeeding "//" (Path "/")
+     succeeding "///foo//bar//mu/" (Path "/foo/bar/mu/")
+     succeeding "///foo//bar////mu" (Path "/foo/bar/mu/")
+     succeeding "///foo//bar/.//mu" (Path "/foo/bar/mu/")
+
+  where failing x = parserTest parseAbsDir x Nothing
+        succeeding x with = parserTest parseAbsDir x (Just with)
+
+-- | Tests for the tokenizer.
+parseRelDirSpec :: Spec
+parseRelDirSpec =
+  do failing ""
+     failing "/"
+     failing "//"
+     succeeding "~/" (Path "~/") -- https://github.com/chrisdone/path/issues/19
+     failing "/"
+     failing "./"
+     failing "././"
+     failing "//"
+     failing "///foo//bar//mu/"
+     failing "///foo//bar////mu"
+     failing "///foo//bar/.//mu"
+     succeeding "..." (Path ".../")
+     succeeding "foo.bak" (Path "foo.bak/")
+     succeeding "./foo" (Path "foo/")
+     succeeding "././foo" (Path "foo/")
+     succeeding "./foo/./bar" (Path "foo/bar/")
+     succeeding "foo//bar//mu//" (Path "foo/bar/mu/")
+     succeeding "foo//bar////mu" (Path "foo/bar/mu/")
+     succeeding "foo//bar/.//mu" (Path "foo/bar/mu/")
+
+  where failing x = parserTest parseRelDir x Nothing
+        succeeding x with = parserTest parseRelDir x (Just with)
+
+-- | Tests for the tokenizer.
+parseAbsFileSpec :: Spec
+parseAbsFileSpec =
+  do failing ""
+     failing "./"
+     failing "/."
+     failing "/foo/bar/."
+     failing "~/"
+     failing "./foo.txt"
+     failing "/"
+     failing "//"
+     failing "///foo//bar//mu/"
+     succeeding "/..." (Path "/...")
+     succeeding "/foo.txt" (Path "/foo.txt")
+     succeeding "///foo//bar////mu.txt" (Path "/foo/bar/mu.txt")
+     succeeding "///foo//bar/.//mu.txt" (Path "/foo/bar/mu.txt")
+
+  where failing x = parserTest parseAbsFile x Nothing
+        succeeding x with = parserTest parseAbsFile x (Just with)
+
+-- | Tests for the tokenizer.
+parseRelFileSpec :: Spec
+parseRelFileSpec =
+  do failing ""
+     failing "/"
+     failing "//"
+     failing "~/"
+     failing "/"
+     failing "./"
+     failing "a/."
+     failing "a/../b"
+     failing "a/.."
+     failing "../foo.txt"
+     failing "//"
+     failing "///foo//bar//mu/"
+     failing "///foo//bar////mu"
+     failing "///foo//bar/.//mu"
+     succeeding "a.." (Path "a..")
+     succeeding "..." (Path "...")
+     succeeding "foo.txt" (Path "foo.txt")
+     succeeding "./foo.txt" (Path "foo.txt")
+     succeeding "././foo.txt" (Path "foo.txt")
+     succeeding "./foo/./bar.txt" (Path "foo/bar.txt")
+     succeeding "foo//bar//mu.txt" (Path "foo/bar/mu.txt")
+     succeeding "foo//bar////mu.txt" (Path "foo/bar/mu.txt")
+     succeeding "foo//bar/.//mu.txt" (Path "foo/bar/mu.txt")
+
+  where failing x = parserTest parseRelFile x Nothing
+        succeeding x with = parserTest parseRelFile x (Just with)
+
+-- | Parser test.
+parserTest :: (Show a1,Show a,Eq a1)
+           => (a -> Maybe a1) -> a -> Maybe a1 -> SpecWith ()
+parserTest parser input expected =
+  it ((case expected of
+         Nothing -> "Failing: "
+         Just{} -> "Succeeding: ") ++
+      "Parsing " ++
+      show input ++
+      " " ++
+      case expected of
+        Nothing -> "should fail."
+        Just x -> "should succeed with: " ++ show x)
+     (actual `shouldBe` expected)
+  where actual = parser input
+
+-- | Tests for the 'ToJSON' and 'FromJSON' instances
+--
+-- Can't use overloaded strings due to some weird issue with bytestring-0.9.2.1 / ghc-7.4.2:
+-- https://travis-ci.org/sjakobi/path/jobs/138399072#L989
+aesonInstances :: Spec
+aesonInstances =
+  do it "Decoding \"[\"/foo/bar\"]\" as a [Path Abs Dir] should succeed." $
+       eitherDecode (LBS.pack "[\"/foo/bar\"]") `shouldBe` Right [Path "/foo/bar/" :: Path Abs Dir]
+     it "Decoding \"[\"/foo/bar\"]\" as a [Path Rel Dir] should fail." $
+       decode (LBS.pack "[\"/foo/bar\"]") `shouldBe` (Nothing :: Maybe [Path Rel Dir])
+     it "Encoding \"[\"/foo/bar/mu.txt\"]\" should succeed." $
+       encode [Path "/foo/bar/mu.txt" :: Path Abs File] `shouldBe` (LBS.pack "[\"/foo/bar/mu.txt\"]")
+
+-- | Test QuasiQuoters. Make sure they work the same as the $(mk*) constructors.
+quasiquotes :: Spec
+quasiquotes =
+  do it "[absdir|/|] == $(mkAbsDir \"/\")"
+       ([absdir|/|] `shouldBe` $(mkAbsDir "/"))
+     it "[absdir|/home|] == $(mkAbsDir \"/home\")"
+       ([absdir|/home|] `shouldBe` $(mkAbsDir "/home"))
+     it "[reldir|foo|] == $(mkRelDir \"foo\")"
+       ([reldir|foo|] `shouldBe` $(mkRelDir "foo"))
+     it "[reldir|foo/bar|] == $(mkRelDir \"foo/bar\")"
+       ([reldir|foo/bar|] `shouldBe` $(mkRelDir "foo/bar"))
+     it "[absfile|/home/chris/foo.txt|] == $(mkAbsFile \"/home/chris/foo.txt\")"
+       ([absfile|/home/chris/foo.txt|] `shouldBe` $(mkAbsFile "/home/chris/foo.txt"))
+     it "[relfile|foo|] == $(mkRelFile \"foo\")"
+       ([relfile|foo|] `shouldBe` $(mkRelFile "foo"))
+     it "[relfile|chris/foo.txt|] == $(mkRelFile \"chris/foo.txt\")"
+       ([relfile|chris/foo.txt|] `shouldBe` $(mkRelFile "chris/foo.txt"))
diff --git a/test/ValidityTest.hs b/test/ValidityTest.hs
--- a/test/ValidityTest.hs
+++ b/test/ValidityTest.hs
@@ -17,7 +17,7 @@
 import Test.QuickCheck
 import Test.Validity
 
-import Path.Gen ()
+import Path.Gen
 
 -- | Test suite entry point, returns exit failure if any test fails.
 main :: IO ()
@@ -25,11 +25,11 @@
 
 -- | Test suite.
 spec :: Spec
-spec = do
-     describe "Parsing: Path Abs Dir" parseAbsDirSpec
-     describe "Parsing: Path Rel Dir" parseRelDirSpec
-     describe "Parsing: Path Abs File" parseAbsFileSpec
-     describe "Parsing: Path Rel File" parseRelFileSpec
+spec = parallel $ do
+     describe "Parsing: Path Abs Dir" (parserSpec parseAbsDir)
+     describe "Parsing: Path Rel Dir" (parserSpec parseRelDir)
+     describe "Parsing: Path Abs File" (parserSpec parseAbsFile)
+     describe "Parsing: Path Rel File" (parserSpec parseRelFile)
      describe "Operations: (</>)" operationAppend
      describe "Operations: stripDir" operationStripDir
      describe "Operations: isParentOf" operationIsParentOf
@@ -40,13 +40,13 @@
 operationFilename :: Spec
 operationFilename = do
      it "filename ($(mkAbsDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename)" $
-         forAll genValid $ \(parent :: Path Abs Dir) ->
-             forAll genValid $ \file ->
+         forAllShrink genValid shrinkValidAbsDir $ \parent ->
+             forAllShrink genValid shrinkValidRelFile $ \file ->
                  filename (parent </> file) `shouldBe` filename file
 
      it "filename ($(mkRelDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename)" $
-         forAll genValid $ \(parent :: Path Rel Dir) ->
-             forAll genValid $ \file ->
+         forAllShrink genValid shrinkValidRelDir $ \parent ->
+             forAllShrink genValid shrinkValidRelFile $ \file ->
                  filename (parent </> file) `shouldBe` filename file
 
      it "produces a valid path on when passed a valid absolute path" $ do
@@ -68,48 +68,48 @@
 operationIsParentOf :: Spec
 operationIsParentOf = do
      it "isParentOf parent (parent </> child)" $
-        forAll genValid $ \(parent :: Path Abs Dir) ->
-            forAll genValid $ \(child :: Path Rel File) ->
+        forAllShrink genValid shrinkValidAbsDir $ \parent ->
+            forAllShrink genValid shrinkValidRelFile $ \child ->
                 isParentOf parent (parent </> child)
 
      it "isParentOf parent (parent </> child)" $
-        forAll genValid $ \(parent :: Path Abs Dir) ->
-            forAll genValid $ \(child :: Path Rel Dir) ->
+        forAllShrink genValid shrinkValidAbsDir $ \parent ->
+            forAllShrink genValid shrinkValidRelDir $ \child ->
                 isParentOf parent (parent </> child)
 
      it "isParentOf parent (parent </> child)" $
-        forAll genValid $ \(parent :: Path Rel Dir) ->
-            forAll genValid $ \(child :: Path Rel File) ->
+        forAllShrink genValid shrinkValidRelDir $ \parent ->
+            forAllShrink genValid shrinkValidRelFile $ \child ->
                 isParentOf parent (parent </> child)
 
      it "isParentOf parent (parent </> child)" $
-        forAll genValid $ \(parent :: Path Rel Dir) ->
-            forAll genValid $ \(child :: Path Rel Dir) ->
+        forAllShrink genValid shrinkValidRelDir $ \parent ->
+            forAllShrink genValid shrinkValidRelDir $ \child ->
                 isParentOf parent (parent </> child)
 
 -- | The 'stripDir' operation.
 operationStripDir :: Spec
 operationStripDir = do
      it "stripDir parent (parent </> child) = child" $
-        forAll genValid $ \(parent :: Path Abs Dir) ->
-            forAll genValid $ \(child :: Path Rel File) ->
+        forAllShrink genValid shrinkValidAbsDir $ \parent ->
+            forAllShrink genValid shrinkValidRelFile $ \child ->
                 stripDir parent (parent </> child) == Just child
 
      it "stripDir parent (parent </> child) = child" $
-        forAll genValid $ \(parent :: Path Rel Dir) ->
-            forAll genValid $ \(child :: Path Rel File) ->
+        forAllShrink genValid shrinkValidRelDir $ \parent ->
+            forAllShrink genValid shrinkValidRelFile $ \child ->
                 stripDir parent (parent </> child) == Just child
 
      it "stripDir parent (parent </> child) = child" $
-        forAll genValid $ \(parent :: Path Abs Dir) ->
-            forAll genValid $ \(child :: Path Rel Dir) ->
+        forAllShrink genValid shrinkValidAbsDir $ \parent ->
+            forAllShrink genValid shrinkValidRelDir $ \child ->
                 stripDir parent (parent </> child) == Just child
 
      it "stripDir parent (parent </> child) = child" $
-        forAll genValid $ \(parent :: Path Rel Dir) ->
-            forAll genValid $ \(child :: Path Rel Dir) ->
+        forAllShrink genValid shrinkValidRelDir $ \parent ->
+            forAllShrink genValid shrinkValidRelDir $ \child ->
                 stripDir parent (parent </> child) == Just child
-        
+
      it "produces a valid path on when passed a valid absolute file paths" $ do
         producesValidsOnValids2 (stripDir @Maybe @Abs @File)
 
@@ -137,27 +137,7 @@
      it "produces a valid path on when creating valid relative directory paths" $ do
         producesValidsOnValids2 ((</>) @Rel @Dir)
 
-
-parseAbsDirSpec :: Spec
-parseAbsDirSpec = do
-     it "Produces valid paths when it succeeds" $
-       validIfSucceedsOnArbitrary
-         (parseAbsDir @Maybe)
-
-parseRelDirSpec :: Spec
-parseRelDirSpec = do
-     it "Produces valid paths when it succeeds" $
-       validIfSucceedsOnArbitrary
-         (parseRelDir @Maybe)
-
-parseAbsFileSpec :: Spec
-parseAbsFileSpec = do
-     it "Produces valid paths when it succeeds" $
-       validIfSucceedsOnArbitrary
-         (parseAbsFile @Maybe)
-
-parseRelFileSpec :: Spec
-parseRelFileSpec = do
+parserSpec :: (Show p, Validity p) => (FilePath -> Maybe p) -> Spec
+parserSpec parser =
      it "Produces valid paths when it succeeds" $
-       validIfSucceedsOnArbitrary
-         (parseRelFile @Maybe)
+       validIfSucceedsOnGen parser genFilePath
diff --git a/test/Windows.hs b/test/Windows.hs
new file mode 100644
--- /dev/null
+++ b/test/Windows.hs
@@ -0,0 +1,285 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE QuasiQuotes #-}
+
+-- | Test suite.
+
+module Windows (spec) where
+
+import Control.Applicative
+import Control.Monad
+import Data.Aeson
+import qualified Data.ByteString.Lazy.Char8 as LBS
+import Data.Maybe
+import Path
+import Path.Internal
+import Test.Hspec
+
+-- | Test suite (Windows version).
+spec :: Spec
+spec =
+  do describe "Parsing: Path Abs Dir" parseAbsDirSpec
+     describe "Parsing: Path Rel Dir" parseRelDirSpec
+     describe "Parsing: Path Abs File" parseAbsFileSpec
+     describe "Parsing: Path Rel File" parseRelFileSpec
+     describe "Operations: (</>)" operationAppend
+     describe "Operations: stripDir" operationStripDir
+     describe "Operations: isParentOf" operationIsParentOf
+     describe "Operations: parent" operationParent
+     describe "Operations: filename" operationFilename
+     describe "Operations: dirname" operationDirname
+     describe "Restrictions" restrictions
+     describe "Aeson Instances" aesonInstances
+     describe "QuasiQuotes" quasiquotes
+
+-- | Restricting the input of any tricks.
+restrictions :: Spec
+restrictions =
+  do parseFails "..\\"
+     parseFails ".."
+     parseFails "."
+     parseSucceeds "a.." (Path "a..\\")
+     parseSucceeds "..a" (Path "..a\\")
+     parseFails "\\.."
+     parseFails "C:\\foo\\..\\bar\\"
+     parseFails "C:\\foo\\bar\\.."
+  where parseFails x =
+          it (show x ++ " should be rejected")
+             (isNothing (void (parseAbsDir x) <|>
+                         void (parseRelDir x) <|>
+                         void (parseAbsFile x) <|>
+                         void (parseRelFile x)))
+        parseSucceeds x with =
+          parserTest parseRelDir x (Just with)
+
+-- | The 'dirname' operation.
+operationDirname :: Spec
+operationDirname = do
+  it
+    "dirname ($(mkAbsDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
+    (dirname ($(mkAbsDir "C:\\chris\\") </> $(mkRelDir "bar")) ==
+     dirname $(mkRelDir "bar"))
+  it
+    "dirname ($(mkRelDir parent) </> $(mkRelFile dirname)) == dirname $(mkRelFile dirname) (unit test)"
+    (dirname ($(mkRelDir "home\\chris\\") </> $(mkRelDir "bar")) ==
+     dirname $(mkRelDir "bar"))
+
+-- | The 'filename' operation.
+operationFilename :: Spec
+operationFilename =
+  do it "filename ($(mkAbsDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
+          (filename ($(mkAbsDir "C:\\chris\\") </>
+                             $(mkRelFile "bar.txt")) ==
+                                      filename $(mkRelFile "bar.txt"))
+
+     it "filename ($(mkRelDir parent) </> $(mkRelFile filename)) == filename $(mkRelFile filename) (unit test)"
+             (filename ($(mkRelDir "home\\chris\\") </>
+                                $(mkRelFile "bar.txt")) ==
+                                         filename $(mkRelFile "bar.txt"))
+
+-- | The 'parent' operation.
+operationParent :: Spec
+operationParent =
+  do it "parent (parent </> child) == parent"
+        (parent ($(mkAbsDir "C:\\foo") </>
+                    $(mkRelDir "bar")) ==
+         $(mkAbsDir "C:\\foo"))
+     it "parent \"\" == \"\""
+        (parent $(mkAbsDir "C:\\") ==
+         $(mkAbsDir "C:\\"))
+     it "parent (parent \"\") == \"\""
+        (parent (parent $(mkAbsDir "C:\\")) ==
+         $(mkAbsDir "C:\\"))
+
+-- | The 'isParentOf' operation.
+operationIsParentOf :: Spec
+operationIsParentOf =
+  do it "isParentOf parent (parent </> child) (unit test)"
+        (isParentOf
+           $(mkAbsDir "C:\\\\\\bar\\")
+           ($(mkAbsDir "C:\\\\\\bar\\") </>
+            $(mkRelFile "bar\\foo.txt")))
+
+     it "isParentOf parent (parent </> child) (unit test)"
+        (isParentOf
+           $(mkRelDir "bar\\")
+           ($(mkRelDir "bar\\") </>
+            $(mkRelFile "bob\\foo.txt")))
+
+-- | The 'stripDir' operation.
+operationStripDir :: Spec
+operationStripDir =
+  do it "stripDir parent (parent </> child) = child (unit test)"
+        (stripDir $(mkAbsDir "C:\\\\\\bar\\")
+                  ($(mkAbsDir "C:\\\\\\bar\\") </>
+                   $(mkRelFile "bar\\foo.txt")) ==
+         Just $(mkRelFile "bar\\foo.txt"))
+
+     it "stripDir parent (parent </> child) = child (unit test)"
+        (stripDir $(mkRelDir "bar\\")
+                  ($(mkRelDir "bar\\") </>
+                   $(mkRelFile "bob\\foo.txt")) ==
+         Just $(mkRelFile "bob\\foo.txt"))
+
+     it "stripDir parent parent = _|_"
+        (stripDir $(mkAbsDir "C:\\home\\chris\\foo")
+                  $(mkAbsDir "C:\\home\\chris\\foo") ==
+         Nothing)
+
+-- | The '</>' operation.
+operationAppend :: Spec
+operationAppend =
+  do it "AbsDir + RelDir = AbsDir"
+        ($(mkAbsDir "C:\\home\\") </>
+         $(mkRelDir "chris") ==
+         $(mkAbsDir "C:\\home\\chris\\"))
+     it "AbsDir + RelFile = AbsFile"
+        ($(mkAbsDir "C:\\home\\") </>
+         $(mkRelFile "chris\\test.txt") ==
+         $(mkAbsFile "C:\\home\\chris\\test.txt"))
+     it "RelDir + RelDir = RelDir"
+        ($(mkRelDir "home\\") </>
+         $(mkRelDir "chris") ==
+         $(mkRelDir "home\\chris"))
+     it "RelDir + RelFile = RelFile"
+        ($(mkRelDir "home\\") </>
+         $(mkRelFile "chris\\test.txt") ==
+         $(mkRelFile "home\\chris\\test.txt"))
+
+-- | Tests for the tokenizer.
+parseAbsDirSpec :: Spec
+parseAbsDirSpec =
+  do failing ""
+     failing ".\\"
+     failing "foo.txt"
+     succeeding "C:\\" (Path "C:\\")
+     succeeding "C:\\\\" (Path "C:\\\\")
+     -- succeeding "C:\\\\\\foo\\\\bar\\\\mu\\" (Path "C:\\foo\\bar\\mu\\") FIXME
+     -- succeeding "C:\\\\\\foo\\\\bar\\\\mu" (Path "C:\\foo\\bar\\mu\\") FIXME
+     -- succeeding "C:\\\\\\foo\\\\bar\\.\\\\mu" (Path "C:\\foo\\bar\\mu\\") FIXME
+
+  where failing x = parserTest parseAbsDir x Nothing
+        succeeding x with = parserTest parseAbsDir x (Just with)
+
+-- | Tests for the tokenizer.
+parseRelDirSpec :: Spec
+parseRelDirSpec =
+  do failing ""
+     -- failing "/" FIXME
+     -- failing "//" FIXME
+     -- succeeding "~/" (Path "~/") -- https://github.com/chrisdone/path/issues/19
+     -- failing "\\" FIXME
+     failing ".\\"
+     failing ".\\.\\"
+     failing "\\\\"
+     failing "\\\\\\foo\\\\bar\\\\mu\\"
+     failing "\\\\\\foo\\\\bar\\\\\\\\mu"
+     failing "\\\\\\foo\\\\bar\\.\\\\mu"
+     succeeding "..." (Path "...\\")
+     succeeding "foo.bak" (Path "foo.bak\\")
+     succeeding ".\\foo" (Path "foo\\")
+     succeeding ".\\.\\foo" (Path "foo\\")
+     succeeding ".\\foo\\.\\bar" (Path "foo\\bar\\")
+     succeeding "foo\\\\bar\\\\mu\\\\" (Path "foo\\bar\\mu\\")
+     succeeding "foo\\\\bar////mu" (Path "foo\\bar\\mu\\")
+     succeeding "foo\\\\bar\\.\\\\mu" (Path "foo\\bar\\mu\\")
+
+  where failing x = parserTest parseRelDir x Nothing
+        succeeding x with = parserTest parseRelDir x (Just with)
+
+-- | Tests for the tokenizer.
+parseAbsFileSpec :: Spec
+parseAbsFileSpec =
+  do failing ""
+     failing ".\\"
+     failing "\\."
+     failing "\\foo\\bar\\."
+     failing "~\\"
+     failing ".\\foo.txt"
+     failing "\\"
+     failing "\\\\"
+     failing "\\\\\\foo\\\\bar\\\\mu\\"
+     -- succeeding "\\..." (Path "\\...") FIXME
+     -- succeeding "\\foo.txt" (Path "\\foo.txt") FIXME
+     -- succeeding "C:\\\\\\foo\\\\bar\\\\\\\\mu.txt" (Path "C:\\foo\\bar\\mu.txt") FIXME
+     -- succeeding "C:\\\\\\foo\\\\bar\\.\\\\mu.txt" (Path "C:\\foo\\bar\\mu.txt") FIXME
+
+  where failing x = parserTest parseAbsFile x Nothing
+        succeeding x with = parserTest parseAbsFile x (Just with)
+
+-- | Tests for the tokenizer.
+parseRelFileSpec :: Spec
+parseRelFileSpec =
+  do failing ""
+     failing "\\"
+     failing "\\\\"
+     failing "~\\"
+     failing "\\"
+     failing ".\\"
+     failing "a\\."
+     failing "a\\..\\b"
+     failing "a\\.."
+     failing "..\\foo.txt"
+     failing "\\\\"
+     failing "\\\\\\foo\\\\bar\\\\mu\\"
+     failing "\\\\\\foo\\\\bar\\\\\\\\mu"
+     failing "\\\\\\foo\\\\bar\\.\\\\mu"
+     succeeding "a.." (Path "a..")
+     succeeding "..." (Path "...")
+     succeeding "foo.txt" (Path "foo.txt")
+     succeeding ".\\foo.txt" (Path "foo.txt")
+     succeeding ".\\.\\foo.txt" (Path "foo.txt")
+     succeeding ".\\foo\\.\\bar.txt" (Path "foo\\bar.txt")
+     succeeding "foo\\\\bar\\\\mu.txt" (Path "foo\\bar\\mu.txt")
+     succeeding "foo\\\\bar\\\\\\\\mu.txt" (Path "foo\\bar\\mu.txt")
+     succeeding "foo\\\\bar\\.\\\\mu.txt" (Path "foo\\bar\\mu.txt")
+
+  where failing x = parserTest parseRelFile x Nothing
+        succeeding x with = parserTest parseRelFile x (Just with)
+
+-- | Parser test.
+parserTest :: (Show a1,Show a,Eq a1)
+           => (a -> Maybe a1) -> a -> Maybe a1 -> SpecWith ()
+parserTest parser input expected =
+  it ((case expected of
+         Nothing -> "Failing: "
+         Just{} -> "Succeeding: ") ++
+      "Parsing " ++
+      show input ++
+      " " ++
+      case expected of
+        Nothing -> "should fail."
+        Just x -> "should succeed with: " ++ show x)
+     (actual `shouldBe` expected)
+  where actual = parser input
+
+-- | Tests for the 'ToJSON' and 'FromJSON' instances
+--
+-- Can't use overloaded strings due to some weird issue with bytestring-0.9.2.1 / ghc-7.4.2:
+-- https://travis-ci.org/sjakobi/path/jobs/138399072#L989
+aesonInstances :: Spec
+aesonInstances =
+  do it "Decoding \"[\"C:\\\\foo\\\\bar\"]\" as a [Path Abs Dir] should succeed." $
+       eitherDecode (LBS.pack "[\"C:\\\\foo\\\\bar\"]") `shouldBe` Right [Path "C:\\foo\\bar\\" :: Path Abs Dir]
+     it "Decoding \"[\"C:\\foo\\bar\"]\" as a [Path Rel Dir] should fail." $
+       decode (LBS.pack "[\"C:\\foo\\bar\"]") `shouldBe` (Nothing :: Maybe [Path Rel Dir])
+     it "Encoding \"[\"C:\\foo\\bar\\mu.txt\"]\" should succeed." $
+       encode [Path "C:\\foo\\bar\\mu.txt" :: Path Abs File] `shouldBe` (LBS.pack "[\"C:\\\\foo\\\\bar\\\\mu.txt\"]")
+
+-- | Test QuasiQuoters. Make sure they work the same as the $(mk*) constructors.
+quasiquotes :: Spec
+quasiquotes =
+  do it "[absdir|C:\\|] == $(mkAbsDir \"C:\\\")"
+       ([absdir|C:\|] `shouldBe` $(mkAbsDir "C:\\"))
+     it "[absdir|C:\\chris\\|] == $(mkAbsDir \"C:\\chris\\\")"
+       ([absdir|C:\chris\|] `shouldBe` $(mkAbsDir "C:\\chris\\"))
+     it "[reldir|foo|] == $(mkRelDir \"foo\")"
+       ([reldir|foo|] `shouldBe` $(mkRelDir "foo"))
+     it "[reldir|foo\\bar|] == $(mkRelDir \"foo\\bar\")"
+       ([reldir|foo\bar|] `shouldBe` $(mkRelDir "foo\\bar"))
+     it "[absfile|C:\\chris\\foo.txt|] == $(mkAbsFile \"C:\\chris\\foo.txt\")"
+       ([absfile|C:\chris\foo.txt|] `shouldBe` $(mkAbsFile "C:\\chris\\foo.txt"))
+     it "[relfile|foo.exe|] == $(mkRelFile \"foo.exe\")"
+       ([relfile|foo.exe|] `shouldBe` $(mkRelFile "foo.exe"))
+     it "[relfile|chris\foo.txt|] == $(mkRelFile \"chris\\foo.txt\")"
+       ([relfile|chris\foo.txt|] `shouldBe` $(mkRelFile "chris\\foo.txt"))
