packages feed

filepath 1.3.0.2 → 1.4.0.0

raw patch · 12 files changed

+861/−967 lines, 12 filesdep −randomdep ~QuickCheckdep ~basesetup-changednew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies removed: random

Dependency ranges changed: QuickCheck, base

API changes (from Hackage documentation)

+ System.FilePath.Posix: (-<.>) :: FilePath -> String -> FilePath
+ System.FilePath.Windows: (-<.>) :: FilePath -> String -> FilePath

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright Neil Mitchell 2005-2007.+Copyright Neil Mitchell 2005-2015. All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -1,62 +1,9 @@-System.FilePath  [![Build Status](https://travis-ci.org/ghc/packages-filepath.png?branch=master)](https://travis-ci.org/ghc/packages-filepath)-===============--I have written a `System.FilePath` module in part based on the one in-Yhc, and in part based on the one in Cabal (thanks to Lemmih). The aim-is to try and get this module into the base package, as `FilePath`s-are something many programs use, but its all too easy to hack up a-little function that gets it right most of the time on most platforms,-and there lies a source of bugs.--This module is Posix (Linux) and Windows capable - just import-`System.FilePath` and it will pick the right one. Of course, if you-demand Windows paths on all OSes, then `System.FilePath.Windows` will-give you that (same with Posix). Written in Haskell 98 with-Hierarchical Modules.--If you go to the -[Haddock](http://hackage.haskell.org/package/filepath/docs/System-FilePath.html)-page, there are a few little examples at the top of the re-exported module.---Acknowledgments------------------Thanks to Marc Webber, shapr, David House, Lemmih, others...---Competitors--------------`System.FilePath` from Cabal, by Lemmih `FilePath.hs` and-`NameManip.hs` from MissingH--The one from Cabal and `FilePath.hs` in MissingH are both very-similar, I stole lots of good ideas from those two.--`NameManip.hs` seems to be more unix specific, but all functions in-that module have equivalents in this new `System.FilePath` module.--Hopefully this new module can be used without noticing any lost-functions, and certainly adds new features/functions to the table.---Should `FilePath` be an abstract data type?----------------------------------------------The answer for this library is no. This is a deliberate design decision.+# FilePath [![Hackage version](https://img.shields.io/hackage/v/filepath.svg?style=flat)](https://hackage.haskell.org/package/filepath) [![Build Status](https://img.shields.io/travis/haskell/filepath.svg?style=flat)](https://travis-ci.org/haskell/filepath) -In Haskell 98 the definition is `type FilePath = String`, and all-functions operating on `FilePath`s, i.e. `readFile`/`writeFile` etc-take `FilePath`s. The only way to introduce an abstract type is to-provide wrappers for these functions or casts between `String`s and-`FilePathAbstract`s.+The `filepath` package provides functionality for manipulating `FilePath` values, and is shipped with both [GHC](https://www.haskell.org/ghc/) and the [Haskell Platform](https://www.haskell.org/platform/). It provides three modules: -There are also additional questions as to what constitutes a-`FilePath`, and what is just a pure `String`. For example,-"/path/file.ext" is a `FilePath`. Is "/" ? "/path" ? "path" ?-"file.ext" ? ".ext" ? "file" ?+* [`System.FilePath.Posix`](http://hackage.haskell.org/package/filepath/docs/System-FilePath-Posix.html) manipulates POSIX/Linux style `FilePath` values (with `/` as the path separator).+* [`System.FilePath.Windows`](http://hackage.haskell.org/package/filepath/docs/System-FilePath-Windows.html) manipulates Windows style `FilePath` values (with either `\` or `/` as the path separator, and deals with drives).+* [`System.FilePath`](http://hackage.haskell.org/package/filepath/docs/System-FilePath.html) is an alias for the module appropriate to your platform. -With that being accepted, it should be trivial to write-`System.FilePath.ByteString` which has the same interface as-`System.FilePath` yet operates on `ByteString`s.+All three modules provide the same API, and the same documentation (calling out differences in the different variants).
Setup.hs view
@@ -1,6 +1,2 @@-module Main (main) where- import Distribution.Simple--main :: IO () main = defaultMain
System/FilePath.hs view
@@ -4,10 +4,10 @@ #endif {- | Module      :  System.FilePath-Copyright   :  (c) Neil Mitchell 2005-2007+Copyright   :  (c) Neil Mitchell 2005-2014 License     :  BSD3 -Maintainer  :  libraries@haskell.org+Maintainer  :  ndmitchell@gmail.com Stability   :  stable Portability :  portable @@ -19,6 +19,7 @@ functions. -} + #if defined(mingw32_HOST_OS) || defined(__MINGW32__) module System.FilePath(module System.FilePath.Windows) where import System.FilePath.Windows@@ -26,4 +27,3 @@ module System.FilePath(module System.FilePath.Posix) where import System.FilePath.Posix #endif-
System/FilePath/Internal.hs view
@@ -1,6 +1,7 @@ #if __GLASGOW_HASKELL__ >= 704 {-# LANGUAGE Safe #-} #endif+{-# LANGUAGE PatternGuards #-}  -- This template expects CPP definitions for: --     MODULE_NAME = Posix | Windows@@ -8,39 +9,58 @@  -- | -- Module      :  System.FilePath.MODULE_NAME--- Copyright   :  (c) Neil Mitchell 2005-2007+-- Copyright   :  (c) Neil Mitchell 2005-2014 -- License     :  BSD3 ----- Maintainer  :  libraries@haskell.org+-- Maintainer  :  ndmitchell@gmail.com -- Stability   :  stable -- Portability :  portable ----- A library for FilePath manipulations, using MODULE_NAME style paths on+-- A library for 'FilePath' manipulations, using MODULE_NAME style paths on -- all platforms. Importing "System.FilePath" is usually better. ----- Some short examples:+-- Given the eample 'FilePath': @\/directory\/file.ext@ ----- You are given a C file, you want to figure out the corresponding object (.o) file:+-- We can use the following functions to extract pieces. ----- @'replaceExtension' file \"o\"@+-- * 'takeFileName' gives @\"file.ext\"@ ----- Haskell module Main imports Test, you have the file named main:+-- * 'takeDirectory' gives @\"\/directory\"@ --+-- * 'takeExtension' gives @\".ext\"@+--+-- * 'dropExtension' gives @\"\/directory\/file\"@+--+-- * 'takeBaseName' gives @\"file\"@+--+-- And we could have built an equivalent path with the following expressions:+--+-- * @\"\/directory\" '</>' \"file.ext\"@.+--+-- * @\"\/directory\/file" '<.>' \"ext\"@.+--+-- * @\"\/directory\/file.txt" '-<.>' \"ext\"@.+--+-- Each function in this module is documented with several examples,+-- which are also used as tests.+--+-- Here are a few examples of using the @filepath@ functions together:+--+-- /Example 1:/ Find the possible locations of a Haskell module @Test@ imported from module @Main@:+-- -- @['replaceFileName' path_to_main \"Test\" '<.>' ext | ext <- [\"hs\",\"lhs\"] ]@ ----- You want to download a file from the web and save it to disk:+-- /Example 2:/ Download a file from @url@ and save it to disk: -- -- @do let file = 'makeValid' url---    System.IO.createDirectoryIfMissing True ('takeDirectory' file)@+--   System.IO.createDirectoryIfMissing True ('takeDirectory' file)@ ----- You want to compile a Haskell file, but put the hi file under \"interface\"+-- /Example 3:/ Compile a Haskell file, putting the @.hi@ file under @interface@: ----- @'takeDirectory' file '</>' \"interface\" '</>' ('takeFileName' file \`replaceExtension\` \"hi\"@)+-- @'takeDirectory' file '</>' \"interface\" '</>' ('takeFileName' file '-<.>' \"hi\")@ ----- The examples in code format descibed by each function are used to generate--- tests, and should give clear semantics for the functions.-------------------------------------------------------------------------------+-- References:+-- [1] <http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx Naming Files, Paths and Namespaces> (Microsoft MSDN) module System.FilePath.MODULE_NAME     (     -- * Separator predicates@@ -49,19 +69,15 @@     searchPathSeparator, isSearchPathSeparator,     extSeparator, isExtSeparator, -    -- * Path methods (environment $PATH)+    -- * @$PATH@ methods     splitSearchPath, getSearchPath, -    -- * Extension methods+    -- * Extension functions     splitExtension,-    takeExtension, replaceExtension, dropExtension, addExtension, hasExtension, (<.>),+    takeExtension, replaceExtension, (-<.>), dropExtension, addExtension, hasExtension, (<.>),     splitExtensions, dropExtensions, takeExtensions, -    -- * Drive methods-    splitDrive, joinDrive,-    takeDrive, hasDrive, dropDrive, isDrive,--    -- * Operations on a FilePath, as a list of directories+    -- * Filename\/directory functions     splitFileName,     takeFileName, replaceFileName, dropFileName,     takeBaseName, replaceBaseName,@@ -69,32 +85,30 @@     combine, (</>),     splitPath, joinPath, splitDirectories, -    -- * Low level FilePath operators+    -- * Drive functions+    splitDrive, joinDrive,+    takeDrive, hasDrive, dropDrive, isDrive,++    -- * Trailing slash functions     hasTrailingPathSeparator,     addTrailingPathSeparator,     dropTrailingPathSeparator, -    -- * File name manipulators+    -- * File name manipulations     normalise, equalFilePath,     makeRelative,     isRelative, isAbsolute,     isValid, makeValid--#ifdef TESTING-    , isRelativeDrive-#endif-     )     where  import Data.Char(toLower, toUpper, isAsciiLower, isAsciiUpper)-import Data.Maybe(isJust, fromJust)-import Data.List(isPrefixOf)+import Data.Maybe(isJust)  import System.Environment(getEnv)  -infixr 7  <.>+infixr 7  <.>, -<.> infixr 5  </>  @@ -138,7 +152,9 @@ -- -- > isPathSeparator a == (a `elem` pathSeparators) isPathSeparator :: Char -> Bool-isPathSeparator = (`elem` pathSeparators)+isPathSeparator '/' = True+isPathSeparator '\\' = isWindows+isPathSeparator _ = False   -- | The character that is used to separate the entries in the $PATH environment variable.@@ -168,8 +184,6 @@ isExtSeparator = (== extSeparator)  -- --------------------------------------------------------------------- -- Path methods (environment $PATH) @@ -182,6 +196,7 @@ -- > Posix:   splitSearchPath "File1::File2:File3" == ["File1",".","File2","File3"] -- > Windows: splitSearchPath "File1;File2;File3"  == ["File1","File2","File3"] -- > Windows: splitSearchPath "File1;;File2;File3" == ["File1","File2","File3"]+-- > Windows: splitSearchPath "File1;\"File2\";File3" == ["File1","File2","File3"] splitSearchPath :: String -> [FilePath] splitSearchPath = f     where@@ -190,10 +205,11 @@            (pre, _:post) -> g pre ++ f post      g "" = ["." | isPosix]+    g ('\"':x@(_:_)) | isWindows && last x == '\"' = [init x]     g x = [x]  --- | Get a list of filepaths in the $PATH.+-- | Get a list of 'FilePath's in the $PATH variable. getSearchPath :: IO [FilePath] getSearchPath = fmap splitSearchPath (getEnv "PATH") @@ -203,8 +219,9 @@  -- | Split on the extension. 'addExtension' is the inverse. --+-- > splitExtension "/directory/path.ext" == ("/directory/path",".ext") -- > uncurry (++) (splitExtension x) == x--- > uncurry addExtension (splitExtension x) == x+-- > Valid x => uncurry addExtension (splitExtension x) == x -- > splitExtension "file.txt" == ("file",".txt") -- > splitExtension "file" == ("file","") -- > splitExtension "file/file.txt" == ("file/file",".txt")@@ -213,44 +230,60 @@ -- > splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred") -- > splitExtension "file/path.txt/" == ("file/path.txt/","") splitExtension :: FilePath -> (String, String)-splitExtension x = case d of+splitExtension x = case nameDot of                        "" -> (x,"")-                       (y:ys) -> (a ++ reverse ys, y : reverse c)+                       _ -> (dir ++ init nameDot, extSeparator : ext)     where-        (a,b) = splitFileName_ x-        (c,d) = break isExtSeparator $ reverse b+        (dir,file) = splitFileName_ x+        (nameDot,ext) = breakEnd isExtSeparator file  -- | Get the extension of a file, returns @\"\"@ for no extension, @.ext@ otherwise. --+-- > takeExtension "/directory/path.ext" == ".ext" -- > takeExtension x == snd (splitExtension x) -- > Valid x => takeExtension (addExtension x "ext") == ".ext" -- > Valid x => takeExtension (replaceExtension x "ext") == ".ext" takeExtension :: FilePath -> String takeExtension = snd . splitExtension --- | Set the extension of a file, overwriting one if already present.+-- | Remove the current extension and add another, equivalent to 'replaceExtension'. --+-- > "/directory/path.txt" -<.> "ext" == "/directory/path.ext"+-- > "/directory/path.txt" -<.> ".ext" == "/directory/path.ext"+-- > "foo.o" -<.> "c" == "foo.c"+(-<.>) :: FilePath -> String -> FilePath+(-<.>) = replaceExtension++-- | Set the extension of a file, overwriting one if already present, equivalent to '<.>'.+--+-- > replaceExtension "/directory/path.txt" "ext" == "/directory/path.ext"+-- > replaceExtension "/directory/path.txt" ".ext" == "/directory/path.ext" -- > replaceExtension "file.txt" ".bob" == "file.bob" -- > replaceExtension "file.txt" "bob" == "file.bob" -- > replaceExtension "file" ".bob" == "file.bob" -- > replaceExtension "file.txt" "" == "file" -- > replaceExtension "file.fred.bob" "txt" == "file.fred.txt"+-- > replaceExtension x y == addExtension (dropExtension x) y replaceExtension :: FilePath -> String -> FilePath replaceExtension x y = dropExtension x <.> y --- | Alias to 'addExtension', for people who like that sort of thing.+-- | Add an extension, even if there is already one there, equivalent to 'addExtension'.+--+-- > "/directory/path" <.> "ext" == "/directory/path.ext"+-- > "/directory/path" <.> ".ext" == "/directory/path.ext" (<.>) :: FilePath -> String -> FilePath (<.>) = addExtension  -- | Remove last extension, and the \".\" preceding it. --+-- > dropExtension "/directory/path.ext" == "/directory/path" -- > dropExtension x == fst (splitExtension x) dropExtension :: FilePath -> FilePath dropExtension = fst . splitExtension --- | Add an extension, even if there is already one there.---   E.g. @addExtension \"foo.txt\" \"bat\" -> \"foo.txt.bat\"@.+-- | Add an extension, even if there is already one there, equivalent to '<.>'. --+-- > addExtension "/directory/path" "ext" == "/directory/path.ext" -- > addExtension "file.txt" "bib" == "file.txt.bib" -- > addExtension "file." ".bib" == "file..bib" -- > addExtension "file" ".bib" == "file.bib"@@ -268,15 +301,19 @@  -- | Does the given filename have an extension? --+-- > hasExtension "/directory/path.ext" == True+-- > hasExtension "/directory/path" == False -- > null (takeExtension x) == not (hasExtension x) hasExtension :: FilePath -> Bool hasExtension = any isExtSeparator . takeFileName  --- | Split on all extensions+-- | Split on all extensions. --+-- > splitExtensions "/directory/path.ext" == ("/directory/path",".ext")+-- > splitExtensions "file.tar.gz" == ("file",".tar.gz") -- > uncurry (++) (splitExtensions x) == x--- > uncurry addExtension (splitExtensions x) == x+-- > Valid x => uncurry addExtension (splitExtensions x) == x -- > splitExtensions "file.tar.gz" == ("file",".tar.gz") splitExtensions :: FilePath -> (FilePath, String) splitExtensions x = (a ++ c, d)@@ -284,14 +321,18 @@         (a,b) = splitFileName_ x         (c,d) = break isExtSeparator b --- | Drop all extensions+-- | Drop all extensions. ----- > not $ hasExtension (dropExtensions x)+-- > dropExtensions "/directory/path.ext" == "/directory/path"+-- > dropExtensions "file.tar.gz" == "file"+-- > not $ hasExtension $ dropExtensions x+-- > not $ any isExtSeparator $ takeFileName $ dropExtensions x dropExtensions :: FilePath -> FilePath dropExtensions = fst . splitExtensions --- | Get all extensions+-- | Get all extensions. --+-- > takeExtensions "/directory/path.ext" == ".ext" -- > takeExtensions "file.tar.gz" == ".tar.gz" takeExtensions :: FilePath -> String takeExtensions = snd . splitExtensions@@ -308,7 +349,7 @@   -- | Split a path into a drive and a path.---   On Unix, \/ is a Drive.+--   On Posix, \/ is a Drive. -- -- > uncurry (++) (splitDrive x) == x -- > Windows: splitDrive "file" == ("","file")@@ -326,25 +367,17 @@ -- > Posix:   splitDrive "file" == ("","file") splitDrive :: FilePath -> (FilePath, FilePath) splitDrive x | isPosix = span (== '/') x--splitDrive x | isJust y = fromJust y-    where y = readDriveLetter x--splitDrive x | isJust y = fromJust y-    where y = readDriveUNC x--splitDrive x | isJust y = fromJust y-    where y = readDriveShare x-+splitDrive x | Just y <- readDriveLetter x = y+splitDrive x | Just y <- readDriveUNC x = y+splitDrive x | Just y <- readDriveShare x = y splitDrive x = ("",x)  addSlash :: FilePath -> FilePath -> (FilePath, FilePath) addSlash a xs = (a++c,d)     where (c,d) = span isPathSeparator xs --- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp+-- See [1]. -- "\\?\D:\<path>" or "\\?\UNC\<server>\<share>"--- a is "\\?\" readDriveUNC :: FilePath -> Maybe (FilePath, FilePath) readDriveUNC (s1:s2:'?':s3:xs) | all isPathSeparator [s1,s2,s3] =     case map toUpper xs of@@ -352,6 +385,7 @@             let (a,b) = readDriveShareName (drop 4 xs)             in Just (s1:s2:'?':s3:take 4 xs ++ a, b)         _ -> case readDriveLetter xs of+                 -- Extended-length path.                  Just (a,b) -> Just (s1:s2:'?':s3:a,b)                  Nothing -> Nothing readDriveUNC _ = Nothing@@ -370,7 +404,7 @@ readDriveShare _ = Nothing  {- assume you have already seen \\ -}-{- share\bob -> "share","\","bob" -}+{- share\bob -> "share\", "bob" -} readDriveShareName :: String -> (FilePath, FilePath) readDriveShareName name = addSlash a b     where (a,b) = break isPathSeparator name@@ -379,19 +413,13 @@  -- | Join a drive and the rest of the path. ----- >          uncurry joinDrive (splitDrive x) == x+-- > Valid x => uncurry joinDrive (splitDrive x) == x -- > Windows: joinDrive "C:" "foo" == "C:foo" -- > Windows: joinDrive "C:\\" "bar" == "C:\\bar" -- > Windows: joinDrive "\\\\share" "foo" == "\\\\share\\foo" -- > Windows: joinDrive "/:" "foo" == "/:\\foo" joinDrive :: FilePath -> FilePath -> FilePath-joinDrive a b | isPosix = a ++ b-              | null a = b-              | null b = a-              | isPathSeparator (last a) = a ++ b-              | otherwise = case a of-                                [a1,':'] | isLetter a1 -> a ++ b-                                _ -> a ++ [pathSeparator] ++ b+joinDrive = combineAlways  -- | Get the drive from a filepath. --@@ -408,20 +436,33 @@ -- | Does a path have a drive. -- -- > not (hasDrive x) == null (takeDrive x)+-- > Posix:   hasDrive "/foo" == True+-- > Windows: hasDrive "C:\\foo" == True+-- > Windows: hasDrive "C:foo" == True+-- >          hasDrive "foo" == False+-- >          hasDrive "" == False hasDrive :: FilePath -> Bool hasDrive = not . null . takeDrive   -- | Is an element a drive+--+-- > Posix:   isDrive "/" == True+-- > Posix:   isDrive "/foo" == False+-- > Windows: isDrive "C:\\" == True+-- > Windows: isDrive "C:\\foo" == False+-- >          isDrive "" == False isDrive :: FilePath -> Bool-isDrive = null . dropDrive+isDrive x = not (null x) && null (dropDrive x)   --------------------------------------------------------------------- -- Operations on a filepath, as a list of directories  -- | Split a filename into directory and file. 'combine' is the inverse.+--   The first component will often end with a trailing slash. --+-- > splitFileName "/directory/file.ext" == ("/directory/","file.ext") -- > Valid x => uncurry (</>) (splitFileName x) == x || fst (splitFileName x) == "./" -- > Valid x => isValid (fst (splitFileName x)) -- > splitFileName "file/bob.txt" == ("file/", "bob.txt")@@ -441,19 +482,22 @@ -- look strange and upset simple equality properties.  See -- e.g. replaceFileName. splitFileName_ :: FilePath -> (String, String)-splitFileName_ x = (c ++ reverse b, reverse a)+splitFileName_ x = (drv ++ dir, file)     where-        (a,b) = break isPathSeparator $ reverse d-        (c,d) = splitDrive x+        (drv,pth) = splitDrive x+        (dir,file) = breakEnd isPathSeparator pth  -- | Set the filename. --+-- > replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext" -- > Valid x => replaceFileName x (takeFileName x) == x replaceFileName :: FilePath -> String -> FilePath replaceFileName x y = a </> y where (a,_) = splitFileName_ x --- | Drop the filename.+-- | Drop the filename. Unlike 'takeDirectory', this function will leave+--   a trailing path separator on the directory. --+-- > dropFileName "/directory/file.ext" == "/directory/" -- > dropFileName x == fst (splitFileName x) dropFileName :: FilePath -> FilePath dropFileName = fst . splitFileName@@ -461,6 +505,7 @@  -- | Get the file name. --+-- > takeFileName "/directory/file.ext" == "file.ext" -- > takeFileName "test/" == "" -- > takeFileName x `isSuffixOf` x -- > takeFileName x == snd (splitFileName x)@@ -472,6 +517,7 @@  -- | Get the base name, without an extension or path. --+-- > takeBaseName "/directory/file.ext" == "file" -- > takeBaseName "file/test.txt" == "test" -- > takeBaseName "dave.ext" == "dave" -- > takeBaseName "" == ""@@ -483,6 +529,7 @@  -- | Set the base name. --+-- > replaceBaseName "/directory/other.ext" "file" == "/directory/file.ext" -- > replaceBaseName "file/test.txt" "bob" == "file/bob.txt" -- > replaceBaseName "fred" "bill" == "bill" -- > replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar"@@ -502,6 +549,11 @@ hasTrailingPathSeparator x = isPathSeparator (last x)  +hasLeadingPathSeparator :: FilePath -> Bool+hasLeadingPathSeparator "" = False+hasLeadingPathSeparator x = isPathSeparator (head x)++ -- | Add a trailing file path separator if one is not already present. -- -- > hasTrailingPathSeparator (addTrailingPathSeparator x)@@ -514,21 +566,24 @@ -- | Remove any trailing path separators -- -- > dropTrailingPathSeparator "file/test/" == "file/test"--- > Posix:    not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x--- > Posix:    dropTrailingPathSeparator "/" == "/"+-- >           dropTrailingPathSeparator "/" == "/" -- > Windows:  dropTrailingPathSeparator "\\" == "\\"+-- > Posix:    not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x dropTrailingPathSeparator :: FilePath -> FilePath dropTrailingPathSeparator x =     if hasTrailingPathSeparator x && not (isDrive x)-    then let x' = reverse $ dropWhile isPathSeparator $ reverse x-         in if null x' then [pathSeparator] else x'+    then let x' = dropWhileEnd isPathSeparator x+         in if null x' then [last x] else x'     else x   -- | Get the directory name, move up one level. --+-- >           takeDirectory "/directory/other.ext" == "/directory" -- >           takeDirectory x `isPrefixOf` x || takeDirectory x == "." -- >           takeDirectory "foo" == "."+-- >           takeDirectory "/" == "/"+-- >           takeDirectory "/foo" == "/" -- >           takeDirectory "/foo/bar/baz" == "/foo/bar" -- >           takeDirectory "/foo/bar/baz/" == "/foo/bar/baz" -- >           takeDirectory "foo/bar/baz" == "foo/bar"@@ -536,46 +591,74 @@ -- > Windows:  takeDirectory "foo\\bar\\\\" == "foo\\bar" -- > Windows:  takeDirectory "C:\\" == "C:\\" takeDirectory :: FilePath -> FilePath-takeDirectory x = if isDrive file || (null res && not (null file)) then file else res-    where-        res = reverse $ dropWhile isPathSeparator $ reverse file-        file = dropFileName x-        _ = isPrefixOf x -- warning suppression+takeDirectory = dropTrailingPathSeparator . dropFileName  -- | Set the directory, keeping the filename the same. --+-- > replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext" -- > Valid x => replaceDirectory x (takeDirectory x) `equalFilePath` x replaceDirectory :: FilePath -> String -> FilePath replaceDirectory x dir = combineAlways dir (takeFileName x)  --- | Combine two paths, if the second path 'isAbsolute', then it returns the second.+-- | Combine two paths, if the second path starts with a path separator or a+-- drive letter, then it returns the second. -- -- > Valid x => combine (takeDirectory x) (takeFileName x) `equalFilePath` x+--+-- Combined: -- > Posix:   combine "/" "test" == "/test" -- > Posix:   combine "home" "bob" == "home/bob"+-- > Posix:   combine "x:" "foo" == "x:/foo"+-- > Windows: combine "C:\\foo" "bar" == "C:\\foo\\bar" -- > Windows: combine "home" "bob" == "home\\bob"+--+-- Not combined:+-- > Posix:   combine "home" "/bob" == "/bob"+-- > Windows: combine "home" "C:\\bob" == "C:\\bob"+--+-- Not combined (tricky):+-- On Windows, if a filepath starts with a single slash, it is relative to the+-- root of the current drive. In [1], this is (confusingly) referred to as an+-- absolute path.+-- The current behavior of @combine@ is to never combine these forms.+-- -- > Windows: combine "home" "/bob" == "/bob"+-- > Windows: combine "home" "\\bob" == "\\bob"+-- > Windows: combine "C:\\home" "\\bob" == "\\bob"+--+-- On Windows, from [1]: "If a file name begins with only a disk designator+-- but not the backslash after the colon, it is interpreted as a relative path+-- to the current directory on the drive with the specified letter."+-- The current behavior of @combine@ is to never combine these forms.+--+-- > Windows: combine "D:\\foo" "C:bar" == "C:bar"+-- > Windows: combine "C:\\foo" "C:bar" == "C:bar" combine :: FilePath -> FilePath -> FilePath-combine a b | hasDrive b || (not (null b) && isPathSeparator (head b)) = b+combine a b | hasLeadingPathSeparator b || hasDrive b = b             | otherwise = combineAlways a b  -- | Combine two paths, assuming rhs is NOT absolute. combineAlways :: FilePath -> FilePath -> FilePath combineAlways a b | null a = b                   | null b = a-                  | isPathSeparator (last a) = a ++ b-                  | isDrive a = joinDrive a b-                  | otherwise = a ++ [pathSeparator] ++ b+                  | hasTrailingPathSeparator a = a ++ b+                  | otherwise = case a of+                      [a1,':'] | isWindows && isLetter a1 -> a ++ b+                      _ -> a ++ [pathSeparator] ++ b  --- | A nice alias for 'combine'.+-- | Join two values with a path separator. For examples and caveats see the equivalent function 'combine'.+--+-- > Posix:   "/directory" </> "file.ext" == "/directory/file.ext"+-- > Windows: "/directory" </> "file.ext" == "/directory\\file.ext" (</>) :: FilePath -> FilePath -> FilePath (</>) = combine   -- | Split a path by the directory separator. --+-- > splitPath "/directory/file.ext" == ["/","directory/","file.ext"] -- > concat (splitPath x) == x -- > splitPath "test//item/" == ["test//","item/"] -- > splitPath "test/item/file" == ["test/","item/","file"]@@ -595,30 +678,26 @@  -- | Just as 'splitPath', but don't add the trailing slashes to each element. ----- > splitDirectories "test/file" == ["test","file"]--- > splitDirectories "/test/file" == ["/","test","file"]--- > Valid x => joinPath (splitDirectories x) `equalFilePath` x--- > splitDirectories "" == []+-- >          splitDirectories "/directory/file.ext" == ["/","directory","file.ext"]+-- >          splitDirectories "test/file" == ["test","file"]+-- >          splitDirectories "/test/file" == ["/","test","file"]+-- > Windows: splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"]+-- >          Valid x => joinPath (splitDirectories x) `equalFilePath` x+-- >          splitDirectories "" == []+-- > Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]+-- >          splitDirectories "/test///file" == ["/","test","file"] splitDirectories :: FilePath -> [FilePath]-splitDirectories path =-        if hasDrive path then head pathComponents : f (tail pathComponents)-        else f pathComponents-    where-        pathComponents = splitPath path--        f = map g-        g x = if null res then x else res-            where res = takeWhile (not . isPathSeparator) x+splitDirectories = map dropTrailingPathSeparator . splitPath   -- | Join path elements back together. --+-- > joinPath ["/","directory/","file.ext"] == "/directory/file.ext" -- > Valid x => joinPath (splitPath x) == x -- > joinPath [] == "" -- > Posix: joinPath ["test","file","path"] == "test/file/path"---- Note that this definition on c:\\c:\\, join then split will give c:\\. joinPath :: [FilePath] -> FilePath+-- Note that this definition on c:\\c:\\, join then split will give c:\\. joinPath = foldr combine ""  @@ -636,33 +715,33 @@ -- -- >          x == y ==> equalFilePath x y -- >          normalise x == normalise y ==> equalFilePath x y--- > Posix:   equalFilePath "foo" "foo/"--- > Posix:   not (equalFilePath "foo" "/foo")+-- >          equalFilePath "foo" "foo/"+-- >          not (equalFilePath "foo" "/foo") -- > Posix:   not (equalFilePath "foo" "FOO") -- > Windows: equalFilePath "foo" "FOO"+-- > Windows: not (equalFilePath "C:" "C:/") equalFilePath :: FilePath -> FilePath -> Bool equalFilePath a b = f a == f b     where-        f x | isWindows = dropTrailSlash $ map toLower $ normalise x-            | otherwise = dropTrailSlash $ normalise x--        dropTrailSlash x | length x >= 2 && isPathSeparator (last x) = init x-                         | otherwise = x+        f x | isWindows = dropTrailingPathSeparator $ map toLower $ normalise x+            | otherwise = dropTrailingPathSeparator $ normalise x   -- | Contract a filename, based on a relative path. -----   There is no corresponding @makeAbsolute@ function, instead use---   @System.Directory.canonicalizePath@ which has the same effect.+--   The corresponding @makeAbsolute@ function can be found in+--   @System.Directory@. ----- >          Valid y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x+-- >          makeRelative "/directory" "/directory/file.ext" == "file.ext"+-- >          Valid x => makeRelative (takeDirectory x) x `equalFilePath` takeFileName x -- >          makeRelative x x == "."--- >          null y || equalFilePath (makeRelative x (x </> y)) y || null (takeFileName x)+-- >          Valid x y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x -- > Windows: makeRelative "C:\\Home" "c:\\home\\bob" == "bob" -- > Windows: makeRelative "C:\\Home" "c:/home/bob" == "bob" -- > Windows: makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob" -- > Windows: makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob" -- > Windows: makeRelative "/Home" "/home/bob" == "bob"+-- > Windows: makeRelative "/" "//" == "//" -- > Posix:   makeRelative "/Home" "/home/bob" == "/home/bob" -- > Posix:   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar" -- > Posix:   makeRelative "/fred" "bob" == "bob"@@ -684,10 +763,10 @@             where (a,b) = break isPathSeparator $ dropWhile isPathSeparator x          -- on windows, need to drop '/' which is kind of absolute, but not a drive-        dropAbs (x:xs) | isPathSeparator x = xs+        dropAbs x | hasLeadingPathSeparator x && not (hasDrive x) = tail x         dropAbs x = dropDrive x -        takeAbs (x:_) | isPathSeparator x = [pathSeparator]+        takeAbs x | hasLeadingPathSeparator x && not (hasDrive x) = [pathSeparator]         takeAbs x = map (\y -> if isPathSeparator y then pathSeparator else toLower y) $ takeDrive x  -- | Normalise a file@@ -705,49 +784,56 @@ -- > Posix:   normalise "./bob/fred/" == "bob/fred/" -- > Windows: normalise "c:\\file/bob\\" == "C:\\file\\bob\\" -- > Windows: normalise "c:\\" == "C:\\"+-- > Windows: normalise "C:.\\" == "C:" -- > Windows: normalise "\\\\server\\test" == "\\\\server\\test"+-- > Windows: normalise "//server/test" == "\\\\server\\test" -- > Windows: normalise "c:/file" == "C:\\file"+-- > Windows: normalise "/file" == "\\file"+-- > Windows: normalise "\\" == "\\"+-- > Windows: normalise "/./" == "\\" -- >          normalise "." == "." -- > Posix:   normalise "./" == "./" -- > Posix:   normalise "./." == "./"+-- > Posix:   normalise "/./" == "/" -- > Posix:   normalise "/" == "/" -- > Posix:   normalise "bob/fred/." == "bob/fred/"+-- > Posix:   normalise "//home" == "/home" normalise :: FilePath -> FilePath-normalise path = joinDrive' (normaliseDrive drv) (f pth)-              ++ [pathSeparator | isDirPath pth]+normalise path = result ++ [pathSeparator | addPathSeparator]     where         (drv,pth) = splitDrive path+        result = joinDrive' (normaliseDrive drv) (f pth)          joinDrive' "" "" = "."         joinDrive' d p = joinDrive d p -        isDirPath xs = lastSep xs-            || not (null xs) && last xs == '.' && lastSep (init xs)-        lastSep xs = not (null xs) && isPathSeparator (last xs)+        addPathSeparator = isDirPath pth+            && not (hasTrailingPathSeparator result)+            && not (isRelativeDrive drv) -        f = joinPath . dropDots . splitDirectories . propSep+        isDirPath xs = hasTrailingPathSeparator xs+            || not (null xs) && last xs == '.' && hasTrailingPathSeparator (init xs) -        propSep (a:b:xs)-         | isPathSeparator a && isPathSeparator b = propSep (a:xs)-        propSep (a:xs)-         | isPathSeparator a = pathSeparator : propSep xs-        propSep (x:xs) = x : propSep xs+        f = joinPath . dropDots . propSep . splitDirectories++        propSep (x:xs) | all isPathSeparator x = [pathSeparator] : xs+                       | otherwise = x : xs         propSep [] = []          dropDots = filter ("." /=)  normaliseDrive :: FilePath -> FilePath-normaliseDrive drive | isPosix = drive+normaliseDrive "" = ""+normaliseDrive _ | isPosix = [pathSeparator] normaliseDrive drive = if isJust $ readDriveLetter x2                        then map toUpper x2-                       else drive+                       else x2     where         x2 = map repSlash drive          repSlash x = if isPathSeparator x then pathSeparator else x --- information for validity functions on Windows--- see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp+-- Information for validity functions on Windows. See [1]. badCharacters :: [Char] badCharacters = ":*?><|\"" badElements :: [FilePath]@@ -766,15 +852,18 @@ -- > Windows: isValid "c:\\test\\prn.txt" == False -- > Windows: isValid "c:\\nul\\file" == False -- > Windows: isValid "\\\\" == False+-- > Windows: isValid "\\\\\\foo" == False+-- > Windows: isValid "\\\\?\\D:file" == False isValid :: FilePath -> Bool isValid "" = False isValid _ | isPosix = True isValid path =         not (any (`elem` badCharacters) x2) &&         not (any f $ splitDirectories x2) &&-        not (length path >= 2 && all isPathSeparator path)+        not (isJust (readDriveShare x1) && all isPathSeparator x1) &&+        not (isJust (readDriveUNC x1) && not (hasTrailingPathSeparator x1))     where-        x2 = dropDrive path+        (x1,x2) = splitDrive path         f x = map toUpper (dropExtensions x) `elem` badElements  @@ -783,17 +872,23 @@ -- > isValid (makeValid x) -- > isValid x ==> makeValid x == x -- > makeValid "" == "_"+-- > Windows: makeValid "c:\\already\\/valid" == "c:\\already\\/valid" -- > Windows: makeValid "c:\\test:of_test" == "c:\\test_of_test" -- > Windows: makeValid "test*" == "test_" -- > Windows: makeValid "c:\\test\\nul" == "c:\\test\\nul_" -- > Windows: makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt" -- > Windows: makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt" -- > Windows: makeValid "c:\\nul\\file" == "c:\\nul_\\file"+-- > Windows: makeValid "\\\\\\foo" == "\\\\drive"+-- > Windows: makeValid "\\\\?\\D:file" == "\\\\?\\D:\\file" makeValid :: FilePath -> FilePath makeValid "" = "_"-makeValid path | isPosix = path-makeValid x | length x >= 2 && all isPathSeparator x = take 2 x ++ "drive"-makeValid path = joinDrive drv $ validElements $ validChars pth+makeValid path+        | isPosix = path+        | isJust (readDriveShare drv) && all isPathSeparator drv = take 2 drv ++ "drive"+        | isJust (readDriveUNC drv) && not (hasTrailingPathSeparator drv) =+            makeValid (drv ++ [pathSeparator] ++ pth)+        | otherwise = joinDrive drv $ validElements $ validChars pth     where         (drv,pth) = splitDrive path @@ -802,8 +897,8 @@             | otherwise = x          validElements x = joinPath $ map g $ splitPath x-        g x = h (reverse b) ++ reverse a-            where (a,b) = span isPathSeparator $ reverse x+        g x = h a ++ b+            where (a,b) = break isPathSeparator x         h x = if map toUpper a `elem` badElements then a ++ "_" <.> b else x             where (a,b) = splitExtensions x @@ -813,26 +908,35 @@ -- > Windows: isRelative "path\\test" == True -- > Windows: isRelative "c:\\test" == False -- > Windows: isRelative "c:test" == True+-- > Windows: isRelative "c:\\" == False+-- > Windows: isRelative "c:/" == False -- > Windows: isRelative "c:" == True -- > Windows: isRelative "\\\\foo" == False+-- > Windows: isRelative "\\\\?\\foo" == False+-- > Windows: isRelative "\\\\?\\UNC\\foo" == False -- > Windows: isRelative "/foo" == True+-- > Windows: isRelative "\\foo" == True -- > Posix:   isRelative "test/path" == True -- > Posix:   isRelative "/test" == False+-- > Posix:   isRelative "/" == False+--+-- According to [1]:+--+-- * "A UNC name of any format [is never relative]."+--+-- * "You cannot use the "\\?\" prefix with a relative path." isRelative :: FilePath -> Bool-isRelative = isRelativeDrive . takeDrive+isRelative x = null drive || isRelativeDrive drive+    where drive = takeDrive x  --- Disable these tests for now, as we want to be able to run the--- testsuite without doing a special TESTING compilation--- -- > isRelativeDrive "" == True--- -- > Windows: isRelativeDrive "c:\\" == False--- -- > Windows: isRelativeDrive "c:/" == False--- -- > Windows: isRelativeDrive "c:" == True--- -- > Windows: isRelativeDrive "\\\\foo" == False--- -- > Posix:   isRelativeDrive "/" == False+{- c:foo -}+-- From [1]: "If a file name begins with only a disk designator but not the+-- backslash after the colon, it is interpreted as a relative path to the+-- current directory on the drive with the specified letter." isRelativeDrive :: String -> Bool-isRelativeDrive x = null x ||-    maybe False (not . isPathSeparator . last . fst) (readDriveLetter x)+isRelativeDrive x =+    maybe False (not . hasTrailingPathSeparator . fst) (readDriveLetter x)   -- | @not . 'isRelative'@@@ -840,3 +944,22 @@ -- > isAbsolute x == not (isRelative x) isAbsolute :: FilePath -> Bool isAbsolute = not . isRelative+++-----------------------------------------------------------------------------+-- dropWhileEnd (>2) [1,2,3,4,1,2,3,4] == [1,2,3,4,1,2])+-- Note that Data.List.dropWhileEnd is only available in base >= 4.5.+dropWhileEnd :: (a -> Bool) -> [a] -> [a]+dropWhileEnd p = reverse . dropWhile p . reverse++-- takeWhileEnd (>2) [1,2,3,4,1,2,3,4] == [3,4])+takeWhileEnd :: (a -> Bool) -> [a] -> [a]+takeWhileEnd p = reverse . takeWhile p . reverse++-- spanEnd (>2) [1,2,3,4,1,2,3,4] = ([1,2,3,4,1,2], [3,4])+spanEnd :: (a -> Bool) -> [a] -> ([a], [a])+spanEnd p xs = (dropWhileEnd p xs, takeWhileEnd p xs)++-- breakEnd (< 2) [1,2,3,4,1,2,3,4] == ([1,2,3,4,1],[2,3,4])+breakEnd :: (a -> Bool) -> [a] -> ([a], [a])+breakEnd p = spanEnd (not . p)
changelog.md view
@@ -1,5 +1,39 @@ # Changelog for [`filepath` package](http://hackage.haskell.org/package/filepath) +_Note: below all `FilePath` values are unquoted, so `\\` really means two backslashes._++## 1.4.0.0  *Mar 2015*++  * Bundled with GHC 7.10.1++  * New function: Add `-<.>` as an alias for `replaceExtension`.++  * Semantic change: `joinDrive /foo bar` now returns `/foo/bar`, instead of `/foobar`++  * Semantic change: on Windows, `splitSearchPath File1;\"File 2\"` now returns `[File1,File2]` instead of `[File1,\"File2\"]`++  * Bug fix: on Posix systems, `normalise //home` now returns `/home`, instead of `//home`++  * Bug fix: `normalise /./` now returns `/` on Posix and `\` on Windows, instead of `//` and `\\`++  * Bug fix: `isDrive ""` now returns `False`, instead of `True`++  * Bug fix: on Windows, `dropTrailingPathSeparator /` now returns `/` unchanged, instead of the normalised `\`++  * Bug fix: on Windows, `equalFilePath C:\ C:` now returns `False`, instead of `True`++  * Bug fix: on Windows, `isValid \\\foo` now returns `False`, instead of `True`++  * Bug fix: on Windows, `isValid \\?\D:file` now returns `False`, instead of `True`++  * Bug fix: on Windows, `normalise \` now returns `\` unchanged, instead of `\\`++  * Bug fix: on Windows, `normalise C:.\` now returns `C:`, instead of `C:\\`++  * Bug fix: on Windows, `normalise //server/test` now returns `\\server\test`, instead of `//server/test` unchanged++  * Bug fix: on Windows, `makeRelative / //` now returns `//`, instead of `""`+ ## 1.3.0.2  *Mar 2014*    * Bundled with GHC 7.8.1@@ -20,4 +54,4 @@    * Add support for SafeHaskell -  * Fix `normalise "/"` to result in `"/"` rather than `"/."`+  * Bug fix: `normalise /` now returns `/`, instead of `/.`
filepath.cabal view
@@ -1,68 +1,65 @@-Name:           filepath-Version:        1.3.0.2--- GHC 7.6.1 released with 1.3.0.1-License:        BSD3+name:           filepath+version:        1.4.0.0+-- NOTE: Don't forget to update ./changelog.md+license:        BSD3 license-file:   LICENSE-Author:         Neil Mitchell-Maintainer:     libraries@haskell.org-bug-reports:    http://ghc.haskell.org/trac/ghc/newticket?component=libraries%20%28other%29&keywords=filepath-Homepage:       http://www-users.cs.york.ac.uk/~ndm/filepath/-Category:       System+author:         Neil Mitchell <ndmitchell@gmail.com>+maintainer:     Neil Mitchell <ndmitchell@gmail.com>+copyright:      Neil Mitchell 2005-2015+bug-reports:    https://github.com/haskell/filepath/issues+homepage:       https://github.com/haskell/filepath#readme+category:       System build-type:     Simple-Synopsis:       Library for manipulating FilePaths in a cross platform way.+synopsis:       Library for manipulating FilePaths in a cross platform way. cabal-version:  >=1.10-tested-with:    GHC==7.6.3, GHC==7.6.2, GHC==7.6.1, GHC==7.4.2, GHC==7.4.1, GHC==7.2.2, GHC==7.2.1, GHC==7.0.4, GHC==7.0.3, GHC==7.0.2, GHC==7.0.1, GHC==6.12.3+tested-with:    GHC==7.10.1, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==7.2.2 description:-    A library for 'FilePath' manipulations, using Posix or Windows filepaths-    depending on the platform.+    This package provides functionality for manipulating @FilePath@ values, and is shipped with both <https://www.haskell.org/ghc/ GHC> and the <https://www.haskell.org/platform/ Haskell Platform>. It provides three modules:     .-    Both "System.FilePath.Posix" and "System.FilePath.Windows" provide-    the same interface. See either for examples and a list of the-    available functions.+    * "System.FilePath.Posix" manipulates POSIX\/Linux style @FilePath@ values (with @\/@ as the path separator).+    .+    * "System.FilePath.Windows" manipulates Windows style @FilePath@ values (with either @\\@ or @\/@ as the path separator, and deals with drives).+    .+    * "System.FilePath" is an alias for the module appropriate to your platform.+    .+    All three modules provide the same API, and the same documentation (calling out differences in the different variants). -Extra-Source-Files:+extra-source-files:     System/FilePath/Internal.hs     README.md     changelog.md -Library+library     default-language: Haskell98     other-extensions:         CPP-    if impl(GHC>=7.2)+    if impl(GHC >= 7.2)         other-extensions: Safe -    Exposed-modules:+    exposed-modules:         System.FilePath         System.FilePath.Posix         System.FilePath.Windows -    Build-Depends:-        base >= 4 && < 4.8+    build-depends:+        base >= 4 && < 4.9      ghc-options: -Wall --- When run directly from the Git repo, you need to--- generate the tests/FilePath_Tests.hs file via------  cd tests/ && runghc ./GenTests.hs-Test-Suite filepath-tests+test-suite filepath-tests     type: exitcode-stdio-1.0     default-language: Haskell98-    main-is: FilePath_Test.hs+    main-is: Test.hs+    ghc-options: -main-is Test     hs-source-dirs: tests-    other-modules: AutoTest+    other-modules:+        TestGen+        TestUtil     build-depends:         filepath,         base,-        QuickCheck == 2.6.*,-        random     == 1.0.*+        QuickCheck >= 2.7 && < 2.8  source-repository head     type:     git-    location: http://git.haskell.org/packages/filepath.git--source-repository this-    type:     git-    location: http://git.haskell.org/packages/filepath.git-    tag:      filepath-1.3.0.2-release+    location: https://github.com/haskell/filepath.git
− tests/AutoTest.hs
@@ -1,106 +0,0 @@--module AutoTest(-    module AutoTest,-    module Test.QuickCheck,-    module Data.List-    ) where--import Test.QuickCheck hiding ((==>))-import Data.Char-import System.Random-import Data.List-import Control.Monad--infixr 0 ==>-a ==> b = not a || b---constTest :: Bool -> IO ()-constTest True = return ()-constTest False = error "Failed on constTest"----data QFilePath = QFilePath FilePath-                 deriving Show--instance Arbitrary QFilePath where-    arbitrary = liftM QFilePath arbitrary----- QuickCheck 2.4.1.1 has its own Arbitrary Char instance, so commented out for now--- instance Arbitrary Char where---     arbitrary = elements "?|./:\\abcd 123;_"----quickSafe :: Testable a => a -> IO ()-quickSafe prop = quickCheckWith (stdArgs { chatty = False }) prop-    -- checkit quick prop---- below is mainly stolen from Test.QuickCheck, modified to crash out on failure--- Doesn't compile with QuickCheck 2.4.1.1, so we just use the quickCheck function for now--{--quick :: Config-quick = Config-  { configMaxTest = 500-  , configMaxFail = 1000-  , configSize    = (+ 3) . (`div` 2)-  , configEvery   = \n args -> let s = show n in s ++ [ '\b' | _ <- s ]-  }--checkit :: Testable a => Config -> a -> IO ()-checkit config a =-  do rnd <- newStdGen-     tests config (evaluate a) rnd 0 0 []---tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO () -tests config gen rnd0 ntest nfail stamps-  | ntest == configMaxTest config = do done "OK, passed" ntest stamps-  | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps-                                       error "More entropy required!"-  | otherwise               =-      do putStr (configEvery config ntest (arguments result))-         case ok result of-           Nothing    ->-             tests config gen rnd1 ntest (nfail+1) stamps-           Just True  ->-             tests config gen rnd1 (ntest+1) nfail (stamp result:stamps)-           Just False ->-             error ( "Falsifiable, after "-                   ++ show ntest-                   ++ " tests:\n"-                   ++ unlines (arguments result)-                    )-     where-      result      = generate (configSize config ntest) rnd2 gen-      (rnd1,rnd2) = split rnd0--done :: String -> Int -> [[String]] -> IO ()-done mesg ntest stamps =-  do putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )- where-  table = display-        . map entry-        . reverse-        . sort-        . map pairLength-        . group-        . sort-        . filter (not . null)-        $ stamps--  display []  = ".\n"-  display [x] = " (" ++ x ++ ").\n"-  display xs  = ".\n" ++ unlines (map (++ ".") xs)--  pairLength xss@(xs:_) = (length xss, xs)-  entry (n, xs)         = percentage n ntest-                       ++ " "-                       ++ concat (intersperse ", " xs)--  percentage n m        = show ((100 * n) `div` m) ++ "%"--}-
− tests/FilePath_Test.hs
@@ -1,602 +0,0 @@-import AutoTest-import qualified System.FilePath.Windows as W-import qualified System.FilePath.Posix as P-main = do- block1- block2- block3- block4- block5- block6- block7- block8- block9- block10- block11- block12-block1 = do- putStrLn "Test 1, from line 122"- constTest (W.pathSeparator == '\\')- putStrLn "Test 2, from line 123"- constTest (P.pathSeparator == '/')- putStrLn "Test 3, from line 124"- constTest (W.isPathSeparator W.pathSeparator)- putStrLn "Test 4, from line 124"- constTest (P.isPathSeparator P.pathSeparator)- putStrLn "Test 5, from line 130"- constTest (W.pathSeparators == [ '\\' , '/' ])- putStrLn "Test 6, from line 131"- constTest (P.pathSeparators == [ '/' ])- putStrLn "Test 7, from line 132"- constTest (W.pathSeparator ` elem ` W.pathSeparators)- putStrLn "Test 8, from line 132"- constTest (P.pathSeparator ` elem ` P.pathSeparators)- putStrLn "Test 9, from line 146"- constTest (W.searchPathSeparator == ';')- putStrLn "Test 10, from line 147"- constTest (P.searchPathSeparator == ':')- putStrLn "Test 11, from line 160"- constTest (W.extSeparator == '.')- putStrLn "Test 12, from line 160"- constTest (P.extSeparator == '.')- putStrLn "Test 13, from line 181"- constTest (P.splitSearchPath "File1:File2:File3" == [ "File1" , "File2" , "File3" ])- putStrLn "Test 14, from line 182"- constTest (P.splitSearchPath "File1::File2:File3" == [ "File1" , "." , "File2" , "File3" ])- putStrLn "Test 15, from line 183"- constTest (W.splitSearchPath "File1;File2;File3" == [ "File1" , "File2" , "File3" ])- putStrLn "Test 16, from line 184"- constTest (W.splitSearchPath "File1;;File2;File3" == [ "File1" , "File2" , "File3" ])- putStrLn "Test 17, from line 208"- constTest (W.splitExtension "file.txt" == ( "file" , ".txt" ))- putStrLn "Test 18, from line 208"- constTest (P.splitExtension "file.txt" == ( "file" , ".txt" ))- putStrLn "Test 19, from line 209"- constTest (W.splitExtension "file" == ( "file" , "" ))- putStrLn "Test 20, from line 209"- constTest (P.splitExtension "file" == ( "file" , "" ))- putStrLn "Test 21, from line 210"- constTest (W.splitExtension "file/file.txt" == ( "file/file" , ".txt" ))- putStrLn "Test 22, from line 210"- constTest (P.splitExtension "file/file.txt" == ( "file/file" , ".txt" ))- putStrLn "Test 23, from line 211"- constTest (W.splitExtension "file.txt/boris" == ( "file.txt/boris" , "" ))- putStrLn "Test 24, from line 211"- constTest (P.splitExtension "file.txt/boris" == ( "file.txt/boris" , "" ))- putStrLn "Test 25, from line 212"- constTest (W.splitExtension "file.txt/boris.ext" == ( "file.txt/boris" , ".ext" ))-block2 = do- putStrLn "Test 26, from line 212"- constTest (P.splitExtension "file.txt/boris.ext" == ( "file.txt/boris" , ".ext" ))- putStrLn "Test 27, from line 213"- constTest (W.splitExtension "file/path.txt.bob.fred" == ( "file/path.txt.bob" , ".fred" ))- putStrLn "Test 28, from line 213"- constTest (P.splitExtension "file/path.txt.bob.fred" == ( "file/path.txt.bob" , ".fred" ))- putStrLn "Test 29, from line 214"- constTest (W.splitExtension "file/path.txt/" == ( "file/path.txt/" , "" ))- putStrLn "Test 30, from line 214"- constTest (P.splitExtension "file/path.txt/" == ( "file/path.txt/" , "" ))- putStrLn "Test 31, from line 233"- constTest (W.replaceExtension "file.txt" ".bob" == "file.bob")- putStrLn "Test 32, from line 233"- constTest (P.replaceExtension "file.txt" ".bob" == "file.bob")- putStrLn "Test 33, from line 234"- constTest (W.replaceExtension "file.txt" "bob" == "file.bob")- putStrLn "Test 34, from line 234"- constTest (P.replaceExtension "file.txt" "bob" == "file.bob")- putStrLn "Test 35, from line 235"- constTest (W.replaceExtension "file" ".bob" == "file.bob")- putStrLn "Test 36, from line 235"- constTest (P.replaceExtension "file" ".bob" == "file.bob")- putStrLn "Test 37, from line 236"- constTest (W.replaceExtension "file.txt" "" == "file")- putStrLn "Test 38, from line 236"- constTest (P.replaceExtension "file.txt" "" == "file")- putStrLn "Test 39, from line 237"- constTest (W.replaceExtension "file.fred.bob" "txt" == "file.fred.txt")- putStrLn "Test 40, from line 237"- constTest (P.replaceExtension "file.fred.bob" "txt" == "file.fred.txt")- putStrLn "Test 41, from line 254"- constTest (W.addExtension "file.txt" "bib" == "file.txt.bib")- putStrLn "Test 42, from line 254"- constTest (P.addExtension "file.txt" "bib" == "file.txt.bib")- putStrLn "Test 43, from line 255"- constTest (W.addExtension "file." ".bib" == "file..bib")- putStrLn "Test 44, from line 255"- constTest (P.addExtension "file." ".bib" == "file..bib")- putStrLn "Test 45, from line 256"- constTest (W.addExtension "file" ".bib" == "file.bib")- putStrLn "Test 46, from line 256"- constTest (P.addExtension "file" ".bib" == "file.bib")- putStrLn "Test 47, from line 257"- constTest (W.addExtension "/" "x" == "/.x")- putStrLn "Test 48, from line 257"- constTest (P.addExtension "/" "x" == "/.x")- putStrLn "Test 49, from line 259"- constTest (W.addExtension "\\\\share" ".txt" == "\\\\share\\.txt")- putStrLn "Test 50, from line 280"- constTest (W.splitExtensions "file.tar.gz" == ( "file" , ".tar.gz" ))-block3 = do- putStrLn "Test 51, from line 280"- constTest (P.splitExtensions "file.tar.gz" == ( "file" , ".tar.gz" ))- putStrLn "Test 52, from line 295"- constTest (W.takeExtensions "file.tar.gz" == ".tar.gz")- putStrLn "Test 53, from line 295"- constTest (P.takeExtensions "file.tar.gz" == ".tar.gz")- putStrLn "Test 54, from line 314"- constTest (W.splitDrive "file" == ( "" , "file" ))- putStrLn "Test 55, from line 315"- constTest (W.splitDrive "c:/file" == ( "c:/" , "file" ))- putStrLn "Test 56, from line 316"- constTest (W.splitDrive "c:\\file" == ( "c:\\" , "file" ))- putStrLn "Test 57, from line 317"- constTest (W.splitDrive "\\\\shared\\test" == ( "\\\\shared\\" , "test" ))- putStrLn "Test 58, from line 318"- constTest (W.splitDrive "\\\\shared" == ( "\\\\shared" , "" ))- putStrLn "Test 59, from line 319"- constTest (W.splitDrive "\\\\?\\UNC\\shared\\file" == ( "\\\\?\\UNC\\shared\\" , "file" ))- putStrLn "Test 60, from line 320"- constTest (W.splitDrive "\\\\?\\UNCshared\\file" == ( "\\\\?\\" , "UNCshared\\file" ))- putStrLn "Test 61, from line 321"- constTest (W.splitDrive "\\\\?\\d:\\file" == ( "\\\\?\\d:\\" , "file" ))- putStrLn "Test 62, from line 322"- constTest (W.splitDrive "/d" == ( "" , "/d" ))- putStrLn "Test 63, from line 323"- constTest (P.splitDrive "/test" == ( "/" , "test" ))- putStrLn "Test 64, from line 324"- constTest (P.splitDrive "//test" == ( "//" , "test" ))- putStrLn "Test 65, from line 325"- constTest (P.splitDrive "test/file" == ( "" , "test/file" ))- putStrLn "Test 66, from line 326"- constTest (P.splitDrive "file" == ( "" , "file" ))- putStrLn "Test 67, from line 383"- constTest (W.joinDrive "C:" "foo" == "C:foo")- putStrLn "Test 68, from line 384"- constTest (W.joinDrive "C:\\" "bar" == "C:\\bar")- putStrLn "Test 69, from line 385"- constTest (W.joinDrive "\\\\share" "foo" == "\\\\share\\foo")- putStrLn "Test 70, from line 386"- constTest (W.joinDrive "/:" "foo" == "/:\\foo")- putStrLn "Test 71, from line 427"- constTest (W.splitFileName "file/bob.txt" == ( "file/" , "bob.txt" ))- putStrLn "Test 72, from line 427"- constTest (P.splitFileName "file/bob.txt" == ( "file/" , "bob.txt" ))- putStrLn "Test 73, from line 428"- constTest (W.splitFileName "file/" == ( "file/" , "" ))- putStrLn "Test 74, from line 428"- constTest (P.splitFileName "file/" == ( "file/" , "" ))- putStrLn "Test 75, from line 429"- constTest (W.splitFileName "bob" == ( "./" , "bob" ))-block4 = do- putStrLn "Test 76, from line 429"- constTest (P.splitFileName "bob" == ( "./" , "bob" ))- putStrLn "Test 77, from line 430"- constTest (P.splitFileName "/" == ( "/" , "" ))- putStrLn "Test 78, from line 431"- constTest (W.splitFileName "c:" == ( "c:" , "" ))- putStrLn "Test 79, from line 464"- constTest (W.takeFileName "test/" == "")- putStrLn "Test 80, from line 464"- constTest (P.takeFileName "test/" == "")- putStrLn "Test 81, from line 475"- constTest (W.takeBaseName "file/test.txt" == "test")- putStrLn "Test 82, from line 475"- constTest (P.takeBaseName "file/test.txt" == "test")- putStrLn "Test 83, from line 476"- constTest (W.takeBaseName "dave.ext" == "dave")- putStrLn "Test 84, from line 476"- constTest (P.takeBaseName "dave.ext" == "dave")- putStrLn "Test 85, from line 477"- constTest (W.takeBaseName "" == "")- putStrLn "Test 86, from line 477"- constTest (P.takeBaseName "" == "")- putStrLn "Test 87, from line 478"- constTest (W.takeBaseName "test" == "test")- putStrLn "Test 88, from line 478"- constTest (P.takeBaseName "test" == "test")- putStrLn "Test 89, from line 480"- constTest (W.takeBaseName "file/file.tar.gz" == "file.tar")- putStrLn "Test 90, from line 480"- constTest (P.takeBaseName "file/file.tar.gz" == "file.tar")- putStrLn "Test 91, from line 486"- constTest (W.replaceBaseName "file/test.txt" "bob" == "file/bob.txt")- putStrLn "Test 92, from line 486"- constTest (P.replaceBaseName "file/test.txt" "bob" == "file/bob.txt")- putStrLn "Test 93, from line 487"- constTest (W.replaceBaseName "fred" "bill" == "bill")- putStrLn "Test 94, from line 487"- constTest (P.replaceBaseName "fred" "bill" == "bill")- putStrLn "Test 95, from line 488"- constTest (W.replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar")- putStrLn "Test 96, from line 488"- constTest (P.replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar")- putStrLn "Test 97, from line 498"- constTest (W.hasTrailingPathSeparator "test" == False)- putStrLn "Test 98, from line 498"- constTest (P.hasTrailingPathSeparator "test" == False)- putStrLn "Test 99, from line 499"- constTest (W.hasTrailingPathSeparator "test/" == True)- putStrLn "Test 100, from line 499"- constTest (P.hasTrailingPathSeparator "test/" == True)-block5 = do- putStrLn "Test 101, from line 509"- constTest (P.addTrailingPathSeparator "test/rest" == "test/rest/")- putStrLn "Test 102, from line 516"- constTest (W.dropTrailingPathSeparator "file/test/" == "file/test")- putStrLn "Test 103, from line 516"- constTest (P.dropTrailingPathSeparator "file/test/" == "file/test")- putStrLn "Test 104, from line 518"- constTest (P.dropTrailingPathSeparator "/" == "/")- putStrLn "Test 105, from line 519"- constTest (W.dropTrailingPathSeparator "\\" == "\\")- putStrLn "Test 106, from line 531"- constTest (W.takeDirectory "foo" == ".")- putStrLn "Test 107, from line 531"- constTest (P.takeDirectory "foo" == ".")- putStrLn "Test 108, from line 532"- constTest (W.takeDirectory "/foo/bar/baz" == "/foo/bar")- putStrLn "Test 109, from line 532"- constTest (P.takeDirectory "/foo/bar/baz" == "/foo/bar")- putStrLn "Test 110, from line 533"- constTest (W.takeDirectory "/foo/bar/baz/" == "/foo/bar/baz")- putStrLn "Test 111, from line 533"- constTest (P.takeDirectory "/foo/bar/baz/" == "/foo/bar/baz")- putStrLn "Test 112, from line 534"- constTest (W.takeDirectory "foo/bar/baz" == "foo/bar")- putStrLn "Test 113, from line 534"- constTest (P.takeDirectory "foo/bar/baz" == "foo/bar")- putStrLn "Test 114, from line 535"- constTest (W.takeDirectory "foo\\bar" == "foo")- putStrLn "Test 115, from line 536"- constTest (W.takeDirectory "foo\\bar\\\\" == "foo\\bar")- putStrLn "Test 116, from line 537"- constTest (W.takeDirectory "C:\\" == "C:\\")- putStrLn "Test 117, from line 555"- constTest (P.combine "/" "test" == "/test")- putStrLn "Test 118, from line 556"- constTest (P.combine "home" "bob" == "home/bob")- putStrLn "Test 119, from line 557"- constTest (W.combine "home" "bob" == "home\\bob")- putStrLn "Test 120, from line 558"- constTest (W.combine "home" "/bob" == "/bob")- putStrLn "Test 121, from line 580"- constTest (W.splitPath "test//item/" == [ "test//" , "item/" ])- putStrLn "Test 122, from line 580"- constTest (P.splitPath "test//item/" == [ "test//" , "item/" ])- putStrLn "Test 123, from line 581"- constTest (W.splitPath "test/item/file" == [ "test/" , "item/" , "file" ])- putStrLn "Test 124, from line 581"- constTest (P.splitPath "test/item/file" == [ "test/" , "item/" , "file" ])- putStrLn "Test 125, from line 582"- constTest (W.splitPath "" == [ ])-block6 = do- putStrLn "Test 126, from line 582"- constTest (P.splitPath "" == [ ])- putStrLn "Test 127, from line 583"- constTest (W.splitPath "c:\\test\\path" == [ "c:\\" , "test\\" , "path" ])- putStrLn "Test 128, from line 584"- constTest (P.splitPath "/file/test" == [ "/" , "file/" , "test" ])- putStrLn "Test 129, from line 598"- constTest (W.splitDirectories "test/file" == [ "test" , "file" ])- putStrLn "Test 130, from line 598"- constTest (P.splitDirectories "test/file" == [ "test" , "file" ])- putStrLn "Test 131, from line 599"- constTest (W.splitDirectories "/test/file" == [ "/" , "test" , "file" ])- putStrLn "Test 132, from line 599"- constTest (P.splitDirectories "/test/file" == [ "/" , "test" , "file" ])- putStrLn "Test 133, from line 601"- constTest (W.splitDirectories "" == [ ])- putStrLn "Test 134, from line 601"- constTest (P.splitDirectories "" == [ ])- putStrLn "Test 135, from line 617"- constTest (W.joinPath [ ] == "")- putStrLn "Test 136, from line 617"- constTest (P.joinPath [ ] == "")- putStrLn "Test 137, from line 618"- constTest (P.joinPath [ "test" , "file" , "path" ] == "test/file/path")- putStrLn "Test 138, from line 639"- constTest (P.equalFilePath "foo" "foo/")- putStrLn "Test 139, from line 640"- constTest (not ( P.equalFilePath "foo" "/foo" ))- putStrLn "Test 140, from line 641"- constTest (not ( P.equalFilePath "foo" "FOO" ))- putStrLn "Test 141, from line 642"- constTest (W.equalFilePath "foo" "FOO")- putStrLn "Test 142, from line 661"- constTest (W.makeRelative "C:\\Home" "c:\\home\\bob" == "bob")- putStrLn "Test 143, from line 662"- constTest (W.makeRelative "C:\\Home" "c:/home/bob" == "bob")- putStrLn "Test 144, from line 663"- constTest (W.makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob")- putStrLn "Test 145, from line 664"- constTest (W.makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob")- putStrLn "Test 146, from line 665"- constTest (W.makeRelative "/Home" "/home/bob" == "bob")- putStrLn "Test 147, from line 666"- constTest (P.makeRelative "/Home" "/home/bob" == "/home/bob")- putStrLn "Test 148, from line 667"- constTest (P.makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar")- putStrLn "Test 149, from line 668"- constTest (P.makeRelative "/fred" "bob" == "bob")- putStrLn "Test 150, from line 669"- constTest (P.makeRelative "/file/test" "/file/test/fred" == "fred")-block7 = do- putStrLn "Test 151, from line 670"- constTest (P.makeRelative "/file/test" "/file/test/fred/" == "fred/")- putStrLn "Test 152, from line 671"- constTest (P.makeRelative "some/path" "some/path/a/b/c" == "a/b/c")- putStrLn "Test 153, from line 701"- constTest (P.normalise "/file/\\test////" == "/file/\\test/")- putStrLn "Test 154, from line 702"- constTest (P.normalise "/file/./test" == "/file/test")- putStrLn "Test 155, from line 703"- constTest (P.normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/")- putStrLn "Test 156, from line 704"- constTest (P.normalise "../bob/fred/" == "../bob/fred/")- putStrLn "Test 157, from line 705"- constTest (P.normalise "./bob/fred/" == "bob/fred/")- putStrLn "Test 158, from line 706"- constTest (W.normalise "c:\\file/bob\\" == "C:\\file\\bob\\")- putStrLn "Test 159, from line 707"- constTest (W.normalise "c:\\" == "C:\\")- putStrLn "Test 160, from line 708"- constTest (W.normalise "\\\\server\\test" == "\\\\server\\test")- putStrLn "Test 161, from line 709"- constTest (W.normalise "c:/file" == "C:\\file")- putStrLn "Test 162, from line 710"- constTest (W.normalise "." == ".")- putStrLn "Test 163, from line 710"- constTest (P.normalise "." == ".")- putStrLn "Test 164, from line 711"- constTest (P.normalise "./" == "./")- putStrLn "Test 165, from line 712"- constTest (P.normalise "./." == "./")- putStrLn "Test 166, from line 713"- constTest (P.normalise "/" == "/")- putStrLn "Test 167, from line 714"- constTest (P.normalise "bob/fred/." == "bob/fred/")- putStrLn "Test 168, from line 759"- constTest (W.isValid "" == False)- putStrLn "Test 169, from line 759"- constTest (P.isValid "" == False)- putStrLn "Test 170, from line 760"- constTest (P.isValid "/random_ path:*" == True)- putStrLn "Test 171, from line 762"- constTest (W.isValid "c:\\test" == True)- putStrLn "Test 172, from line 763"- constTest (W.isValid "c:\\test:of_test" == False)- putStrLn "Test 173, from line 764"- constTest (W.isValid "test*" == False)- putStrLn "Test 174, from line 765"- constTest (W.isValid "c:\\test\\nul" == False)- putStrLn "Test 175, from line 766"- constTest (W.isValid "c:\\test\\prn.txt" == False)-block8 = do- putStrLn "Test 176, from line 767"- constTest (W.isValid "c:\\nul\\file" == False)- putStrLn "Test 177, from line 768"- constTest (W.isValid "\\\\" == False)- putStrLn "Test 178, from line 785"- constTest (W.makeValid "" == "_")- putStrLn "Test 179, from line 785"- constTest (P.makeValid "" == "_")- putStrLn "Test 180, from line 786"- constTest (W.makeValid "c:\\test:of_test" == "c:\\test_of_test")- putStrLn "Test 181, from line 787"- constTest (W.makeValid "test*" == "test_")- putStrLn "Test 182, from line 788"- constTest (W.makeValid "c:\\test\\nul" == "c:\\test\\nul_")- putStrLn "Test 183, from line 789"- constTest (W.makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt")- putStrLn "Test 184, from line 790"- constTest (W.makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt")- putStrLn "Test 185, from line 791"- constTest (W.makeValid "c:\\nul\\file" == "c:\\nul_\\file")- putStrLn "Test 186, from line 813"- constTest (W.isRelative "path\\test" == True)- putStrLn "Test 187, from line 814"- constTest (W.isRelative "c:\\test" == False)- putStrLn "Test 188, from line 815"- constTest (W.isRelative "c:test" == True)- putStrLn "Test 189, from line 816"- constTest (W.isRelative "c:" == True)- putStrLn "Test 190, from line 817"- constTest (W.isRelative "\\\\foo" == False)- putStrLn "Test 191, from line 818"- constTest (W.isRelative "/foo" == True)- putStrLn "Test 192, from line 819"- constTest (P.isRelative "test/path" == True)- putStrLn "Test 193, from line 820"- constTest (P.isRelative "/test" == False)- putStrLn "Test 194, from line 139"- quickSafe (\ a -> (W.isPathSeparator a == ( a ` elem ` W.pathSeparators )))- putStrLn "Test 195, from line 139"- quickSafe (\ a -> (P.isPathSeparator a == ( a ` elem ` P.pathSeparators )))- putStrLn "Test 196, from line 153"- quickSafe (\ a -> (W.isSearchPathSeparator a == ( a == W.searchPathSeparator )))- putStrLn "Test 197, from line 153"- quickSafe (\ a -> (P.isSearchPathSeparator a == ( a == P.searchPathSeparator )))- putStrLn "Test 198, from line 166"- quickSafe (\ a -> (W.isExtSeparator a == ( a == W.extSeparator )))- putStrLn "Test 199, from line 166"- quickSafe (\ a -> (P.isExtSeparator a == ( a == P.extSeparator )))- putStrLn "Test 200, from line 206"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( W.splitExtension x ) == x))-block9 = do- putStrLn "Test 201, from line 206"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( P.splitExtension x ) == x))- putStrLn "Test 202, from line 207"- quickSafe (\ (QFilePath x) -> (uncurry W.addExtension ( W.splitExtension x ) == x))- putStrLn "Test 203, from line 207"- quickSafe (\ (QFilePath x) -> (uncurry P.addExtension ( P.splitExtension x ) == x))- putStrLn "Test 204, from line 225"- quickSafe (\ (QFilePath x) -> (W.takeExtension x == snd ( W.splitExtension x )))- putStrLn "Test 205, from line 225"- quickSafe (\ (QFilePath x) -> (P.takeExtension x == snd ( P.splitExtension x )))- putStrLn "Test 206, from line 226"- quickSafe (\ (QFilePath x) -> ((\ x -> W.takeExtension ( W.addExtension x "ext" ) == ".ext" ) ( W.makeValid x )))- putStrLn "Test 207, from line 226"- quickSafe (\ (QFilePath x) -> ((\ x -> P.takeExtension ( P.addExtension x "ext" ) == ".ext" ) ( P.makeValid x )))- putStrLn "Test 208, from line 227"- quickSafe (\ (QFilePath x) -> ((\ x -> W.takeExtension ( W.replaceExtension x "ext" ) == ".ext" ) ( W.makeValid x )))- putStrLn "Test 209, from line 227"- quickSafe (\ (QFilePath x) -> ((\ x -> P.takeExtension ( P.replaceExtension x "ext" ) == ".ext" ) ( P.makeValid x )))- putStrLn "Test 210, from line 247"- quickSafe (\ (QFilePath x) -> (W.dropExtension x == fst ( W.splitExtension x )))- putStrLn "Test 211, from line 247"- quickSafe (\ (QFilePath x) -> (P.dropExtension x == fst ( P.splitExtension x )))- putStrLn "Test 212, from line 258"- quickSafe (\ (QFilePath x) -> ((\ x -> W.takeFileName ( W.addExtension ( W.addTrailingPathSeparator x ) "ext" ) == ".ext" ) ( W.makeValid x )))- putStrLn "Test 213, from line 258"- quickSafe (\ (QFilePath x) -> ((\ x -> P.takeFileName ( P.addExtension ( P.addTrailingPathSeparator x ) "ext" ) == ".ext" ) ( P.makeValid x )))- putStrLn "Test 214, from line 271"- quickSafe (\ (QFilePath x) -> (null ( W.takeExtension x ) == not ( W.hasExtension x )))- putStrLn "Test 215, from line 271"- quickSafe (\ (QFilePath x) -> (null ( P.takeExtension x ) == not ( P.hasExtension x )))- putStrLn "Test 216, from line 278"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( W.splitExtensions x ) == x))- putStrLn "Test 217, from line 278"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( P.splitExtensions x ) == x))- putStrLn "Test 218, from line 279"- quickSafe (\ (QFilePath x) -> (uncurry W.addExtension ( W.splitExtensions x ) == x))- putStrLn "Test 219, from line 279"- quickSafe (\ (QFilePath x) -> (uncurry P.addExtension ( P.splitExtensions x ) == x))- putStrLn "Test 220, from line 289"- quickSafe (\ (QFilePath x) -> (not $ W.hasExtension ( W.dropExtensions x )))- putStrLn "Test 221, from line 289"- quickSafe (\ (QFilePath x) -> (not $ P.hasExtension ( P.dropExtensions x )))- putStrLn "Test 222, from line 313"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( W.splitDrive x ) == x))- putStrLn "Test 223, from line 313"- quickSafe (\ (QFilePath x) -> (uncurry ( ++ ) ( P.splitDrive x ) == x))- putStrLn "Test 224, from line 382"- quickSafe (\ (QFilePath x) -> (uncurry W.joinDrive ( W.splitDrive x ) == x))- putStrLn "Test 225, from line 382"- quickSafe (\ (QFilePath x) -> (uncurry P.joinDrive ( P.splitDrive x ) == x))-block10 = do- putStrLn "Test 226, from line 398"- quickSafe (\ (QFilePath x) -> (W.takeDrive x == fst ( W.splitDrive x )))- putStrLn "Test 227, from line 398"- quickSafe (\ (QFilePath x) -> (P.takeDrive x == fst ( P.splitDrive x )))- putStrLn "Test 228, from line 404"- quickSafe (\ (QFilePath x) -> (W.dropDrive x == snd ( W.splitDrive x )))- putStrLn "Test 229, from line 404"- quickSafe (\ (QFilePath x) -> (P.dropDrive x == snd ( P.splitDrive x )))- putStrLn "Test 230, from line 410"- quickSafe (\ (QFilePath x) -> (not ( W.hasDrive x ) == null ( W.takeDrive x )))- putStrLn "Test 231, from line 410"- quickSafe (\ (QFilePath x) -> (not ( P.hasDrive x ) == null ( P.takeDrive x )))- putStrLn "Test 232, from line 425"- quickSafe (\ (QFilePath x) -> ((\ x -> uncurry ( W.</> ) ( W.splitFileName x ) == x || fst ( W.splitFileName x ) == "./" ) ( W.makeValid x )))- putStrLn "Test 233, from line 425"- quickSafe (\ (QFilePath x) -> ((\ x -> uncurry ( P.</> ) ( P.splitFileName x ) == x || fst ( P.splitFileName x ) == "./" ) ( P.makeValid x )))- putStrLn "Test 234, from line 426"- quickSafe (\ (QFilePath x) -> ((\ x -> W.isValid ( fst ( W.splitFileName x ) ) ) ( W.makeValid x )))- putStrLn "Test 235, from line 426"- quickSafe (\ (QFilePath x) -> ((\ x -> P.isValid ( fst ( P.splitFileName x ) ) ) ( P.makeValid x )))- putStrLn "Test 236, from line 451"- quickSafe (\ (QFilePath x) -> ((\ x -> W.replaceFileName x ( W.takeFileName x ) == x ) ( W.makeValid x )))- putStrLn "Test 237, from line 451"- quickSafe (\ (QFilePath x) -> ((\ x -> P.replaceFileName x ( P.takeFileName x ) == x ) ( P.makeValid x )))- putStrLn "Test 238, from line 457"- quickSafe (\ (QFilePath x) -> (W.dropFileName x == fst ( W.splitFileName x )))- putStrLn "Test 239, from line 457"- quickSafe (\ (QFilePath x) -> (P.dropFileName x == fst ( P.splitFileName x )))- putStrLn "Test 240, from line 465"- quickSafe (\ (QFilePath x) -> (W.takeFileName x ` isSuffixOf ` x))- putStrLn "Test 241, from line 465"- quickSafe (\ (QFilePath x) -> (P.takeFileName x ` isSuffixOf ` x))- putStrLn "Test 242, from line 466"- quickSafe (\ (QFilePath x) -> (W.takeFileName x == snd ( W.splitFileName x )))- putStrLn "Test 243, from line 466"- quickSafe (\ (QFilePath x) -> (P.takeFileName x == snd ( P.splitFileName x )))- putStrLn "Test 244, from line 467"- quickSafe (\ (QFilePath x) -> ((\ x -> W.takeFileName ( W.replaceFileName x "fred" ) == "fred" ) ( W.makeValid x )))- putStrLn "Test 245, from line 467"- quickSafe (\ (QFilePath x) -> ((\ x -> P.takeFileName ( P.replaceFileName x "fred" ) == "fred" ) ( P.makeValid x )))- putStrLn "Test 246, from line 468"- quickSafe (\ (QFilePath x) -> ((\ x -> W.takeFileName ( x W.</> "fred" ) == "fred" ) ( W.makeValid x )))- putStrLn "Test 247, from line 468"- quickSafe (\ (QFilePath x) -> ((\ x -> P.takeFileName ( x P.</> "fred" ) == "fred" ) ( P.makeValid x )))- putStrLn "Test 248, from line 469"- quickSafe (\ (QFilePath x) -> ((\ x -> W.isRelative ( W.takeFileName x ) ) ( W.makeValid x )))- putStrLn "Test 249, from line 469"- quickSafe (\ (QFilePath x) -> ((\ x -> P.isRelative ( P.takeFileName x ) ) ( P.makeValid x )))- putStrLn "Test 250, from line 479"- quickSafe (\ (QFilePath x) -> (W.takeBaseName ( W.addTrailingPathSeparator x ) == ""))-block11 = do- putStrLn "Test 251, from line 479"- quickSafe (\ (QFilePath x) -> (P.takeBaseName ( P.addTrailingPathSeparator x ) == ""))- putStrLn "Test 252, from line 489"- quickSafe (\ (QFilePath x) -> ((\ x -> W.replaceBaseName x ( W.takeBaseName x ) == x ) ( W.makeValid x )))- putStrLn "Test 253, from line 489"- quickSafe (\ (QFilePath x) -> ((\ x -> P.replaceBaseName x ( P.takeBaseName x ) == x ) ( P.makeValid x )))- putStrLn "Test 254, from line 507"- quickSafe (\ (QFilePath x) -> (W.hasTrailingPathSeparator ( W.addTrailingPathSeparator x )))- putStrLn "Test 255, from line 507"- quickSafe (\ (QFilePath x) -> (P.hasTrailingPathSeparator ( P.addTrailingPathSeparator x )))- putStrLn "Test 256, from line 508"- quickSafe (\ (QFilePath x) -> (W.hasTrailingPathSeparator x ==> W.addTrailingPathSeparator x == x))- putStrLn "Test 257, from line 508"- quickSafe (\ (QFilePath x) -> (P.hasTrailingPathSeparator x ==> P.addTrailingPathSeparator x == x))- putStrLn "Test 258, from line 517"- quickSafe (\ (QFilePath x) -> (not ( P.hasTrailingPathSeparator ( P.dropTrailingPathSeparator x ) ) || P.isDrive x))- putStrLn "Test 259, from line 530"- quickSafe (\ (QFilePath x) -> (W.takeDirectory x ` isPrefixOf ` x || W.takeDirectory x == "."))- putStrLn "Test 260, from line 530"- quickSafe (\ (QFilePath x) -> (P.takeDirectory x ` isPrefixOf ` x || P.takeDirectory x == "."))- putStrLn "Test 261, from line 547"- quickSafe (\ (QFilePath x) -> ((\ x -> W.replaceDirectory x ( W.takeDirectory x ) ` W.equalFilePath ` x ) ( W.makeValid x )))- putStrLn "Test 262, from line 547"- quickSafe (\ (QFilePath x) -> ((\ x -> P.replaceDirectory x ( P.takeDirectory x ) ` P.equalFilePath ` x ) ( P.makeValid x )))- putStrLn "Test 263, from line 554"- quickSafe (\ (QFilePath x) -> ((\ x -> W.combine ( W.takeDirectory x ) ( W.takeFileName x ) ` W.equalFilePath ` x ) ( W.makeValid x )))- putStrLn "Test 264, from line 554"- quickSafe (\ (QFilePath x) -> ((\ x -> P.combine ( P.takeDirectory x ) ( P.takeFileName x ) ` P.equalFilePath ` x ) ( P.makeValid x )))- putStrLn "Test 265, from line 579"- quickSafe (\ (QFilePath x) -> (concat ( W.splitPath x ) == x))- putStrLn "Test 266, from line 579"- quickSafe (\ (QFilePath x) -> (concat ( P.splitPath x ) == x))- putStrLn "Test 267, from line 600"- quickSafe (\ (QFilePath x) -> ((\ x -> W.joinPath ( W.splitDirectories x ) ` W.equalFilePath ` x ) ( W.makeValid x )))- putStrLn "Test 268, from line 600"- quickSafe (\ (QFilePath x) -> ((\ x -> P.joinPath ( P.splitDirectories x ) ` P.equalFilePath ` x ) ( P.makeValid x )))- putStrLn "Test 269, from line 616"- quickSafe (\ (QFilePath x) -> ((\ x -> W.joinPath ( W.splitPath x ) == x ) ( W.makeValid x )))- putStrLn "Test 270, from line 616"- quickSafe (\ (QFilePath x) -> ((\ x -> P.joinPath ( P.splitPath x ) == x ) ( P.makeValid x )))- putStrLn "Test 271, from line 637"- quickSafe (\ (QFilePath x) (QFilePath y) -> (x == y ==> W.equalFilePath x y))- putStrLn "Test 272, from line 637"- quickSafe (\ (QFilePath x) (QFilePath y) -> (x == y ==> P.equalFilePath x y))- putStrLn "Test 273, from line 638"- quickSafe (\ (QFilePath x) (QFilePath y) -> (W.normalise x == W.normalise y ==> W.equalFilePath x y))- putStrLn "Test 274, from line 638"- quickSafe (\ (QFilePath x) (QFilePath y) -> (P.normalise x == P.normalise y ==> P.equalFilePath x y))- putStrLn "Test 275, from line 658"- quickSafe (\ (QFilePath x) (QFilePath y) -> ((\ y -> W.equalFilePath x y || ( W.isRelative x && W.makeRelative y x == x ) || W.equalFilePath ( y W.</> W.makeRelative y x ) x ) ( W.makeValid y )))-block12 = do- putStrLn "Test 276, from line 658"- quickSafe (\ (QFilePath x) (QFilePath y) -> ((\ y -> P.equalFilePath x y || ( P.isRelative x && P.makeRelative y x == x ) || P.equalFilePath ( y P.</> P.makeRelative y x ) x ) ( P.makeValid y )))- putStrLn "Test 277, from line 659"- quickSafe (\ (QFilePath x) -> (W.makeRelative x x == "."))- putStrLn "Test 278, from line 659"- quickSafe (\ (QFilePath x) -> (P.makeRelative x x == "."))- putStrLn "Test 279, from line 660"- quickSafe (\ (QFilePath x) (QFilePath y) -> (null y || W.equalFilePath ( W.makeRelative x ( x W.</> y ) ) y || null ( W.takeFileName x )))- putStrLn "Test 280, from line 660"- quickSafe (\ (QFilePath x) (QFilePath y) -> (null y || P.equalFilePath ( P.makeRelative x ( x P.</> y ) ) y || null ( P.takeFileName x )))- putStrLn "Test 281, from line 761"- quickSafe (\ (QFilePath x) -> (P.isValid x == not ( null x )))- putStrLn "Test 282, from line 783"- quickSafe (\ (QFilePath x) -> (W.isValid ( W.makeValid x )))- putStrLn "Test 283, from line 783"- quickSafe (\ (QFilePath x) -> (P.isValid ( P.makeValid x )))- putStrLn "Test 284, from line 784"- quickSafe (\ (QFilePath x) -> (W.isValid x ==> W.makeValid x == x))- putStrLn "Test 285, from line 784"- quickSafe (\ (QFilePath x) -> (P.isValid x ==> P.makeValid x == x))- putStrLn "Test 286, from line 840"- quickSafe (\ (QFilePath x) -> (W.isAbsolute x == not ( W.isRelative x )))- putStrLn "Test 287, from line 840"- quickSafe (\ (QFilePath x) -> (P.isAbsolute x == not ( P.isRelative x )))
+ tests/Test.hs view
@@ -0,0 +1,30 @@++module Test(main) where++import System.Environment+import TestGen+import Control.Monad+import Data.Maybe+import Test.QuickCheck+++main :: IO ()+main = do+    args <- getArgs+    let count = case args of i:_ -> read i; _ -> 10000+    putStrLn $ "Testing with " ++ show count ++ " repetitions"+    let total = length tests+    let showOutput x = show x{output=""} ++ "\n" ++ output x+    bad <- fmap catMaybes $ forM (zip [1..] tests) $ \(i,(msg,prop)) -> do+        putStrLn $ "Test " ++ show i ++ " of " ++ show total ++ ": " ++ msg+        res <- quickCheckWithResult stdArgs{chatty=False, maxSuccess=count} prop+        case res of+            Success{} -> return Nothing+            bad -> do putStrLn $ showOutput bad; putStrLn "TEST FAILURE!"; return $ Just (msg,bad)+    if null bad then+        putStrLn $ "Success, " ++ show total ++ " tests passed"+     else do+        putStrLn $ show (length bad) ++ " FAILURES\n"+        forM_ (zip [1..] bad) $ \(i,(a,b)) ->+            putStrLn $ "FAILURE " ++ show i ++ ": " ++ a ++ "\n" ++ showOutput b ++ "\n"+        fail $ "FAILURE, failed " ++ show (length bad) ++ " of " ++ show total ++ " tests"
+ tests/TestGen.hs view
@@ -0,0 +1,414 @@+-- GENERATED CODE: See ../Generate.hs+module TestGen(tests) where+import TestUtil+import qualified System.FilePath.Windows as W+import qualified System.FilePath.Posix as P+tests :: [(String, Test)]+tests =+    [("W.pathSeparator == '\\\\'", test $ W.pathSeparator == '\\')+    ,("P.pathSeparator == '/'", test $ P.pathSeparator == '/')+    ,("P.isPathSeparator P.pathSeparator", test $ P.isPathSeparator P.pathSeparator)+    ,("W.isPathSeparator W.pathSeparator", test $ W.isPathSeparator W.pathSeparator)+    ,("W.pathSeparators == ['\\\\', '/']", test $ W.pathSeparators == ['\\', '/'])+    ,("P.pathSeparators == ['/']", test $ P.pathSeparators == ['/'])+    ,("P.pathSeparator `elem` P.pathSeparators", test $ P.pathSeparator `elem` P.pathSeparators)+    ,("W.pathSeparator `elem` W.pathSeparators", test $ W.pathSeparator `elem` W.pathSeparators)+    ,("P.isPathSeparator a == (a `elem` P.pathSeparators)", test $ \a -> P.isPathSeparator a == (a `elem` P.pathSeparators))+    ,("W.isPathSeparator a == (a `elem` W.pathSeparators)", test $ \a -> W.isPathSeparator a == (a `elem` W.pathSeparators))+    ,("W.searchPathSeparator == ';'", test $ W.searchPathSeparator == ';')+    ,("P.searchPathSeparator == ':'", test $ P.searchPathSeparator == ':')+    ,("P.isSearchPathSeparator a == (a == P.searchPathSeparator)", test $ \a -> P.isSearchPathSeparator a == (a == P.searchPathSeparator))+    ,("W.isSearchPathSeparator a == (a == W.searchPathSeparator)", test $ \a -> W.isSearchPathSeparator a == (a == W.searchPathSeparator))+    ,("P.extSeparator == '.'", test $ P.extSeparator == '.')+    ,("W.extSeparator == '.'", test $ W.extSeparator == '.')+    ,("P.isExtSeparator a == (a == P.extSeparator)", test $ \a -> P.isExtSeparator a == (a == P.extSeparator))+    ,("W.isExtSeparator a == (a == W.extSeparator)", test $ \a -> W.isExtSeparator a == (a == W.extSeparator))+    ,("P.splitSearchPath \"File1:File2:File3\" == [\"File1\", \"File2\", \"File3\"]", test $ P.splitSearchPath "File1:File2:File3" == ["File1", "File2", "File3"])+    ,("P.splitSearchPath \"File1::File2:File3\" == [\"File1\", \".\", \"File2\", \"File3\"]", test $ P.splitSearchPath "File1::File2:File3" == ["File1", ".", "File2", "File3"])+    ,("W.splitSearchPath \"File1;File2;File3\" == [\"File1\", \"File2\", \"File3\"]", test $ W.splitSearchPath "File1;File2;File3" == ["File1", "File2", "File3"])+    ,("W.splitSearchPath \"File1;;File2;File3\" == [\"File1\", \"File2\", \"File3\"]", test $ W.splitSearchPath "File1;;File2;File3" == ["File1", "File2", "File3"])+    ,("W.splitSearchPath \"File1;\\\"File2\\\";File3\" == [\"File1\", \"File2\", \"File3\"]", test $ W.splitSearchPath "File1;\"File2\";File3" == ["File1", "File2", "File3"])+    ,("P.splitExtension \"/directory/path.ext\" == (\"/directory/path\", \".ext\")", test $ P.splitExtension "/directory/path.ext" == ("/directory/path", ".ext"))+    ,("W.splitExtension \"/directory/path.ext\" == (\"/directory/path\", \".ext\")", test $ W.splitExtension "/directory/path.ext" == ("/directory/path", ".ext"))+    ,("uncurry (++) (P.splitExtension x) == x", test $ \(QFilePath x) -> uncurry (++) (P.splitExtension x) == x)+    ,("uncurry (++) (W.splitExtension x) == x", test $ \(QFilePath x) -> uncurry (++) (W.splitExtension x) == x)+    ,("uncurry P.addExtension (P.splitExtension x) == x", test $ \(QFilePathValidP x) -> uncurry P.addExtension (P.splitExtension x) == x)+    ,("uncurry W.addExtension (W.splitExtension x) == x", test $ \(QFilePathValidW x) -> uncurry W.addExtension (W.splitExtension x) == x)+    ,("P.splitExtension \"file.txt\" == (\"file\", \".txt\")", test $ P.splitExtension "file.txt" == ("file", ".txt"))+    ,("W.splitExtension \"file.txt\" == (\"file\", \".txt\")", test $ W.splitExtension "file.txt" == ("file", ".txt"))+    ,("P.splitExtension \"file\" == (\"file\", \"\")", test $ P.splitExtension "file" == ("file", ""))+    ,("W.splitExtension \"file\" == (\"file\", \"\")", test $ W.splitExtension "file" == ("file", ""))+    ,("P.splitExtension \"file/file.txt\" == (\"file/file\", \".txt\")", test $ P.splitExtension "file/file.txt" == ("file/file", ".txt"))+    ,("W.splitExtension \"file/file.txt\" == (\"file/file\", \".txt\")", test $ W.splitExtension "file/file.txt" == ("file/file", ".txt"))+    ,("P.splitExtension \"file.txt/boris\" == (\"file.txt/boris\", \"\")", test $ P.splitExtension "file.txt/boris" == ("file.txt/boris", ""))+    ,("W.splitExtension \"file.txt/boris\" == (\"file.txt/boris\", \"\")", test $ W.splitExtension "file.txt/boris" == ("file.txt/boris", ""))+    ,("P.splitExtension \"file.txt/boris.ext\" == (\"file.txt/boris\", \".ext\")", test $ P.splitExtension "file.txt/boris.ext" == ("file.txt/boris", ".ext"))+    ,("W.splitExtension \"file.txt/boris.ext\" == (\"file.txt/boris\", \".ext\")", test $ W.splitExtension "file.txt/boris.ext" == ("file.txt/boris", ".ext"))+    ,("P.splitExtension \"file/path.txt.bob.fred\" == (\"file/path.txt.bob\", \".fred\")", test $ P.splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob", ".fred"))+    ,("W.splitExtension \"file/path.txt.bob.fred\" == (\"file/path.txt.bob\", \".fred\")", test $ W.splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob", ".fred"))+    ,("P.splitExtension \"file/path.txt/\" == (\"file/path.txt/\", \"\")", test $ P.splitExtension "file/path.txt/" == ("file/path.txt/", ""))+    ,("W.splitExtension \"file/path.txt/\" == (\"file/path.txt/\", \"\")", test $ W.splitExtension "file/path.txt/" == ("file/path.txt/", ""))+    ,("P.takeExtension \"/directory/path.ext\" == \".ext\"", test $ P.takeExtension "/directory/path.ext" == ".ext")+    ,("W.takeExtension \"/directory/path.ext\" == \".ext\"", test $ W.takeExtension "/directory/path.ext" == ".ext")+    ,("P.takeExtension x == snd (P.splitExtension x)", test $ \(QFilePath x) -> P.takeExtension x == snd (P.splitExtension x))+    ,("W.takeExtension x == snd (W.splitExtension x)", test $ \(QFilePath x) -> W.takeExtension x == snd (W.splitExtension x))+    ,("P.takeExtension (P.addExtension x \"ext\") == \".ext\"", test $ \(QFilePathValidP x) -> P.takeExtension (P.addExtension x "ext") == ".ext")+    ,("W.takeExtension (W.addExtension x \"ext\") == \".ext\"", test $ \(QFilePathValidW x) -> W.takeExtension (W.addExtension x "ext") == ".ext")+    ,("P.takeExtension (P.replaceExtension x \"ext\") == \".ext\"", test $ \(QFilePathValidP x) -> P.takeExtension (P.replaceExtension x "ext") == ".ext")+    ,("W.takeExtension (W.replaceExtension x \"ext\") == \".ext\"", test $ \(QFilePathValidW x) -> W.takeExtension (W.replaceExtension x "ext") == ".ext")+    ,("\"/directory/path.txt\" P.-<.> \"ext\" == \"/directory/path.ext\"", test $ "/directory/path.txt" P.-<.> "ext" == "/directory/path.ext")+    ,("\"/directory/path.txt\" W.-<.> \"ext\" == \"/directory/path.ext\"", test $ "/directory/path.txt" W.-<.> "ext" == "/directory/path.ext")+    ,("\"/directory/path.txt\" P.-<.> \".ext\" == \"/directory/path.ext\"", test $ "/directory/path.txt" P.-<.> ".ext" == "/directory/path.ext")+    ,("\"/directory/path.txt\" W.-<.> \".ext\" == \"/directory/path.ext\"", test $ "/directory/path.txt" W.-<.> ".ext" == "/directory/path.ext")+    ,("\"foo.o\" P.-<.> \"c\" == \"foo.c\"", test $ "foo.o" P.-<.> "c" == "foo.c")+    ,("\"foo.o\" W.-<.> \"c\" == \"foo.c\"", test $ "foo.o" W.-<.> "c" == "foo.c")+    ,("P.replaceExtension \"/directory/path.txt\" \"ext\" == \"/directory/path.ext\"", test $ P.replaceExtension "/directory/path.txt" "ext" == "/directory/path.ext")+    ,("W.replaceExtension \"/directory/path.txt\" \"ext\" == \"/directory/path.ext\"", test $ W.replaceExtension "/directory/path.txt" "ext" == "/directory/path.ext")+    ,("P.replaceExtension \"/directory/path.txt\" \".ext\" == \"/directory/path.ext\"", test $ P.replaceExtension "/directory/path.txt" ".ext" == "/directory/path.ext")+    ,("W.replaceExtension \"/directory/path.txt\" \".ext\" == \"/directory/path.ext\"", test $ W.replaceExtension "/directory/path.txt" ".ext" == "/directory/path.ext")+    ,("P.replaceExtension \"file.txt\" \".bob\" == \"file.bob\"", test $ P.replaceExtension "file.txt" ".bob" == "file.bob")+    ,("W.replaceExtension \"file.txt\" \".bob\" == \"file.bob\"", test $ W.replaceExtension "file.txt" ".bob" == "file.bob")+    ,("P.replaceExtension \"file.txt\" \"bob\" == \"file.bob\"", test $ P.replaceExtension "file.txt" "bob" == "file.bob")+    ,("W.replaceExtension \"file.txt\" \"bob\" == \"file.bob\"", test $ W.replaceExtension "file.txt" "bob" == "file.bob")+    ,("P.replaceExtension \"file\" \".bob\" == \"file.bob\"", test $ P.replaceExtension "file" ".bob" == "file.bob")+    ,("W.replaceExtension \"file\" \".bob\" == \"file.bob\"", test $ W.replaceExtension "file" ".bob" == "file.bob")+    ,("P.replaceExtension \"file.txt\" \"\" == \"file\"", test $ P.replaceExtension "file.txt" "" == "file")+    ,("W.replaceExtension \"file.txt\" \"\" == \"file\"", test $ W.replaceExtension "file.txt" "" == "file")+    ,("P.replaceExtension \"file.fred.bob\" \"txt\" == \"file.fred.txt\"", test $ P.replaceExtension "file.fred.bob" "txt" == "file.fred.txt")+    ,("W.replaceExtension \"file.fred.bob\" \"txt\" == \"file.fred.txt\"", test $ W.replaceExtension "file.fred.bob" "txt" == "file.fred.txt")+    ,("P.replaceExtension x y == P.addExtension (P.dropExtension x) y", test $ \(QFilePath x) (QFilePath y) -> P.replaceExtension x y == P.addExtension (P.dropExtension x) y)+    ,("W.replaceExtension x y == W.addExtension (W.dropExtension x) y", test $ \(QFilePath x) (QFilePath y) -> W.replaceExtension x y == W.addExtension (W.dropExtension x) y)+    ,("\"/directory/path\" P.<.> \"ext\" == \"/directory/path.ext\"", test $ "/directory/path" P.<.> "ext" == "/directory/path.ext")+    ,("\"/directory/path\" W.<.> \"ext\" == \"/directory/path.ext\"", test $ "/directory/path" W.<.> "ext" == "/directory/path.ext")+    ,("\"/directory/path\" P.<.> \".ext\" == \"/directory/path.ext\"", test $ "/directory/path" P.<.> ".ext" == "/directory/path.ext")+    ,("\"/directory/path\" W.<.> \".ext\" == \"/directory/path.ext\"", test $ "/directory/path" W.<.> ".ext" == "/directory/path.ext")+    ,("P.dropExtension \"/directory/path.ext\" == \"/directory/path\"", test $ P.dropExtension "/directory/path.ext" == "/directory/path")+    ,("W.dropExtension \"/directory/path.ext\" == \"/directory/path\"", test $ W.dropExtension "/directory/path.ext" == "/directory/path")+    ,("P.dropExtension x == fst (P.splitExtension x)", test $ \(QFilePath x) -> P.dropExtension x == fst (P.splitExtension x))+    ,("W.dropExtension x == fst (W.splitExtension x)", test $ \(QFilePath x) -> W.dropExtension x == fst (W.splitExtension x))+    ,("P.addExtension \"/directory/path\" \"ext\" == \"/directory/path.ext\"", test $ P.addExtension "/directory/path" "ext" == "/directory/path.ext")+    ,("W.addExtension \"/directory/path\" \"ext\" == \"/directory/path.ext\"", test $ W.addExtension "/directory/path" "ext" == "/directory/path.ext")+    ,("P.addExtension \"file.txt\" \"bib\" == \"file.txt.bib\"", test $ P.addExtension "file.txt" "bib" == "file.txt.bib")+    ,("W.addExtension \"file.txt\" \"bib\" == \"file.txt.bib\"", test $ W.addExtension "file.txt" "bib" == "file.txt.bib")+    ,("P.addExtension \"file.\" \".bib\" == \"file..bib\"", test $ P.addExtension "file." ".bib" == "file..bib")+    ,("W.addExtension \"file.\" \".bib\" == \"file..bib\"", test $ W.addExtension "file." ".bib" == "file..bib")+    ,("P.addExtension \"file\" \".bib\" == \"file.bib\"", test $ P.addExtension "file" ".bib" == "file.bib")+    ,("W.addExtension \"file\" \".bib\" == \"file.bib\"", test $ W.addExtension "file" ".bib" == "file.bib")+    ,("P.addExtension \"/\" \"x\" == \"/.x\"", test $ P.addExtension "/" "x" == "/.x")+    ,("W.addExtension \"/\" \"x\" == \"/.x\"", test $ W.addExtension "/" "x" == "/.x")+    ,("P.takeFileName (P.addExtension (P.addTrailingPathSeparator x) \"ext\") == \".ext\"", test $ \(QFilePathValidP x) -> P.takeFileName (P.addExtension (P.addTrailingPathSeparator x) "ext") == ".ext")+    ,("W.takeFileName (W.addExtension (W.addTrailingPathSeparator x) \"ext\") == \".ext\"", test $ \(QFilePathValidW x) -> W.takeFileName (W.addExtension (W.addTrailingPathSeparator x) "ext") == ".ext")+    ,("W.addExtension \"\\\\\\\\share\" \".txt\" == \"\\\\\\\\share\\\\.txt\"", test $ W.addExtension "\\\\share" ".txt" == "\\\\share\\.txt")+    ,("P.hasExtension \"/directory/path.ext\" == True", test $ P.hasExtension "/directory/path.ext" == True)+    ,("W.hasExtension \"/directory/path.ext\" == True", test $ W.hasExtension "/directory/path.ext" == True)+    ,("P.hasExtension \"/directory/path\" == False", test $ P.hasExtension "/directory/path" == False)+    ,("W.hasExtension \"/directory/path\" == False", test $ W.hasExtension "/directory/path" == False)+    ,("null (P.takeExtension x) == not (P.hasExtension x)", test $ \(QFilePath x) -> null (P.takeExtension x) == not (P.hasExtension x))+    ,("null (W.takeExtension x) == not (W.hasExtension x)", test $ \(QFilePath x) -> null (W.takeExtension x) == not (W.hasExtension x))+    ,("P.splitExtensions \"/directory/path.ext\" == (\"/directory/path\", \".ext\")", test $ P.splitExtensions "/directory/path.ext" == ("/directory/path", ".ext"))+    ,("W.splitExtensions \"/directory/path.ext\" == (\"/directory/path\", \".ext\")", test $ W.splitExtensions "/directory/path.ext" == ("/directory/path", ".ext"))+    ,("P.splitExtensions \"file.tar.gz\" == (\"file\", \".tar.gz\")", test $ P.splitExtensions "file.tar.gz" == ("file", ".tar.gz"))+    ,("W.splitExtensions \"file.tar.gz\" == (\"file\", \".tar.gz\")", test $ W.splitExtensions "file.tar.gz" == ("file", ".tar.gz"))+    ,("uncurry (++) (P.splitExtensions x) == x", test $ \(QFilePath x) -> uncurry (++) (P.splitExtensions x) == x)+    ,("uncurry (++) (W.splitExtensions x) == x", test $ \(QFilePath x) -> uncurry (++) (W.splitExtensions x) == x)+    ,("uncurry P.addExtension (P.splitExtensions x) == x", test $ \(QFilePathValidP x) -> uncurry P.addExtension (P.splitExtensions x) == x)+    ,("uncurry W.addExtension (W.splitExtensions x) == x", test $ \(QFilePathValidW x) -> uncurry W.addExtension (W.splitExtensions x) == x)+    ,("P.splitExtensions \"file.tar.gz\" == (\"file\", \".tar.gz\")", test $ P.splitExtensions "file.tar.gz" == ("file", ".tar.gz"))+    ,("W.splitExtensions \"file.tar.gz\" == (\"file\", \".tar.gz\")", test $ W.splitExtensions "file.tar.gz" == ("file", ".tar.gz"))+    ,("P.dropExtensions \"/directory/path.ext\" == \"/directory/path\"", test $ P.dropExtensions "/directory/path.ext" == "/directory/path")+    ,("W.dropExtensions \"/directory/path.ext\" == \"/directory/path\"", test $ W.dropExtensions "/directory/path.ext" == "/directory/path")+    ,("P.dropExtensions \"file.tar.gz\" == \"file\"", test $ P.dropExtensions "file.tar.gz" == "file")+    ,("W.dropExtensions \"file.tar.gz\" == \"file\"", test $ W.dropExtensions "file.tar.gz" == "file")+    ,("not $ P.hasExtension $ P.dropExtensions x", test $ \(QFilePath x) -> not $ P.hasExtension $ P.dropExtensions x)+    ,("not $ W.hasExtension $ W.dropExtensions x", test $ \(QFilePath x) -> not $ W.hasExtension $ W.dropExtensions x)+    ,("not $ any P.isExtSeparator $ P.takeFileName $ P.dropExtensions x", test $ \(QFilePath x) -> not $ any P.isExtSeparator $ P.takeFileName $ P.dropExtensions x)+    ,("not $ any W.isExtSeparator $ W.takeFileName $ W.dropExtensions x", test $ \(QFilePath x) -> not $ any W.isExtSeparator $ W.takeFileName $ W.dropExtensions x)+    ,("P.takeExtensions \"/directory/path.ext\" == \".ext\"", test $ P.takeExtensions "/directory/path.ext" == ".ext")+    ,("W.takeExtensions \"/directory/path.ext\" == \".ext\"", test $ W.takeExtensions "/directory/path.ext" == ".ext")+    ,("P.takeExtensions \"file.tar.gz\" == \".tar.gz\"", test $ P.takeExtensions "file.tar.gz" == ".tar.gz")+    ,("W.takeExtensions \"file.tar.gz\" == \".tar.gz\"", test $ W.takeExtensions "file.tar.gz" == ".tar.gz")+    ,("uncurry (++) (P.splitDrive x) == x", test $ \(QFilePath x) -> uncurry (++) (P.splitDrive x) == x)+    ,("uncurry (++) (W.splitDrive x) == x", test $ \(QFilePath x) -> uncurry (++) (W.splitDrive x) == x)+    ,("W.splitDrive \"file\" == (\"\", \"file\")", test $ W.splitDrive "file" == ("", "file"))+    ,("W.splitDrive \"c:/file\" == (\"c:/\", \"file\")", test $ W.splitDrive "c:/file" == ("c:/", "file"))+    ,("W.splitDrive \"c:\\\\file\" == (\"c:\\\\\", \"file\")", test $ W.splitDrive "c:\\file" == ("c:\\", "file"))+    ,("W.splitDrive \"\\\\\\\\shared\\\\test\" == (\"\\\\\\\\shared\\\\\", \"test\")", test $ W.splitDrive "\\\\shared\\test" == ("\\\\shared\\", "test"))+    ,("W.splitDrive \"\\\\\\\\shared\" == (\"\\\\\\\\shared\", \"\")", test $ W.splitDrive "\\\\shared" == ("\\\\shared", ""))+    ,("W.splitDrive \"\\\\\\\\?\\\\UNC\\\\shared\\\\file\" == (\"\\\\\\\\?\\\\UNC\\\\shared\\\\\", \"file\")", test $ W.splitDrive "\\\\?\\UNC\\shared\\file" == ("\\\\?\\UNC\\shared\\", "file"))+    ,("W.splitDrive \"\\\\\\\\?\\\\UNCshared\\\\file\" == (\"\\\\\\\\?\\\\\", \"UNCshared\\\\file\")", test $ W.splitDrive "\\\\?\\UNCshared\\file" == ("\\\\?\\", "UNCshared\\file"))+    ,("W.splitDrive \"\\\\\\\\?\\\\d:\\\\file\" == (\"\\\\\\\\?\\\\d:\\\\\", \"file\")", test $ W.splitDrive "\\\\?\\d:\\file" == ("\\\\?\\d:\\", "file"))+    ,("W.splitDrive \"/d\" == (\"\", \"/d\")", test $ W.splitDrive "/d" == ("", "/d"))+    ,("P.splitDrive \"/test\" == (\"/\", \"test\")", test $ P.splitDrive "/test" == ("/", "test"))+    ,("P.splitDrive \"//test\" == (\"//\", \"test\")", test $ P.splitDrive "//test" == ("//", "test"))+    ,("P.splitDrive \"test/file\" == (\"\", \"test/file\")", test $ P.splitDrive "test/file" == ("", "test/file"))+    ,("P.splitDrive \"file\" == (\"\", \"file\")", test $ P.splitDrive "file" == ("", "file"))+    ,("uncurry P.joinDrive (P.splitDrive x) == x", test $ \(QFilePathValidP x) -> uncurry P.joinDrive (P.splitDrive x) == x)+    ,("uncurry W.joinDrive (W.splitDrive x) == x", test $ \(QFilePathValidW x) -> uncurry W.joinDrive (W.splitDrive x) == x)+    ,("W.joinDrive \"C:\" \"foo\" == \"C:foo\"", test $ W.joinDrive "C:" "foo" == "C:foo")+    ,("W.joinDrive \"C:\\\\\" \"bar\" == \"C:\\\\bar\"", test $ W.joinDrive "C:\\" "bar" == "C:\\bar")+    ,("W.joinDrive \"\\\\\\\\share\" \"foo\" == \"\\\\\\\\share\\\\foo\"", test $ W.joinDrive "\\\\share" "foo" == "\\\\share\\foo")+    ,("W.joinDrive \"/:\" \"foo\" == \"/:\\\\foo\"", test $ W.joinDrive "/:" "foo" == "/:\\foo")+    ,("P.takeDrive x == fst (P.splitDrive x)", test $ \(QFilePath x) -> P.takeDrive x == fst (P.splitDrive x))+    ,("W.takeDrive x == fst (W.splitDrive x)", test $ \(QFilePath x) -> W.takeDrive x == fst (W.splitDrive x))+    ,("P.dropDrive x == snd (P.splitDrive x)", test $ \(QFilePath x) -> P.dropDrive x == snd (P.splitDrive x))+    ,("W.dropDrive x == snd (W.splitDrive x)", test $ \(QFilePath x) -> W.dropDrive x == snd (W.splitDrive x))+    ,("not (P.hasDrive x) == null (P.takeDrive x)", test $ \(QFilePath x) -> not (P.hasDrive x) == null (P.takeDrive x))+    ,("not (W.hasDrive x) == null (W.takeDrive x)", test $ \(QFilePath x) -> not (W.hasDrive x) == null (W.takeDrive x))+    ,("P.hasDrive \"/foo\" == True", test $ P.hasDrive "/foo" == True)+    ,("W.hasDrive \"C:\\\\foo\" == True", test $ W.hasDrive "C:\\foo" == True)+    ,("W.hasDrive \"C:foo\" == True", test $ W.hasDrive "C:foo" == True)+    ,("P.hasDrive \"foo\" == False", test $ P.hasDrive "foo" == False)+    ,("W.hasDrive \"foo\" == False", test $ W.hasDrive "foo" == False)+    ,("P.hasDrive \"\" == False", test $ P.hasDrive "" == False)+    ,("W.hasDrive \"\" == False", test $ W.hasDrive "" == False)+    ,("P.isDrive \"/\" == True", test $ P.isDrive "/" == True)+    ,("P.isDrive \"/foo\" == False", test $ P.isDrive "/foo" == False)+    ,("W.isDrive \"C:\\\\\" == True", test $ W.isDrive "C:\\" == True)+    ,("W.isDrive \"C:\\\\foo\" == False", test $ W.isDrive "C:\\foo" == False)+    ,("P.isDrive \"\" == False", test $ P.isDrive "" == False)+    ,("W.isDrive \"\" == False", test $ W.isDrive "" == False)+    ,("P.splitFileName \"/directory/file.ext\" == (\"/directory/\", \"file.ext\")", test $ P.splitFileName "/directory/file.ext" == ("/directory/", "file.ext"))+    ,("W.splitFileName \"/directory/file.ext\" == (\"/directory/\", \"file.ext\")", test $ W.splitFileName "/directory/file.ext" == ("/directory/", "file.ext"))+    ,("uncurry (P.</>) (P.splitFileName x) == x || fst (P.splitFileName x) == \"./\"", test $ \(QFilePathValidP x) -> uncurry (P.</>) (P.splitFileName x) == x || fst (P.splitFileName x) == "./")+    ,("uncurry (W.</>) (W.splitFileName x) == x || fst (W.splitFileName x) == \"./\"", test $ \(QFilePathValidW x) -> uncurry (W.</>) (W.splitFileName x) == x || fst (W.splitFileName x) == "./")+    ,("P.isValid (fst (P.splitFileName x))", test $ \(QFilePathValidP x) -> P.isValid (fst (P.splitFileName x)))+    ,("W.isValid (fst (W.splitFileName x))", test $ \(QFilePathValidW x) -> W.isValid (fst (W.splitFileName x)))+    ,("P.splitFileName \"file/bob.txt\" == (\"file/\", \"bob.txt\")", test $ P.splitFileName "file/bob.txt" == ("file/", "bob.txt"))+    ,("W.splitFileName \"file/bob.txt\" == (\"file/\", \"bob.txt\")", test $ W.splitFileName "file/bob.txt" == ("file/", "bob.txt"))+    ,("P.splitFileName \"file/\" == (\"file/\", \"\")", test $ P.splitFileName "file/" == ("file/", ""))+    ,("W.splitFileName \"file/\" == (\"file/\", \"\")", test $ W.splitFileName "file/" == ("file/", ""))+    ,("P.splitFileName \"bob\" == (\"./\", \"bob\")", test $ P.splitFileName "bob" == ("./", "bob"))+    ,("W.splitFileName \"bob\" == (\"./\", \"bob\")", test $ W.splitFileName "bob" == ("./", "bob"))+    ,("P.splitFileName \"/\" == (\"/\", \"\")", test $ P.splitFileName "/" == ("/", ""))+    ,("W.splitFileName \"c:\" == (\"c:\", \"\")", test $ W.splitFileName "c:" == ("c:", ""))+    ,("P.replaceFileName \"/directory/other.txt\" \"file.ext\" == \"/directory/file.ext\"", test $ P.replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext")+    ,("W.replaceFileName \"/directory/other.txt\" \"file.ext\" == \"/directory/file.ext\"", test $ W.replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext")+    ,("P.replaceFileName x (P.takeFileName x) == x", test $ \(QFilePathValidP x) -> P.replaceFileName x (P.takeFileName x) == x)+    ,("W.replaceFileName x (W.takeFileName x) == x", test $ \(QFilePathValidW x) -> W.replaceFileName x (W.takeFileName x) == x)+    ,("P.dropFileName \"/directory/file.ext\" == \"/directory/\"", test $ P.dropFileName "/directory/file.ext" == "/directory/")+    ,("W.dropFileName \"/directory/file.ext\" == \"/directory/\"", test $ W.dropFileName "/directory/file.ext" == "/directory/")+    ,("P.dropFileName x == fst (P.splitFileName x)", test $ \(QFilePath x) -> P.dropFileName x == fst (P.splitFileName x))+    ,("W.dropFileName x == fst (W.splitFileName x)", test $ \(QFilePath x) -> W.dropFileName x == fst (W.splitFileName x))+    ,("P.takeFileName \"/directory/file.ext\" == \"file.ext\"", test $ P.takeFileName "/directory/file.ext" == "file.ext")+    ,("W.takeFileName \"/directory/file.ext\" == \"file.ext\"", test $ W.takeFileName "/directory/file.ext" == "file.ext")+    ,("P.takeFileName \"test/\" == \"\"", test $ P.takeFileName "test/" == "")+    ,("W.takeFileName \"test/\" == \"\"", test $ W.takeFileName "test/" == "")+    ,("P.takeFileName x `isSuffixOf` x", test $ \(QFilePath x) -> P.takeFileName x `isSuffixOf` x)+    ,("W.takeFileName x `isSuffixOf` x", test $ \(QFilePath x) -> W.takeFileName x `isSuffixOf` x)+    ,("P.takeFileName x == snd (P.splitFileName x)", test $ \(QFilePath x) -> P.takeFileName x == snd (P.splitFileName x))+    ,("W.takeFileName x == snd (W.splitFileName x)", test $ \(QFilePath x) -> W.takeFileName x == snd (W.splitFileName x))+    ,("P.takeFileName (P.replaceFileName x \"fred\") == \"fred\"", test $ \(QFilePathValidP x) -> P.takeFileName (P.replaceFileName x "fred") == "fred")+    ,("W.takeFileName (W.replaceFileName x \"fred\") == \"fred\"", test $ \(QFilePathValidW x) -> W.takeFileName (W.replaceFileName x "fred") == "fred")+    ,("P.takeFileName (x P.</> \"fred\") == \"fred\"", test $ \(QFilePathValidP x) -> P.takeFileName (x P.</> "fred") == "fred")+    ,("W.takeFileName (x W.</> \"fred\") == \"fred\"", test $ \(QFilePathValidW x) -> W.takeFileName (x W.</> "fred") == "fred")+    ,("P.isRelative (P.takeFileName x)", test $ \(QFilePathValidP x) -> P.isRelative (P.takeFileName x))+    ,("W.isRelative (W.takeFileName x)", test $ \(QFilePathValidW x) -> W.isRelative (W.takeFileName x))+    ,("P.takeBaseName \"/directory/file.ext\" == \"file\"", test $ P.takeBaseName "/directory/file.ext" == "file")+    ,("W.takeBaseName \"/directory/file.ext\" == \"file\"", test $ W.takeBaseName "/directory/file.ext" == "file")+    ,("P.takeBaseName \"file/test.txt\" == \"test\"", test $ P.takeBaseName "file/test.txt" == "test")+    ,("W.takeBaseName \"file/test.txt\" == \"test\"", test $ W.takeBaseName "file/test.txt" == "test")+    ,("P.takeBaseName \"dave.ext\" == \"dave\"", test $ P.takeBaseName "dave.ext" == "dave")+    ,("W.takeBaseName \"dave.ext\" == \"dave\"", test $ W.takeBaseName "dave.ext" == "dave")+    ,("P.takeBaseName \"\" == \"\"", test $ P.takeBaseName "" == "")+    ,("W.takeBaseName \"\" == \"\"", test $ W.takeBaseName "" == "")+    ,("P.takeBaseName \"test\" == \"test\"", test $ P.takeBaseName "test" == "test")+    ,("W.takeBaseName \"test\" == \"test\"", test $ W.takeBaseName "test" == "test")+    ,("P.takeBaseName (P.addTrailingPathSeparator x) == \"\"", test $ \(QFilePath x) -> P.takeBaseName (P.addTrailingPathSeparator x) == "")+    ,("W.takeBaseName (W.addTrailingPathSeparator x) == \"\"", test $ \(QFilePath x) -> W.takeBaseName (W.addTrailingPathSeparator x) == "")+    ,("P.takeBaseName \"file/file.tar.gz\" == \"file.tar\"", test $ P.takeBaseName "file/file.tar.gz" == "file.tar")+    ,("W.takeBaseName \"file/file.tar.gz\" == \"file.tar\"", test $ W.takeBaseName "file/file.tar.gz" == "file.tar")+    ,("P.replaceBaseName \"/directory/other.ext\" \"file\" == \"/directory/file.ext\"", test $ P.replaceBaseName "/directory/other.ext" "file" == "/directory/file.ext")+    ,("W.replaceBaseName \"/directory/other.ext\" \"file\" == \"/directory/file.ext\"", test $ W.replaceBaseName "/directory/other.ext" "file" == "/directory/file.ext")+    ,("P.replaceBaseName \"file/test.txt\" \"bob\" == \"file/bob.txt\"", test $ P.replaceBaseName "file/test.txt" "bob" == "file/bob.txt")+    ,("W.replaceBaseName \"file/test.txt\" \"bob\" == \"file/bob.txt\"", test $ W.replaceBaseName "file/test.txt" "bob" == "file/bob.txt")+    ,("P.replaceBaseName \"fred\" \"bill\" == \"bill\"", test $ P.replaceBaseName "fred" "bill" == "bill")+    ,("W.replaceBaseName \"fred\" \"bill\" == \"bill\"", test $ W.replaceBaseName "fred" "bill" == "bill")+    ,("P.replaceBaseName \"/dave/fred/bob.gz.tar\" \"new\" == \"/dave/fred/new.tar\"", test $ P.replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar")+    ,("W.replaceBaseName \"/dave/fred/bob.gz.tar\" \"new\" == \"/dave/fred/new.tar\"", test $ W.replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar")+    ,("P.replaceBaseName x (P.takeBaseName x) == x", test $ \(QFilePathValidP x) -> P.replaceBaseName x (P.takeBaseName x) == x)+    ,("W.replaceBaseName x (W.takeBaseName x) == x", test $ \(QFilePathValidW x) -> W.replaceBaseName x (W.takeBaseName x) == x)+    ,("P.hasTrailingPathSeparator \"test\" == False", test $ P.hasTrailingPathSeparator "test" == False)+    ,("W.hasTrailingPathSeparator \"test\" == False", test $ W.hasTrailingPathSeparator "test" == False)+    ,("P.hasTrailingPathSeparator \"test/\" == True", test $ P.hasTrailingPathSeparator "test/" == True)+    ,("W.hasTrailingPathSeparator \"test/\" == True", test $ W.hasTrailingPathSeparator "test/" == True)+    ,("P.hasTrailingPathSeparator (P.addTrailingPathSeparator x)", test $ \(QFilePath x) -> P.hasTrailingPathSeparator (P.addTrailingPathSeparator x))+    ,("W.hasTrailingPathSeparator (W.addTrailingPathSeparator x)", test $ \(QFilePath x) -> W.hasTrailingPathSeparator (W.addTrailingPathSeparator x))+    ,("P.hasTrailingPathSeparator x ==> P.addTrailingPathSeparator x == x", test $ \(QFilePath x) -> P.hasTrailingPathSeparator x ==> P.addTrailingPathSeparator x == x)+    ,("W.hasTrailingPathSeparator x ==> W.addTrailingPathSeparator x == x", test $ \(QFilePath x) -> W.hasTrailingPathSeparator x ==> W.addTrailingPathSeparator x == x)+    ,("P.addTrailingPathSeparator \"test/rest\" == \"test/rest/\"", test $ P.addTrailingPathSeparator "test/rest" == "test/rest/")+    ,("P.dropTrailingPathSeparator \"file/test/\" == \"file/test\"", test $ P.dropTrailingPathSeparator "file/test/" == "file/test")+    ,("W.dropTrailingPathSeparator \"file/test/\" == \"file/test\"", test $ W.dropTrailingPathSeparator "file/test/" == "file/test")+    ,("P.dropTrailingPathSeparator \"/\" == \"/\"", test $ P.dropTrailingPathSeparator "/" == "/")+    ,("W.dropTrailingPathSeparator \"/\" == \"/\"", test $ W.dropTrailingPathSeparator "/" == "/")+    ,("W.dropTrailingPathSeparator \"\\\\\" == \"\\\\\"", test $ W.dropTrailingPathSeparator "\\" == "\\")+    ,("not (P.hasTrailingPathSeparator (P.dropTrailingPathSeparator x)) || P.isDrive x", test $ \(QFilePath x) -> not (P.hasTrailingPathSeparator (P.dropTrailingPathSeparator x)) || P.isDrive x)+    ,("P.takeDirectory \"/directory/other.ext\" == \"/directory\"", test $ P.takeDirectory "/directory/other.ext" == "/directory")+    ,("W.takeDirectory \"/directory/other.ext\" == \"/directory\"", test $ W.takeDirectory "/directory/other.ext" == "/directory")+    ,("P.takeDirectory x `isPrefixOf` x || P.takeDirectory x == \".\"", test $ \(QFilePath x) -> P.takeDirectory x `isPrefixOf` x || P.takeDirectory x == ".")+    ,("W.takeDirectory x `isPrefixOf` x || W.takeDirectory x == \".\"", test $ \(QFilePath x) -> W.takeDirectory x `isPrefixOf` x || W.takeDirectory x == ".")+    ,("P.takeDirectory \"foo\" == \".\"", test $ P.takeDirectory "foo" == ".")+    ,("W.takeDirectory \"foo\" == \".\"", test $ W.takeDirectory "foo" == ".")+    ,("P.takeDirectory \"/\" == \"/\"", test $ P.takeDirectory "/" == "/")+    ,("W.takeDirectory \"/\" == \"/\"", test $ W.takeDirectory "/" == "/")+    ,("P.takeDirectory \"/foo\" == \"/\"", test $ P.takeDirectory "/foo" == "/")+    ,("W.takeDirectory \"/foo\" == \"/\"", test $ W.takeDirectory "/foo" == "/")+    ,("P.takeDirectory \"/foo/bar/baz\" == \"/foo/bar\"", test $ P.takeDirectory "/foo/bar/baz" == "/foo/bar")+    ,("W.takeDirectory \"/foo/bar/baz\" == \"/foo/bar\"", test $ W.takeDirectory "/foo/bar/baz" == "/foo/bar")+    ,("P.takeDirectory \"/foo/bar/baz/\" == \"/foo/bar/baz\"", test $ P.takeDirectory "/foo/bar/baz/" == "/foo/bar/baz")+    ,("W.takeDirectory \"/foo/bar/baz/\" == \"/foo/bar/baz\"", test $ W.takeDirectory "/foo/bar/baz/" == "/foo/bar/baz")+    ,("P.takeDirectory \"foo/bar/baz\" == \"foo/bar\"", test $ P.takeDirectory "foo/bar/baz" == "foo/bar")+    ,("W.takeDirectory \"foo/bar/baz\" == \"foo/bar\"", test $ W.takeDirectory "foo/bar/baz" == "foo/bar")+    ,("W.takeDirectory \"foo\\\\bar\" == \"foo\"", test $ W.takeDirectory "foo\\bar" == "foo")+    ,("W.takeDirectory \"foo\\\\bar\\\\\\\\\" == \"foo\\\\bar\"", test $ W.takeDirectory "foo\\bar\\\\" == "foo\\bar")+    ,("W.takeDirectory \"C:\\\\\" == \"C:\\\\\"", test $ W.takeDirectory "C:\\" == "C:\\")+    ,("P.replaceDirectory \"root/file.ext\" \"/directory/\" == \"/directory/file.ext\"", test $ P.replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext")+    ,("W.replaceDirectory \"root/file.ext\" \"/directory/\" == \"/directory/file.ext\"", test $ W.replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext")+    ,("P.replaceDirectory x (P.takeDirectory x) `P.equalFilePath` x", test $ \(QFilePathValidP x) -> P.replaceDirectory x (P.takeDirectory x) `P.equalFilePath` x)+    ,("W.replaceDirectory x (W.takeDirectory x) `W.equalFilePath` x", test $ \(QFilePathValidW x) -> W.replaceDirectory x (W.takeDirectory x) `W.equalFilePath` x)+    ,("P.combine (P.takeDirectory x) (P.takeFileName x) `P.equalFilePath` x", test $ \(QFilePathValidP x) -> P.combine (P.takeDirectory x) (P.takeFileName x) `P.equalFilePath` x)+    ,("W.combine (W.takeDirectory x) (W.takeFileName x) `W.equalFilePath` x", test $ \(QFilePathValidW x) -> W.combine (W.takeDirectory x) (W.takeFileName x) `W.equalFilePath` x)+    ,("P.combine \"/\" \"test\" == \"/test\"", test $ P.combine "/" "test" == "/test")+    ,("P.combine \"home\" \"bob\" == \"home/bob\"", test $ P.combine "home" "bob" == "home/bob")+    ,("P.combine \"x:\" \"foo\" == \"x:/foo\"", test $ P.combine "x:" "foo" == "x:/foo")+    ,("W.combine \"C:\\\\foo\" \"bar\" == \"C:\\\\foo\\\\bar\"", test $ W.combine "C:\\foo" "bar" == "C:\\foo\\bar")+    ,("W.combine \"home\" \"bob\" == \"home\\\\bob\"", test $ W.combine "home" "bob" == "home\\bob")+    ,("P.combine \"home\" \"/bob\" == \"/bob\"", test $ P.combine "home" "/bob" == "/bob")+    ,("W.combine \"home\" \"C:\\\\bob\" == \"C:\\\\bob\"", test $ W.combine "home" "C:\\bob" == "C:\\bob")+    ,("W.combine \"home\" \"/bob\" == \"/bob\"", test $ W.combine "home" "/bob" == "/bob")+    ,("W.combine \"home\" \"\\\\bob\" == \"\\\\bob\"", test $ W.combine "home" "\\bob" == "\\bob")+    ,("W.combine \"C:\\\\home\" \"\\\\bob\" == \"\\\\bob\"", test $ W.combine "C:\\home" "\\bob" == "\\bob")+    ,("W.combine \"D:\\\\foo\" \"C:bar\" == \"C:bar\"", test $ W.combine "D:\\foo" "C:bar" == "C:bar")+    ,("W.combine \"C:\\\\foo\" \"C:bar\" == \"C:bar\"", test $ W.combine "C:\\foo" "C:bar" == "C:bar")+    ,("\"/directory\" P.</> \"file.ext\" == \"/directory/file.ext\"", test $ "/directory" P.</> "file.ext" == "/directory/file.ext")+    ,("\"/directory\" W.</> \"file.ext\" == \"/directory\\\\file.ext\"", test $ "/directory" W.</> "file.ext" == "/directory\\file.ext")+    ,("P.splitPath \"/directory/file.ext\" == [\"/\", \"directory/\", \"file.ext\"]", test $ P.splitPath "/directory/file.ext" == ["/", "directory/", "file.ext"])+    ,("W.splitPath \"/directory/file.ext\" == [\"/\", \"directory/\", \"file.ext\"]", test $ W.splitPath "/directory/file.ext" == ["/", "directory/", "file.ext"])+    ,("concat (P.splitPath x) == x", test $ \(QFilePath x) -> concat (P.splitPath x) == x)+    ,("concat (W.splitPath x) == x", test $ \(QFilePath x) -> concat (W.splitPath x) == x)+    ,("P.splitPath \"test//item/\" == [\"test//\", \"item/\"]", test $ P.splitPath "test//item/" == ["test//", "item/"])+    ,("W.splitPath \"test//item/\" == [\"test//\", \"item/\"]", test $ W.splitPath "test//item/" == ["test//", "item/"])+    ,("P.splitPath \"test/item/file\" == [\"test/\", \"item/\", \"file\"]", test $ P.splitPath "test/item/file" == ["test/", "item/", "file"])+    ,("W.splitPath \"test/item/file\" == [\"test/\", \"item/\", \"file\"]", test $ W.splitPath "test/item/file" == ["test/", "item/", "file"])+    ,("P.splitPath \"\" == []", test $ P.splitPath "" == [])+    ,("W.splitPath \"\" == []", test $ W.splitPath "" == [])+    ,("W.splitPath \"c:\\\\test\\\\path\" == [\"c:\\\\\", \"test\\\\\", \"path\"]", test $ W.splitPath "c:\\test\\path" == ["c:\\", "test\\", "path"])+    ,("P.splitPath \"/file/test\" == [\"/\", \"file/\", \"test\"]", test $ P.splitPath "/file/test" == ["/", "file/", "test"])+    ,("P.splitDirectories \"/directory/file.ext\" == [\"/\", \"directory\", \"file.ext\"]", test $ P.splitDirectories "/directory/file.ext" == ["/", "directory", "file.ext"])+    ,("W.splitDirectories \"/directory/file.ext\" == [\"/\", \"directory\", \"file.ext\"]", test $ W.splitDirectories "/directory/file.ext" == ["/", "directory", "file.ext"])+    ,("P.splitDirectories \"test/file\" == [\"test\", \"file\"]", test $ P.splitDirectories "test/file" == ["test", "file"])+    ,("W.splitDirectories \"test/file\" == [\"test\", \"file\"]", test $ W.splitDirectories "test/file" == ["test", "file"])+    ,("P.splitDirectories \"/test/file\" == [\"/\", \"test\", \"file\"]", test $ P.splitDirectories "/test/file" == ["/", "test", "file"])+    ,("W.splitDirectories \"/test/file\" == [\"/\", \"test\", \"file\"]", test $ W.splitDirectories "/test/file" == ["/", "test", "file"])+    ,("W.splitDirectories \"C:\\\\test\\\\file\" == [\"C:\\\\\", \"test\", \"file\"]", test $ W.splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"])+    ,("P.joinPath (P.splitDirectories x) `P.equalFilePath` x", test $ \(QFilePathValidP x) -> P.joinPath (P.splitDirectories x) `P.equalFilePath` x)+    ,("W.joinPath (W.splitDirectories x) `W.equalFilePath` x", test $ \(QFilePathValidW x) -> W.joinPath (W.splitDirectories x) `W.equalFilePath` x)+    ,("P.splitDirectories \"\" == []", test $ P.splitDirectories "" == [])+    ,("W.splitDirectories \"\" == []", test $ W.splitDirectories "" == [])+    ,("W.splitDirectories \"C:\\\\test\\\\\\\\\\\\file\" == [\"C:\\\\\", \"test\", \"file\"]", test $ W.splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"])+    ,("P.splitDirectories \"/test///file\" == [\"/\", \"test\", \"file\"]", test $ P.splitDirectories "/test///file" == ["/", "test", "file"])+    ,("W.splitDirectories \"/test///file\" == [\"/\", \"test\", \"file\"]", test $ W.splitDirectories "/test///file" == ["/", "test", "file"])+    ,("P.joinPath [\"/\", \"directory/\", \"file.ext\"] == \"/directory/file.ext\"", test $ P.joinPath ["/", "directory/", "file.ext"] == "/directory/file.ext")+    ,("W.joinPath [\"/\", \"directory/\", \"file.ext\"] == \"/directory/file.ext\"", test $ W.joinPath ["/", "directory/", "file.ext"] == "/directory/file.ext")+    ,("P.joinPath (P.splitPath x) == x", test $ \(QFilePathValidP x) -> P.joinPath (P.splitPath x) == x)+    ,("W.joinPath (W.splitPath x) == x", test $ \(QFilePathValidW x) -> W.joinPath (W.splitPath x) == x)+    ,("P.joinPath [] == \"\"", test $ P.joinPath [] == "")+    ,("W.joinPath [] == \"\"", test $ W.joinPath [] == "")+    ,("P.joinPath [\"test\", \"file\", \"path\"] == \"test/file/path\"", test $ P.joinPath ["test", "file", "path"] == "test/file/path")+    ,("x == y ==> P.equalFilePath x y", test $ \(QFilePath x) (QFilePath y) -> x == y ==> P.equalFilePath x y)+    ,("x == y ==> W.equalFilePath x y", test $ \(QFilePath x) (QFilePath y) -> x == y ==> W.equalFilePath x y)+    ,("P.normalise x == P.normalise y ==> P.equalFilePath x y", test $ \(QFilePath x) (QFilePath y) -> P.normalise x == P.normalise y ==> P.equalFilePath x y)+    ,("W.normalise x == W.normalise y ==> W.equalFilePath x y", test $ \(QFilePath x) (QFilePath y) -> W.normalise x == W.normalise y ==> W.equalFilePath x y)+    ,("P.equalFilePath \"foo\" \"foo/\"", test $ P.equalFilePath "foo" "foo/")+    ,("W.equalFilePath \"foo\" \"foo/\"", test $ W.equalFilePath "foo" "foo/")+    ,("not (P.equalFilePath \"foo\" \"/foo\")", test $ not (P.equalFilePath "foo" "/foo"))+    ,("not (W.equalFilePath \"foo\" \"/foo\")", test $ not (W.equalFilePath "foo" "/foo"))+    ,("not (P.equalFilePath \"foo\" \"FOO\")", test $ not (P.equalFilePath "foo" "FOO"))+    ,("W.equalFilePath \"foo\" \"FOO\"", test $ W.equalFilePath "foo" "FOO")+    ,("not (W.equalFilePath \"C:\" \"C:/\")", test $ not (W.equalFilePath "C:" "C:/"))+    ,("P.makeRelative \"/directory\" \"/directory/file.ext\" == \"file.ext\"", test $ P.makeRelative "/directory" "/directory/file.ext" == "file.ext")+    ,("W.makeRelative \"/directory\" \"/directory/file.ext\" == \"file.ext\"", test $ W.makeRelative "/directory" "/directory/file.ext" == "file.ext")+    ,("P.makeRelative (P.takeDirectory x) x `P.equalFilePath` P.takeFileName x", test $ \(QFilePathValidP x) -> P.makeRelative (P.takeDirectory x) x `P.equalFilePath` P.takeFileName x)+    ,("W.makeRelative (W.takeDirectory x) x `W.equalFilePath` W.takeFileName x", test $ \(QFilePathValidW x) -> W.makeRelative (W.takeDirectory x) x `W.equalFilePath` W.takeFileName x)+    ,("P.makeRelative x x == \".\"", test $ \(QFilePath x) -> P.makeRelative x x == ".")+    ,("W.makeRelative x x == \".\"", test $ \(QFilePath x) -> W.makeRelative x x == ".")+    ,("P.equalFilePath x y || (P.isRelative x && P.makeRelative y x == x) || P.equalFilePath (y P.</> P.makeRelative y x) x", test $ \(QFilePathValidP x) (QFilePathValidP y) -> P.equalFilePath x y || (P.isRelative x && P.makeRelative y x == x) || P.equalFilePath (y P.</> P.makeRelative y x) x)+    ,("W.equalFilePath x y || (W.isRelative x && W.makeRelative y x == x) || W.equalFilePath (y W.</> W.makeRelative y x) x", test $ \(QFilePathValidW x) (QFilePathValidW y) -> W.equalFilePath x y || (W.isRelative x && W.makeRelative y x == x) || W.equalFilePath (y W.</> W.makeRelative y x) x)+    ,("W.makeRelative \"C:\\\\Home\" \"c:\\\\home\\\\bob\" == \"bob\"", test $ W.makeRelative "C:\\Home" "c:\\home\\bob" == "bob")+    ,("W.makeRelative \"C:\\\\Home\" \"c:/home/bob\" == \"bob\"", test $ W.makeRelative "C:\\Home" "c:/home/bob" == "bob")+    ,("W.makeRelative \"C:\\\\Home\" \"D:\\\\Home\\\\Bob\" == \"D:\\\\Home\\\\Bob\"", test $ W.makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob")+    ,("W.makeRelative \"C:\\\\Home\" \"C:Home\\\\Bob\" == \"C:Home\\\\Bob\"", test $ W.makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob")+    ,("W.makeRelative \"/Home\" \"/home/bob\" == \"bob\"", test $ W.makeRelative "/Home" "/home/bob" == "bob")+    ,("W.makeRelative \"/\" \"//\" == \"//\"", test $ W.makeRelative "/" "//" == "//")+    ,("P.makeRelative \"/Home\" \"/home/bob\" == \"/home/bob\"", test $ P.makeRelative "/Home" "/home/bob" == "/home/bob")+    ,("P.makeRelative \"/home/\" \"/home/bob/foo/bar\" == \"bob/foo/bar\"", test $ P.makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar")+    ,("P.makeRelative \"/fred\" \"bob\" == \"bob\"", test $ P.makeRelative "/fred" "bob" == "bob")+    ,("P.makeRelative \"/file/test\" \"/file/test/fred\" == \"fred\"", test $ P.makeRelative "/file/test" "/file/test/fred" == "fred")+    ,("P.makeRelative \"/file/test\" \"/file/test/fred/\" == \"fred/\"", test $ P.makeRelative "/file/test" "/file/test/fred/" == "fred/")+    ,("P.makeRelative \"some/path\" \"some/path/a/b/c\" == \"a/b/c\"", test $ P.makeRelative "some/path" "some/path/a/b/c" == "a/b/c")+    ,("P.normalise \"/file/\\\\test////\" == \"/file/\\\\test/\"", test $ P.normalise "/file/\\test////" == "/file/\\test/")+    ,("P.normalise \"/file/./test\" == \"/file/test\"", test $ P.normalise "/file/./test" == "/file/test")+    ,("P.normalise \"/test/file/../bob/fred/\" == \"/test/file/../bob/fred/\"", test $ P.normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/")+    ,("P.normalise \"../bob/fred/\" == \"../bob/fred/\"", test $ P.normalise "../bob/fred/" == "../bob/fred/")+    ,("P.normalise \"./bob/fred/\" == \"bob/fred/\"", test $ P.normalise "./bob/fred/" == "bob/fred/")+    ,("W.normalise \"c:\\\\file/bob\\\\\" == \"C:\\\\file\\\\bob\\\\\"", test $ W.normalise "c:\\file/bob\\" == "C:\\file\\bob\\")+    ,("W.normalise \"c:\\\\\" == \"C:\\\\\"", test $ W.normalise "c:\\" == "C:\\")+    ,("W.normalise \"C:.\\\\\" == \"C:\"", test $ W.normalise "C:.\\" == "C:")+    ,("W.normalise \"\\\\\\\\server\\\\test\" == \"\\\\\\\\server\\\\test\"", test $ W.normalise "\\\\server\\test" == "\\\\server\\test")+    ,("W.normalise \"//server/test\" == \"\\\\\\\\server\\\\test\"", test $ W.normalise "//server/test" == "\\\\server\\test")+    ,("W.normalise \"c:/file\" == \"C:\\\\file\"", test $ W.normalise "c:/file" == "C:\\file")+    ,("W.normalise \"/file\" == \"\\\\file\"", test $ W.normalise "/file" == "\\file")+    ,("W.normalise \"\\\\\" == \"\\\\\"", test $ W.normalise "\\" == "\\")+    ,("W.normalise \"/./\" == \"\\\\\"", test $ W.normalise "/./" == "\\")+    ,("P.normalise \".\" == \".\"", test $ P.normalise "." == ".")+    ,("W.normalise \".\" == \".\"", test $ W.normalise "." == ".")+    ,("P.normalise \"./\" == \"./\"", test $ P.normalise "./" == "./")+    ,("P.normalise \"./.\" == \"./\"", test $ P.normalise "./." == "./")+    ,("P.normalise \"/./\" == \"/\"", test $ P.normalise "/./" == "/")+    ,("P.normalise \"/\" == \"/\"", test $ P.normalise "/" == "/")+    ,("P.normalise \"bob/fred/.\" == \"bob/fred/\"", test $ P.normalise "bob/fred/." == "bob/fred/")+    ,("P.normalise \"//home\" == \"/home\"", test $ P.normalise "//home" == "/home")+    ,("P.isValid \"\" == False", test $ P.isValid "" == False)+    ,("W.isValid \"\" == False", test $ W.isValid "" == False)+    ,("P.isValid \"/random_ path:*\" == True", test $ P.isValid "/random_ path:*" == True)+    ,("P.isValid x == not (null x)", test $ \(QFilePath x) -> P.isValid x == not (null x))+    ,("W.isValid \"c:\\\\test\" == True", test $ W.isValid "c:\\test" == True)+    ,("W.isValid \"c:\\\\test:of_test\" == False", test $ W.isValid "c:\\test:of_test" == False)+    ,("W.isValid \"test*\" == False", test $ W.isValid "test*" == False)+    ,("W.isValid \"c:\\\\test\\\\nul\" == False", test $ W.isValid "c:\\test\\nul" == False)+    ,("W.isValid \"c:\\\\test\\\\prn.txt\" == False", test $ W.isValid "c:\\test\\prn.txt" == False)+    ,("W.isValid \"c:\\\\nul\\\\file\" == False", test $ W.isValid "c:\\nul\\file" == False)+    ,("W.isValid \"\\\\\\\\\" == False", test $ W.isValid "\\\\" == False)+    ,("W.isValid \"\\\\\\\\\\\\foo\" == False", test $ W.isValid "\\\\\\foo" == False)+    ,("W.isValid \"\\\\\\\\?\\\\D:file\" == False", test $ W.isValid "\\\\?\\D:file" == False)+    ,("P.isValid (P.makeValid x)", test $ \(QFilePath x) -> P.isValid (P.makeValid x))+    ,("W.isValid (W.makeValid x)", test $ \(QFilePath x) -> W.isValid (W.makeValid x))+    ,("P.isValid x ==> P.makeValid x == x", test $ \(QFilePath x) -> P.isValid x ==> P.makeValid x == x)+    ,("W.isValid x ==> W.makeValid x == x", test $ \(QFilePath x) -> W.isValid x ==> W.makeValid x == x)+    ,("P.makeValid \"\" == \"_\"", test $ P.makeValid "" == "_")+    ,("W.makeValid \"\" == \"_\"", test $ W.makeValid "" == "_")+    ,("W.makeValid \"c:\\\\already\\\\/valid\" == \"c:\\\\already\\\\/valid\"", test $ W.makeValid "c:\\already\\/valid" == "c:\\already\\/valid")+    ,("W.makeValid \"c:\\\\test:of_test\" == \"c:\\\\test_of_test\"", test $ W.makeValid "c:\\test:of_test" == "c:\\test_of_test")+    ,("W.makeValid \"test*\" == \"test_\"", test $ W.makeValid "test*" == "test_")+    ,("W.makeValid \"c:\\\\test\\\\nul\" == \"c:\\\\test\\\\nul_\"", test $ W.makeValid "c:\\test\\nul" == "c:\\test\\nul_")+    ,("W.makeValid \"c:\\\\test\\\\prn.txt\" == \"c:\\\\test\\\\prn_.txt\"", test $ W.makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt")+    ,("W.makeValid \"c:\\\\test/prn.txt\" == \"c:\\\\test/prn_.txt\"", test $ W.makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt")+    ,("W.makeValid \"c:\\\\nul\\\\file\" == \"c:\\\\nul_\\\\file\"", test $ W.makeValid "c:\\nul\\file" == "c:\\nul_\\file")+    ,("W.makeValid \"\\\\\\\\\\\\foo\" == \"\\\\\\\\drive\"", test $ W.makeValid "\\\\\\foo" == "\\\\drive")+    ,("W.makeValid \"\\\\\\\\?\\\\D:file\" == \"\\\\\\\\?\\\\D:\\\\file\"", test $ W.makeValid "\\\\?\\D:file" == "\\\\?\\D:\\file")+    ,("W.isRelative \"path\\\\test\" == True", test $ W.isRelative "path\\test" == True)+    ,("W.isRelative \"c:\\\\test\" == False", test $ W.isRelative "c:\\test" == False)+    ,("W.isRelative \"c:test\" == True", test $ W.isRelative "c:test" == True)+    ,("W.isRelative \"c:\\\\\" == False", test $ W.isRelative "c:\\" == False)+    ,("W.isRelative \"c:/\" == False", test $ W.isRelative "c:/" == False)+    ,("W.isRelative \"c:\" == True", test $ W.isRelative "c:" == True)+    ,("W.isRelative \"\\\\\\\\foo\" == False", test $ W.isRelative "\\\\foo" == False)+    ,("W.isRelative \"\\\\\\\\?\\\\foo\" == False", test $ W.isRelative "\\\\?\\foo" == False)+    ,("W.isRelative \"\\\\\\\\?\\\\UNC\\\\foo\" == False", test $ W.isRelative "\\\\?\\UNC\\foo" == False)+    ,("W.isRelative \"/foo\" == True", test $ W.isRelative "/foo" == True)+    ,("W.isRelative \"\\\\foo\" == True", test $ W.isRelative "\\foo" == True)+    ,("P.isRelative \"test/path\" == True", test $ P.isRelative "test/path" == True)+    ,("P.isRelative \"/test\" == False", test $ P.isRelative "/test" == False)+    ,("P.isRelative \"/\" == False", test $ P.isRelative "/" == False)+    ,("P.isAbsolute x == not (P.isRelative x)", test $ \(QFilePath x) -> P.isAbsolute x == not (P.isRelative x))+    ,("W.isAbsolute x == not (W.isRelative x)", test $ \(QFilePath x) -> W.isAbsolute x == not (W.isRelative x))+    ]
+ tests/TestUtil.hs view
@@ -0,0 +1,61 @@++module TestUtil(+    (==>), QFilePath(..), QFilePathValidW(..), QFilePathValidP(..),+    test, Test,+    module Test.QuickCheck,+    module Data.List+    ) where++import Test.QuickCheck hiding ((==>))+import Data.List+import Control.Monad+import qualified System.FilePath.Windows as W+import qualified System.FilePath.Posix as P++infixr 0 ==>+a ==> b = not a || b+++newtype QFilePathValidW = QFilePathValidW FilePath deriving Show++instance Arbitrary QFilePathValidW where+    arbitrary = fmap (QFilePathValidW . W.makeValid) arbitraryFilePath+    shrink (QFilePathValidW x) = shrinkValid QFilePathValidW W.makeValid x++newtype QFilePathValidP = QFilePathValidP FilePath deriving Show++instance Arbitrary QFilePathValidP where+    arbitrary = fmap (QFilePathValidP . P.makeValid) arbitraryFilePath+    shrink (QFilePathValidP x) = shrinkValid QFilePathValidP P.makeValid x++newtype QFilePath = QFilePath FilePath deriving Show++instance Arbitrary QFilePath where+    arbitrary = fmap QFilePath arbitraryFilePath+    shrink (QFilePath x) = shrinkValid QFilePath id x+++-- | Generate an arbitrary FilePath use a few special (interesting) characters.+arbitraryFilePath :: Gen FilePath+arbitraryFilePath = sized $ \n -> do+    k <- choose (0,n)+    replicateM k $ elements "?./:\\a ;_"++-- | Shrink, but also apply a validity function. Try and make shorter, or use more+--   @a@ (since @a@ is pretty dull), but make sure you terminate even after valid.+shrinkValid :: (FilePath -> a) -> (FilePath -> FilePath) -> FilePath -> [a]+shrinkValid wrap valid o =+    [ wrap y+    | y <- map valid $ shrinkList (\x -> ['a' | x /= 'a']) o+    , length y < length o || (length y == length o && countA y > countA o)]+    where countA = length . filter (== 'a')+++data Test = Test Property Bool++test :: Testable prop => prop -> Test+test prop = Test (property prop) (exhaustive prop)++instance Testable Test where+    property (Test x _) = x+    exhaustive (Test _ x) = x