packages feed

system-fileio 0.3.16.4 → 0.3.16.5

raw patch · 8 files changed

+1213/−1178 lines, 8 filesdep ~basedep ~chelldep ~temporarynew-uploader

Dependency ranges changed: base, chell, temporary, time

Files

ChangeLog.md view
@@ -1,16 +1,21 @@ # Changelog for system-fileio +## 0.3.16.5++* Fix building of the testsuite with `unix-2.8`.+* Tested with GHC 8.0 - 9.12.0.+ ## 0.3.16.4 -* Fix for Win32 2.6 and above [#21](https://github.com/fpco/haskell-filesystem/pull/21)+* Fix for Win32 2.6 and above [#21](https://github.com/fpco/haskell-filesystem/pull/21).  ## 0.3.16.2 -* withHANDLE (Win32) now works on directories [#8](https://github.com/fpco/haskell-filesystem/issues/8) [#10](https://github.com/fpco/haskell-filesystem/pull/10)+* `withHANDLE` (Win32) now works on directories [#8](https://github.com/fpco/haskell-filesystem/issues/8) [#10](https://github.com/fpco/haskell-filesystem/pull/10).  ## 0.3.16.1 -* Use different path encoding on Darwin in POSIX tests [#6](https://github.com/fpco/haskell-filesystem/pull/6)+* Use different path encoding on Darwin in POSIX tests [#6](https://github.com/fpco/haskell-filesystem/pull/6).  ## 0.3.16 
README.md view
@@ -1,6 +1,6 @@ ## system-fileio -Please see [deprecation announcement](https://plus.google.com/+MichaelSnoyman/posts/Ft5hnPqpgEx)+Legacy package (deprecated).  This is a small wrapper around the `directory`, `unix`, and `Win32` packages, for use with `system-filepath`. It provides a consistent API
lib/Filesystem.hs view
@@ -16,63 +16,63 @@ -- In particular, they do not require POSIX file paths to be valid strings, -- and can therefore open paths regardless of the current locale encoding. module Filesystem-	(-	-- * Exports from System.IO-	  IO.Handle-	, IO.IOMode(..)-	-	-- * Files-	, isFile-	, getModified-	, getSize-	, copyFile-	, copyFileContent-	, copyPermissions-	, removeFile-	-	-- ** Binary files-	, openFile-	, withFile-	, readFile-	, writeFile-	, appendFile-	-	-- ** Text files-	, openTextFile-	, withTextFile-	, readTextFile-	, writeTextFile-	, appendTextFile-	-	-- * Directories-	, isDirectory-	, canonicalizePath-	, listDirectory-	-	-- ** Creating directories-	, createDirectory-	, createTree-	-	-- ** Removing directories-	, removeDirectory-	, removeTree-	-	-- ** Current working directory-	, getWorkingDirectory-	, setWorkingDirectory-	-	-- ** Commonly used paths-	, getHomeDirectory-	, getDesktopDirectory-	, getDocumentsDirectory-	, getAppDataDirectory-	, getAppCacheDirectory-	, getAppConfigDirectory-	-	-- * Other-	, rename-	) where+  (+  -- * Exports from System.IO+    IO.Handle+  , IO.IOMode(..) +  -- * Files+  , isFile+  , getModified+  , getSize+  , copyFile+  , copyFileContent+  , copyPermissions+  , removeFile++  -- ** Binary files+  , openFile+  , withFile+  , readFile+  , writeFile+  , appendFile++  -- ** Text files+  , openTextFile+  , withTextFile+  , readTextFile+  , writeTextFile+  , appendTextFile++  -- * Directories+  , isDirectory+  , canonicalizePath+  , listDirectory++  -- ** Creating directories+  , createDirectory+  , createTree++  -- ** Removing directories+  , removeDirectory+  , removeTree++  -- ** Current working directory+  , getWorkingDirectory+  , setWorkingDirectory++  -- ** Commonly used paths+  , getHomeDirectory+  , getDesktopDirectory+  , getDocumentsDirectory+  , getAppDataDirectory+  , getAppCacheDirectory+  , getAppConfigDirectory++  -- * Other+  , rename+  ) where+ import           Prelude hiding (FilePath, readFile, writeFile, appendFile)  import qualified Control.Exception as Exc@@ -138,10 +138,10 @@ isFile path = SD.doesFileExist (encodeString path) #else isFile path = Exc.catch-	(do-		stat <- posixStat "isFile" path-		return (not (Posix.isDirectory stat)))-	((\_ -> return False) :: IOError -> IO Bool)+  (do+    stat <- posixStat "isFile" path+    return (not (Posix.isDirectory stat)))+  ((\_ -> return False) :: IOError -> IO Bool) #endif  -- | Check if a directory exists at the given path.@@ -154,10 +154,10 @@ isDirectory path = SD.doesDirectoryExist (encodeString path) #else isDirectory path = Exc.catch-	(do-		stat <- posixStat "isDirectory" path-		return (Posix.isDirectory stat))-	((\_ -> return False) :: IOError -> IO Bool)+  (do+    stat <- posixStat "isDirectory" path+    return (Posix.isDirectory stat))+  ((\_ -> return False) :: IOError -> IO Bool) #endif  -- | Rename a filesystem object.@@ -168,20 +168,20 @@ rename :: FilePath -> FilePath -> IO () rename old new = #ifdef CABAL_OS_WINDOWS-	let old' = encodeString old in-	let new' = encodeString new in+  let old' = encodeString old in+  let new' = encodeString new in #if MIN_VERSION_Win32(2,6,0)-	Win32.moveFileEx old' (Just new') Win32.mOVEFILE_REPLACE_EXISTING+  Win32.moveFileEx old' (Just new') Win32.mOVEFILE_REPLACE_EXISTING #else-	Win32.moveFileEx old' new' Win32.mOVEFILE_REPLACE_EXISTING+  Win32.moveFileEx old' new' Win32.mOVEFILE_REPLACE_EXISTING #endif #else-	withFilePath old $ \old' ->-	withFilePath new $ \new' ->-	throwErrnoPathIfMinus1_ "rename" old (c_rename old' new')+  withFilePath old $ \old' ->+  withFilePath new $ \new' ->+  throwErrnoPathIfMinus1_ "rename" old (c_rename old' new')  foreign import ccall unsafe "rename"-	c_rename :: CString -> CString -> IO CInt+  c_rename :: CString -> CString -> IO CInt  #endif @@ -199,41 +199,41 @@ -- Since: 0.1.1 canonicalizePath :: FilePath -> IO FilePath canonicalizePath path =-	fmap (preserveFinalSlash path) $-	let path' = encodeString path in+  fmap (preserveFinalSlash path) $+  let path' = encodeString path in #ifdef CABAL_OS_WINDOWS-	fmap decodeString $+  fmap decodeString $ #if MIN_VERSION_Win32(2,2,1)-	Win32.getFullPathName path'+  Win32.getFullPathName path' #else-	Win32.withTString path' $ \c_name -> do-		Win32.try "getFullPathName" (\buf len ->-			c_GetFullPathNameW c_name len buf nullPtr) 512+  Win32.withTString path' $ \c_name -> do+    Win32.try "getFullPathName" (\buf len ->+      c_GetFullPathNameW c_name len buf nullPtr) 512 #endif #else-	withFilePath path $ \cPath -> do-		cOut <- Posix.throwErrnoPathIfNull "canonicalizePath" path' (c_realpath cPath nullPtr)-		bytes <- B.packCString cOut-		c_free cOut-		return (R.decode R.posix bytes)+  withFilePath path $ \cPath -> do+    cOut <- Posix.throwErrnoPathIfNull "canonicalizePath" path' (c_realpath cPath nullPtr)+    bytes <- B.packCString cOut+    c_free cOut+    return (R.decode R.posix bytes) #endif  preserveFinalSlash :: FilePath -> FilePath -> FilePath preserveFinalSlash orig out = if Path.null (Path.filename orig)-	then Path.append out Path.empty-	else out+  then Path.append out Path.empty+  else out  #ifdef CABAL_OS_WINDOWS #if MIN_VERSION_Win32(2,2,1) #else foreign import stdcall unsafe "GetFullPathNameW"-	c_GetFullPathNameW :: Win32.LPCTSTR -> Win32.DWORD -> Win32.LPTSTR -> Ptr Win32.LPTSTR -> IO Win32.DWORD+  c_GetFullPathNameW :: Win32.LPCTSTR -> Win32.DWORD -> Win32.LPTSTR -> Ptr Win32.LPTSTR -> IO Win32.DWORD #endif #endif  #ifndef CABAL_OS_WINDOWS foreign import ccall unsafe "realpath"-	c_realpath :: CString -> CString -> IO CString+  c_realpath :: CString -> CString -> IO CString #endif  -- | Create a directory at a given path. The user may choose whether it is@@ -246,33 +246,33 @@                 -> FilePath -> IO () createDirectory succeedIfExists path = #ifdef CABAL_OS_WINDOWS-	let path' = encodeString path in-	if succeedIfExists-		then SD.createDirectoryIfMissing False path'-		else Win32.createDirectory path' Nothing+  let path' = encodeString path in+  if succeedIfExists+    then SD.createDirectoryIfMissing False path'+    else Win32.createDirectory path' Nothing #else-	withFilePath path $ \cPath ->-	throwErrnoPathIfMinus1Retry_ "createDirectory" path $ if succeedIfExists-		then mkdirIfMissing path cPath 0o777-		else c_mkdir cPath 0o777+  withFilePath path $ \cPath ->+  throwErrnoPathIfMinus1Retry_ "createDirectory" path $ if succeedIfExists+    then mkdirIfMissing path cPath 0o777+    else c_mkdir cPath 0o777  mkdirIfMissing :: FilePath -> CString -> CInt -> IO CInt mkdirIfMissing path cPath mode = do-	rc <- c_mkdir cPath mode-	if rc == -1-		then do-			errno <- CError.getErrno-			if errno == CError.eEXIST-				then do-					dirExists <- isDirectory path-					if dirExists-						then return 0-						else return rc-				else return rc-		else return rc+  rc <- c_mkdir cPath mode+  if rc == -1+    then do+      errno <- CError.getErrno+      if errno == CError.eEXIST+        then do+          dirExists <- isDirectory path+          if dirExists+            then return 0+            else return rc+        else return rc+    else return rc  foreign import ccall unsafe "mkdir"-	c_mkdir :: CString -> CInt -> IO CInt+  c_mkdir :: CString -> CInt -> IO CInt #endif  -- | Create a directory at a given path, including any parents which might@@ -286,11 +286,11 @@ createTree path = SD.createDirectoryIfMissing True (encodeString path) #else createTree path = do-	let parent = Path.parent path-	parentExists <- isDirectory parent-	unless parentExists (createTree parent)-	withFilePath path $ \cPath ->-		throwErrnoPathIfMinus1Retry_ "createTree" path (mkdirIfMissing path cPath 0o777)+  let parent = Path.parent path+  parentExists <- isDirectory parent+  unless parentExists (createTree parent)+  withFilePath path $ \cPath ->+    throwErrnoPathIfMinus1Retry_ "createTree" path (mkdirIfMissing path cPath 0o777) #endif  -- | List objects in a directory, excluding @\".\"@ and @\"..\"@. Each@@ -303,71 +303,71 @@ listDirectory :: FilePath -> IO [FilePath] #ifdef CABAL_OS_WINDOWS listDirectory root = fmap cleanup contents where-	contents = SD.getDirectoryContents (encodeString root)-	cleanup = map (append root) . map decodeString . filter (`notElem` [".", ".."])+  contents = SD.getDirectoryContents (encodeString root)+  cleanup = map (append root) . map decodeString . filter (`notElem` [".", ".."]) #else listDirectory root = Exc.bracket alloc free list where-	alloc = do-		dir <- openDir root-		let Dir _ dirp = dir-		dirent <- c_alloc_dirent dirp-		return (dirent, dir)-	free (dirent, dir) = do-		c_free_dirent dirent-		closeDir dir-	list (dirent, dir) = loop where-		loop = do-			next <- readDir dir dirent-			case next of-				Nothing -> return []-				Just bytes | ignore bytes -> loop-				Just bytes -> do-					let name = append root (R.decode R.posix bytes)-					names <- loop-					return (name:names)+  alloc = do+    dir <- openDir root+    let Dir _ dirp = dir+    dirent <- c_alloc_dirent dirp+    return (dirent, dir)+  free (dirent, dir) = do+    c_free_dirent dirent+    closeDir dir+  list (dirent, dir) = loop where+    loop = do+      next <- readDir dir dirent+      case next of+        Nothing -> return []+        Just bytes | ignore bytes -> loop+        Just bytes -> do+          let name = append root (R.decode R.posix bytes)+          names <- loop+          return (name:names)  ignore :: B.ByteString -> Bool ignore = ignore' where-	dot = B.pack [46]-	dotdot = B.pack [46, 46]-	ignore' b = b == dot || b == dotdot+  dot = B.pack [46]+  dotdot = B.pack [46, 46]+  ignore' b = b == dot || b == dotdot  data Dir = Dir FilePath (Ptr ())  openDir :: FilePath -> IO Dir openDir root = withFilePath root $ \cRoot -> do-	p <- throwErrnoPathIfNullRetry "listDirectory" root (c_opendir cRoot)-	return (Dir root p)+  p <- throwErrnoPathIfNullRetry "listDirectory" root (c_opendir cRoot)+  return (Dir root p)  closeDir :: Dir -> IO () closeDir (Dir _ p) = CError.throwErrnoIfMinus1Retry_ "listDirectory" (c_closedir p)  readDir :: Dir -> Ptr () -> IO (Maybe B.ByteString) readDir (Dir _ p) dirent = do-	rc <- CError.throwErrnoIfMinus1Retry "listDirectory" (c_readdir p dirent)-	if rc == 0-		then do-			bytes <- c_dirent_name dirent >>= B.packCString-			return (Just bytes)-		else return Nothing+  rc <- CError.throwErrnoIfMinus1Retry "listDirectory" (c_readdir p dirent)+  if rc == 0+    then do+      bytes <- c_dirent_name dirent >>= B.packCString+      return (Just bytes)+    else return Nothing  foreign import ccall unsafe "opendir"-	c_opendir :: CString -> IO (Ptr ())+  c_opendir :: CString -> IO (Ptr ())  foreign import ccall unsafe "closedir"-	c_closedir :: Ptr () -> IO CInt+  c_closedir :: Ptr () -> IO CInt  foreign import ccall unsafe "hssystemfileio_alloc_dirent"-	c_alloc_dirent :: Ptr () -> IO (Ptr ())+  c_alloc_dirent :: Ptr () -> IO (Ptr ())  foreign import ccall unsafe "hssystemfileio_free_dirent"-	c_free_dirent :: Ptr () -> IO ()+  c_free_dirent :: Ptr () -> IO ()  foreign import ccall unsafe "hssystemfileio_readdir"-	c_readdir :: Ptr () -> Ptr () -> IO CInt+  c_readdir :: Ptr () -> Ptr () -> IO CInt  foreign import ccall unsafe "hssystemfileio_dirent_name"-	c_dirent_name :: Ptr () -> IO CString+  c_dirent_name :: Ptr () -> IO CString  #endif @@ -382,13 +382,13 @@ removeFile :: FilePath -> IO () removeFile path = #ifdef CABAL_OS_WINDOWS-	Win32.deleteFile (encodeString path)+  Win32.deleteFile (encodeString path) #else-	withFilePath path $ \cPath ->-	throwErrnoPathIfMinus1_ "removeFile" path (c_unlink cPath)+  withFilePath path $ \cPath ->+  throwErrnoPathIfMinus1_ "removeFile" path (c_unlink cPath)  foreign import ccall unsafe "unlink"-	c_unlink :: CString -> IO CInt+  c_unlink :: CString -> IO CInt #endif  -- | Remove an empty directory.@@ -399,13 +399,13 @@ removeDirectory :: FilePath -> IO () removeDirectory path = #ifdef CABAL_OS_WINDOWS-	Win32.removeDirectory (encodeString path)+  Win32.removeDirectory (encodeString path) #else-	withFilePath path $ \cPath ->-	throwErrnoPathIfMinus1Retry_ "removeDirectory" path (c_rmdir cPath)+  withFilePath path $ \cPath ->+  throwErrnoPathIfMinus1Retry_ "removeDirectory" path (c_rmdir cPath)  foreign import ccall unsafe "rmdir"-	c_rmdir :: CString -> IO CInt+  c_rmdir :: CString -> IO CInt #endif  -- | Recursively remove a directory tree rooted at the given path.@@ -424,15 +424,15 @@ removeTree root = SD.removeDirectoryRecursive (encodeString root) #else removeTree root = do-	items <- listDirectory root-	forM_ items $ \item -> Exc.catch-		(removeFile item)-		(\exc -> do-			isDir <- isRealDir item-			if isDir-				then removeTree item-				else Exc.throwIO (exc :: IOError))-	removeDirectory root+  items <- listDirectory root+  forM_ items $ \item -> Exc.catch+    (removeFile item)+    (\exc -> do+      isDir <- isRealDir item+      if isDir+        then removeTree item+        else Exc.throwIO (exc :: IOError))+  removeDirectory root  -- Check whether a path is a directory, and not just a symlink to a directory. --@@ -440,11 +440,11 @@ -- itself cannot be deleted. isRealDir :: FilePath -> IO Bool isRealDir path = withFilePath path $ \cPath -> do-	rc <- throwErrnoPathIfMinus1Retry "removeTree" path (c_isrealdir cPath)-	return (rc == 1)+  rc <- throwErrnoPathIfMinus1Retry "removeTree" path (c_isrealdir cPath)+  return (rc == 1)  foreign import ccall unsafe "hssystemfileio_isrealdir"-	c_isrealdir :: CString -> IO CInt+  c_isrealdir :: CString -> IO CInt  #endif @@ -457,18 +457,18 @@ getWorkingDirectory = do #ifdef CABAL_OS_WINDOWS #if MIN_VERSION_Win32(2,2,1)-	fmap decodeString Win32.getCurrentDirectory+  fmap decodeString Win32.getCurrentDirectory #else-	fmap decodeString (Win32.try "getWorkingDirectory" (flip c_GetCurrentDirectoryW) 512)+  fmap decodeString (Win32.try "getWorkingDirectory" (flip c_GetCurrentDirectoryW) 512) #endif #else-	buf <- CError.throwErrnoIfNull "getWorkingDirectory" c_getcwd-	bytes <- B.packCString buf-	c_free buf-	return (R.decode R.posix bytes)+  buf <- CError.throwErrnoIfNull "getWorkingDirectory" c_getcwd+  bytes <- B.packCString buf+  c_free buf+  return (R.decode R.posix bytes)  foreign import ccall unsafe "hssystemfileio_getcwd"-	c_getcwd :: IO CString+  c_getcwd :: IO CString  #endif @@ -476,7 +476,7 @@ #if MIN_VERSION_Win32(2,2,1) #else foreign import stdcall unsafe "GetCurrentDirectoryW"-	c_GetCurrentDirectoryW :: Win32.DWORD -> Win32.LPTSTR -> IO Win32.UINT+  c_GetCurrentDirectoryW :: Win32.DWORD -> Win32.LPTSTR -> IO Win32.UINT #endif #endif @@ -488,13 +488,13 @@ setWorkingDirectory :: FilePath -> IO () setWorkingDirectory path = #ifdef CABAL_OS_WINDOWS-	Win32.setCurrentDirectory (encodeString path)+  Win32.setCurrentDirectory (encodeString path) #else-	withFilePath path $ \cPath ->-	throwErrnoPathIfMinus1Retry_ "setWorkingDirectory" path (c_chdir cPath)+  withFilePath path $ \cPath ->+  throwErrnoPathIfMinus1Retry_ "setWorkingDirectory" path (c_chdir cPath)  foreign import ccall unsafe "chdir"-	c_chdir :: CString -> IO CInt+  c_chdir :: CString -> IO CInt  #endif @@ -518,12 +518,12 @@ getHomeDirectory = fmap decodeString SD.getHomeDirectory #else getHomeDirectory = do-	path <- getenv "HOME"-	case path of-		Just p -> return p-		Nothing -> do-			-- use getEnv to throw the right exception type-			fmap decodeString (SE.getEnv "HOME")+  path <- getenv "HOME"+  case path of+    Just p -> return p+    Nothing -> do+      -- use getEnv to throw the right exception type+      fmap decodeString (SE.getEnv "HOME") #endif  -- | Get the user&#x2019;s desktop directory. This is a good starting point for@@ -535,7 +535,7 @@ -- why the failure occured. getDesktopDirectory :: IO FilePath getDesktopDirectory = xdg "XDG_DESKTOP_DIR" Nothing-	(homeSlash "Desktop")+  (homeSlash "Desktop")  -- | Get the user&#x2019;s documents directory. This is a good place to save -- user&#8208;created files. For data files the user does not explicitly@@ -547,9 +547,9 @@ getDocumentsDirectory :: IO FilePath getDocumentsDirectory = xdg "XDG_DOCUMENTS_DIR" Nothing #ifdef CABAL_OS_WINDOWS-	(fmap decodeString SD.getUserDocumentsDirectory)+  (fmap decodeString SD.getUserDocumentsDirectory) #else-	(homeSlash "Documents")+  (homeSlash "Documents") #endif  -- | Get the user&#x2019;s application data directory, given an application@@ -562,9 +562,9 @@ getAppDataDirectory :: T.Text -> IO FilePath getAppDataDirectory label = xdg "XDG_DATA_HOME" (Just label) #ifdef CABAL_OS_WINDOWS-	(fmap decodeString (SD.getAppUserDataDirectory ""))+  (fmap decodeString (SD.getAppUserDataDirectory "")) #else-	(homeSlash ".local/share")+  (homeSlash ".local/share") #endif  -- | Get the user&#x2019;s application cache directory, given an application@@ -577,9 +577,9 @@ getAppCacheDirectory :: T.Text -> IO FilePath getAppCacheDirectory label = xdg "XDG_CACHE_HOME" (Just label) #ifdef CABAL_OS_WINDOWS-	(homeSlash "Local Settings\\Cache")+  (homeSlash "Local Settings\\Cache") #else-	(homeSlash ".cache")+  (homeSlash ".cache") #endif  -- | Get the user&#x2019;s application configuration directory, given an@@ -592,46 +592,46 @@ getAppConfigDirectory :: T.Text -> IO FilePath getAppConfigDirectory label = xdg "XDG_CONFIG_HOME" (Just label) #ifdef CABAL_OS_WINDOWS-	(homeSlash "Local Settings")+  (homeSlash "Local Settings") #else-	(homeSlash ".config")+  (homeSlash ".config") #endif  homeSlash :: String -> IO FilePath homeSlash path = do-	home <- getHomeDirectory-	return (append home (decodeString path))+  home <- getHomeDirectory+  return (append home (decodeString path))  getenv :: String -> IO (Maybe FilePath) #ifdef CABAL_OS_WINDOWS getenv key = Exc.catch-	(fmap (Just . decodeString) (SE.getEnv key))-	(\e -> if isDoesNotExistError e-		then return Nothing-		else Exc.throwIO e)+  (fmap (Just . decodeString) (SE.getEnv key))+  (\e -> if isDoesNotExistError e+    then return Nothing+    else Exc.throwIO e) #else getenv key = withCAString key $ \cKey -> do-	ret <- c_getenv cKey-	if ret == nullPtr-		then return Nothing-		else do-			bytes <- B.packCString ret-			return (Just (R.decode R.posix bytes))+  ret <- c_getenv cKey+  if ret == nullPtr+    then return Nothing+    else do+      bytes <- B.packCString ret+      return (Just (R.decode R.posix bytes))  foreign import ccall unsafe "getenv"-	c_getenv :: CString -> IO CString+  c_getenv :: CString -> IO CString  #endif  xdg :: String -> Maybe T.Text -> IO FilePath -> IO FilePath xdg envkey label fallback = do-	env <- getenv envkey-	dir <- case env of-		Just var -> return var-		Nothing -> fallback-	return $ case label of-		Just text -> append dir (R.fromText currentOS text)-		Nothing -> dir+  env <- getenv envkey+  dir <- case env of+    Just var -> return var+    Nothing -> fallback+  return $ case label of+    Just text -> append dir (R.fromText currentOS text)+    Nothing -> dir  -- | Copy the content of a file to a new entry in the filesystem. If a -- file already exists at the new location, it will be replaced. Copying@@ -646,9 +646,9 @@                 -> FilePath -- ^ New location                 -> IO () copyFileContent oldPath newPath =-	withFile oldPath IO.ReadMode $ \old ->-	withFile newPath IO.WriteMode $ \new ->-	BL.hGetContents old >>= BL.hPut new+  withFile oldPath IO.ReadMode $ \old ->+  withFile newPath IO.WriteMode $ \new ->+  BL.hGetContents old >>= BL.hPut new  -- | Copy the permissions from one path to another. Both paths must already -- exist.@@ -662,20 +662,20 @@                 -> FilePath -- ^ New location                 -> IO () copyPermissions oldPath newPath =-	withFilePath oldPath $ \cOldPath ->-	withFilePath newPath $ \cNewPath ->-	CError.throwErrnoIfMinus1Retry_ "copyPermissions" $-	c_copy_permissions cOldPath cNewPath+  withFilePath oldPath $ \cOldPath ->+  withFilePath newPath $ \cNewPath ->+  CError.throwErrnoIfMinus1Retry_ "copyPermissions" $+  c_copy_permissions cOldPath cNewPath  #ifdef CABAL_OS_WINDOWS  foreign import ccall unsafe "hssystemfileio_copy_permissions"-	c_copy_permissions :: CWString -> CWString -> IO CInt+  c_copy_permissions :: CWString -> CWString -> IO CInt  #else  foreign import ccall unsafe "hssystemfileio_copy_permissions"-	c_copy_permissions :: CString -> CString -> IO CInt+  c_copy_permissions :: CString -> CString -> IO CInt  #endif @@ -692,10 +692,10 @@          -> FilePath -- ^ New location          -> IO () copyFile oldPath newPath = do-	copyFileContent oldPath newPath-	Exc.catch-		(copyPermissions oldPath newPath)-		((\_ -> return ()) :: IOError -> IO ())+  copyFileContent oldPath newPath+  Exc.catch+    (copyPermissions oldPath newPath)+    ((\_ -> return ()) :: IOError -> IO ())  -- | Get when the object at a given path was last modified. --@@ -707,28 +707,28 @@ getModified :: FilePath -> IO UTCTime getModified path = do #ifdef CABAL_OS_WINDOWS-	info <- withHANDLE path Win32.getFileInformationByHandle-	let ftime = Win32.bhfiLastWriteTime info-	stime <- Win32.fileTimeToSystemTime ftime-	-	let date = fromGregorian-		(fromIntegral (Win32.wYear stime))-		(fromIntegral (Win32.wMonth stime))-		(fromIntegral (Win32.wDay stime))-	-	let seconds = secondsToDiffTime $-		(toInteger (Win32.wHour stime) * 3600) +-		(toInteger (Win32.wMinute stime) * 60) +-		(toInteger (Win32.wSecond stime))-	-	let msecs = picosecondsToDiffTime $-		(toInteger (Win32.wMilliseconds stime) * 1000000000)-	-	return (UTCTime date (seconds + msecs))+  info <- withHANDLE path Win32.getFileInformationByHandle+  let ftime = Win32.bhfiLastWriteTime info+  stime <- Win32.fileTimeToSystemTime ftime++  let date = fromGregorian+    (fromIntegral (Win32.wYear stime))+    (fromIntegral (Win32.wMonth stime))+    (fromIntegral (Win32.wDay stime))++  let seconds = secondsToDiffTime $+    (toInteger (Win32.wHour stime) * 3600) ++    (toInteger (Win32.wMinute stime) * 60) ++    (toInteger (Win32.wSecond stime))++  let msecs = picosecondsToDiffTime $+    (toInteger (Win32.wMilliseconds stime) * 1000000000)++  return (UTCTime date (seconds + msecs)) #else-	stat <- posixStat "getModified" path-	let mtime = Posix.modificationTime stat-	return (posixSecondsToUTCTime (realToFrac mtime))+  stat <- posixStat "getModified" path+  let mtime = Posix.modificationTime stat+  return (posixSecondsToUTCTime (realToFrac mtime)) #endif  -- | Get the size of an object at a given path. For special objects like@@ -743,11 +743,11 @@ getSize :: FilePath -> IO Integer getSize path = do #ifdef CABAL_OS_WINDOWS-	info <- withHANDLE path Win32.getFileInformationByHandle-	return (toInteger (Win32.bhfiSize info))+  info <- withHANDLE path Win32.getFileInformationByHandle+  return (toInteger (Win32.bhfiSize info)) #else-	stat <- posixStat "getSize" path-	return (toInteger (Posix.fileSize stat))+  stat <- posixStat "getSize" path+  return (toInteger (Posix.fileSize stat)) #endif  -- | Open a file in binary mode, and return an open 'Handle'. The 'Handle'@@ -783,7 +783,7 @@ -- why the failure occured. readFile :: FilePath -> IO B.ByteString readFile path = withFile path IO.ReadMode-	(\h -> IO.hFileSize h >>= B.hGet h . fromIntegral)+  (\h -> IO.hFileSize h >>= B.hGet h . fromIntegral)  -- | Replace the entire content of a binary file with the provided -- 'B.ByteString'.@@ -793,7 +793,7 @@ -- why the failure occured. writeFile :: FilePath -> B.ByteString -> IO () writeFile path bytes = withFile path IO.WriteMode-	(\h -> B.hPut h bytes)+  (\h -> B.hPut h bytes)  -- | Append a 'B.ByteString' to a file. If the file does not exist, it will -- be created.@@ -803,7 +803,7 @@ -- why the failure occured. appendFile :: FilePath -> B.ByteString -> IO () appendFile path bytes = withFile path IO.AppendMode-	(\h -> B.hPut h bytes)+  (\h -> B.hPut h bytes)  -- | Open a file in text mode, and return an open 'Handle'. The 'Handle' -- should be closed with 'IO.hClose' when it is no longer needed.@@ -847,7 +847,7 @@ -- why the failure occured. writeTextFile :: FilePath -> T.Text -> IO () writeTextFile path text = withTextFile path IO.WriteMode-	(\h -> T.hPutStr h text)+  (\h -> T.hPutStr h text)  -- | Append 'T.Text' to a file. If the file does not exist, it will -- be created.@@ -857,47 +857,47 @@ -- why the failure occured. appendTextFile :: FilePath -> T.Text -> IO () appendTextFile path text = withTextFile path IO.AppendMode-	(\h -> T.hPutStr h text)+  (\h -> T.hPutStr h text)  #ifdef SYSTEMFILEIO_LOCAL_OPEN_FILE -- | Copied from GHC.IO.FD.openFile openFile' :: String -> FilePath -> IO.IOMode -> (Maybe IO.TextEncoding) -> IO IO.Handle openFile' loc path mode codec = open where-	sys_c_open = System.Posix.Internals.c_open-	sys_c_close = System.Posix.Internals.c_close-	flags = iomodeFlags mode-	open = withFilePath path $ \cPath -> do-		c_fd <- throwErrnoPathIfMinus1Retry loc path (sys_c_open cPath flags 0o666)-		(fd, fd_type) <- Exc.onException-			(mkFD c_fd mode Nothing False True)-			(sys_c_close c_fd)-		when (mode == IO.WriteMode && fd_type == GHC.IO.Device.RegularFile) $ do-			GHC.IO.Device.setSize fd 0-		Exc.onException-			(mkHandleFromFD fd fd_type (encodeString path) mode False codec)-			(GHC.IO.Device.close fd)+  sys_c_open = System.Posix.Internals.c_open+  sys_c_close = System.Posix.Internals.c_close+  flags = iomodeFlags mode+  open = withFilePath path $ \cPath -> do+    c_fd <- throwErrnoPathIfMinus1Retry loc path (sys_c_open cPath flags 0o666)+    (fd, fd_type) <- Exc.onException+      (mkFD c_fd mode Nothing False True)+      (sys_c_close c_fd)+    when (mode == IO.WriteMode && fd_type == GHC.IO.Device.RegularFile) $ do+      GHC.IO.Device.setSize fd 0+    Exc.onException+      (mkHandleFromFD fd fd_type (encodeString path) mode False codec)+      (GHC.IO.Device.close fd)  iomodeFlags :: IO.IOMode -> CInt iomodeFlags mode = cased .|. commonFlags where-	cased = case mode of-		IO.ReadMode -> flagsR+  cased = case mode of+    IO.ReadMode -> flagsR #ifdef mingw32_HOST_OS-		IO.WriteMode -> flagsW .|. System.Posix.Internals.o_TRUNC+    IO.WriteMode -> flagsW .|. System.Posix.Internals.o_TRUNC #else-		IO.WriteMode -> flagsW+    IO.WriteMode -> flagsW #endif-		IO.ReadWriteMode -> flagsRW-		IO.AppendMode -> flagsA-	-	flagsR  = System.Posix.Internals.o_RDONLY-	flagsW  = outputFlags .|. System.Posix.Internals.o_WRONLY-	flagsRW = outputFlags .|. System.Posix.Internals.o_RDWR-	flagsA  = flagsW      .|. System.Posix.Internals.o_APPEND-	-	commonFlags = System.Posix.Internals.o_NOCTTY .|.-	              System.Posix.Internals.o_NONBLOCK-	outputFlags = System.Posix.Internals.o_CREAT+    IO.ReadWriteMode -> flagsRW+    IO.AppendMode -> flagsA +  flagsR  = System.Posix.Internals.o_RDONLY+  flagsW  = outputFlags .|. System.Posix.Internals.o_WRONLY+  flagsRW = outputFlags .|. System.Posix.Internals.o_RDWR+  flagsA  = flagsW      .|. System.Posix.Internals.o_APPEND++  commonFlags = System.Posix.Internals.o_NOCTTY .|.+                System.Posix.Internals.o_NONBLOCK+  outputFlags = System.Posix.Internals.o_CREAT+ #endif  #ifdef CABAL_OS_WINDOWS@@ -906,15 +906,15 @@ -- See issue #8. withHANDLE :: FilePath -> (Win32.HANDLE -> IO a) -> IO a withHANDLE path = Exc.bracket open close where-	open = Win32.createFile-		(encodeString path)-		0-		(Win32.fILE_SHARE_READ .|. Win32.fILE_SHARE_WRITE)-		Nothing-		Win32.oPEN_EXISTING-		Win32.fILE_FLAG_BACKUP_SEMANTICS-		Nothing-	close = Win32.closeHandle+  open = Win32.createFile+    (encodeString path)+    0+    (Win32.fILE_SHARE_READ .|. Win32.fILE_SHARE_WRITE)+    Nothing+    Win32.oPEN_EXISTING+    Win32.fILE_FLAG_BACKUP_SEMANTICS+    Nothing+  close = Win32.closeHandle  withFilePath :: FilePath -> (CWString -> IO a) -> IO a withFilePath path = withCWString (encodeString path)@@ -941,20 +941,20 @@  throwErrnoPathIfRetry :: (a -> Bool) -> String -> FilePath -> IO a -> IO a throwErrnoPathIfRetry failed loc path io = loop where-	loop = do-		a <- io-		if failed a-			then do-				errno <- CError.getErrno-				if errno == CError.eINTR-					then loop-					else CError.throwErrnoPath loc (encodeString path)-			else return a+  loop = do+    a <- io+    if failed a+      then do+        errno <- CError.getErrno+        if errno == CError.eINTR+          then loop+          else CError.throwErrnoPath loc (encodeString path)+      else return a  throwErrnoPathIfRetry_ :: (a -> Bool) -> String -> FilePath -> IO a -> IO () throwErrnoPathIfRetry_ failed loc path io = do-	_ <- throwErrnoPathIfRetry failed loc path io-	return ()+  _ <- throwErrnoPathIfRetry failed loc path io+  return ()  posixStat :: String -> FilePath -> IO Posix.FileStatus #if MIN_VERSION_unix(2,5,1)@@ -964,17 +964,17 @@  withFd :: String -> FilePath -> (Posix.Fd -> IO a) -> IO a withFd fnName path = Exc.bracket open close where-	open = withFilePath path $ \cpath -> do-		fd <- throwErrnoPathIfMinus1 fnName path (c_open_nonblocking cpath 0)-		return (Posix.Fd fd)-	close = Posix.closeFd+  open = withFilePath path $ \cpath -> do+    fd <- throwErrnoPathIfMinus1 fnName path (c_open_nonblocking cpath 0)+    return (Posix.Fd fd)+  close = Posix.closeFd  foreign import ccall unsafe "hssystemfileio_open_nonblocking"-	c_open_nonblocking :: CString -> CInt -> IO CInt+  c_open_nonblocking :: CString -> CInt -> IO CInt  #endif  foreign import ccall unsafe "free"-	c_free :: Ptr a -> IO ()+  c_free :: Ptr a -> IO ()  #endif
system-fileio.cabal view
@@ -1,22 +1,24 @@+cabal-version: 1.18 name: system-fileio-version: 0.3.16.4+version: 0.3.16.5 license: MIT license-file: license.txt author: John Millikin <jmillikin@gmail.com>-maintainer: FP Complete <michael@fpcomplete.com>+maintainer: https://github.com/fpco/haskell-filesystem build-type: Simple-cabal-version: >= 1.8 category: System stability: experimental homepage: https://github.com/fpco/haskell-filesystem bug-reports: https://github.com/fpco/haskell-filesystem/issues  synopsis: Consistent filesystem interaction across GHC versions (deprecated)-description: Please see: https://plus.google.com/+MichaelSnoyman/posts/Ft5hnPqpgEx+description: Consistent filesystem interaction across GHC versions (deprecated package). -extra-source-files:+extra-doc-files:   README.md   ChangeLog.md++extra-source-files:   lib/hssystemfileio-unix.h   lib/hssystemfileio-win32.h   --@@ -26,6 +28,21 @@   tests/FilesystemTests/Util.hs   tests/FilesystemTests/Windows.hs +tested-with:+  GHC == 9.12.0+  GHC == 9.10.1+  GHC == 9.8.2+  GHC == 9.6.6+  GHC == 9.4.8+  GHC == 9.2.8+  GHC == 9.0.2+  GHC == 8.10.7+  GHC == 8.8.4+  GHC == 8.6.5+  GHC == 8.4.4+  GHC == 8.2.2+  GHC == 8.0.2+ source-repository head   type: git   location: https://github.com/fpco/haskell-filesystem.git@@ -35,11 +52,11 @@   hs-source-dirs: lib    build-depends:-      base >= 4.0 && < 5.0+      base >= 4.0 && < 5     , bytestring >= 0.9     , system-filepath >= 0.3.1 && < 0.5     , text >= 0.7.1-    , time >= 1.0 && < 2.0+    , time >= 1.0 && < 2    if os(windows)     cpp-options: -DCABAL_OS_WINDOWS@@ -57,6 +74,8 @@   exposed-modules:     Filesystem +  default-language: Haskell2010+ test-suite filesystem_tests   type: exitcode-stdio-1.0   main-is: FilesystemTests.hs@@ -66,14 +85,14 @@   hs-source-dirs: tests    build-depends:-      base >= 4.0 && < 5.0+      base >= 4.0 && < 5     , bytestring >= 0.9-    , chell >= 0.4 && < 0.5+    , chell >= 0.4 && < 0.6     , system-fileio     , system-filepath-    , temporary >= 1.1 && < 2.0+    , temporary >= 1.1 && < 2     , text-    , time >= 1.0 && < 2.0+    , time >= 1.0 && < 2     , transformers >= 0.2    if os(windows)@@ -89,3 +108,5 @@     FilesystemTests.Posix     FilesystemTests.Util     FilesystemTests.Windows++  default-language: Haskell2010
tests/FilesystemTests.hs view
@@ -7,9 +7,9 @@ -- -- See license.txt for details module Main-	( tests-	, main-	) where+  ( tests+  , main+  ) where  import           Test.Chell 
tests/FilesystemTests/Posix.hs view
@@ -7,795 +7,803 @@ -- -- See license.txt for details module FilesystemTests.Posix-	( suite_Posix-	) where--import           Prelude hiding (FilePath)-import           Control.Exception (bracket)-import           Control.Monad-import           Control.Monad.IO.Class (liftIO)-import qualified Data.ByteString-import           Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as Char8-import qualified Data.Text-import           Data.Text (Text)-import qualified Data.Text.IO-import           Data.Time.Clock (diffUTCTime, getCurrentTime)-import           Foreign-import           Foreign.C-import           Test.Chell--#if MIN_VERSION_base(4,2,0)-import qualified GHC.IO.Exception as GHC-#else-import qualified GHC.IOBase as GHC-#endif--import qualified System.Posix.IO as PosixIO--import           Filesystem-import           Filesystem.Path-import qualified Filesystem.Path.Rules as Rules-import qualified Filesystem.Path.CurrentOS as CurrentOS--import           FilesystemTests.Util (assertionsWithTemp, todo)--suite_Posix :: Suite-suite_Posix = suite "posix" $-	(concatMap suiteTests-		[ suite_IsFile-		, suite_IsDirectory-		, suite_Rename-		, suite_CanonicalizePath-		, suite_CreateDirectory-		, suite_CreateTree-		, suite_RemoveFile-		, suite_RemoveDirectory-		, suite_RemoveTree-		, suite_GetWorkingDirectory-		, suite_SetWorkingDirectory-		, suite_GetHomeDirectory-		, suite_GetDesktopDirectory-		, suite_GetModified-		, suite_GetSize-		, suite_CopyFile-		, suite_WithFile-		, suite_WithTextFile-		, suite_RegressionTests-		]) ++-	[ test_ListDirectory-	, todo "getDocumentsDirectory"-	, todo "getAppDataDirectory"-	, todo "getAppCacheDirectory"-	, todo "getAppConfigDirectory"-	, todo "openFile"-	, todo "readFile"-	, todo "writeFile"-	, todo "appendFile"-	, todo "openTextFile"-	, todo "readTextFile"-	, todo "writeTextFile"-	, todo "appendTextFile"-	]--suite_IsFile :: Suite-suite_IsFile = suite "isFile"-	[ test_IsFile "ascii" (decode "test.txt")-	, test_IsFile "utf8" (fromText "\xA1\xA2.txt")-	, test_IsFile "iso8859" (decode "\xA1\xA2\xA3.txt")-	, test_PipeIsFile "pipe.ascii" (decode "test.txt")-	, test_PipeIsFile "pipe.utf8" (fromText "\xA1\xA2.txt")-	, test_PipeIsFile "pipe.iso8859" (decode "\xA1\xA2\xA3.txt")-	]--suite_IsDirectory :: Suite-suite_IsDirectory = suite "isDirectory"-	[ test_IsDirectory "ascii" (decode "test.d")-	, test_IsDirectory "utf8" (fromText "\xA1\xA2.d")-	, test_IsDirectory "iso8859" (decode "\xA1\xA2\xA3.d")-	]--suite_Rename :: Suite-suite_Rename = suite "rename"-	[ test_Rename "ascii"-		(decode "old_test.txt")-		(decode "new_test.txt")-	, test_Rename "utf8"-		(fromText "old_\xA1\xA2.txt")-		(fromText "new_\xA1\xA2.txt")-	, test_Rename "iso8859"-		(decode "old_\xA1\xA2\xA3.txt")-		(decode "new_\xA1\xA2\xA3.txt")-	]--suite_CanonicalizePath :: Suite-suite_CanonicalizePath = suite "canonicalizePath"-	[ test_CanonicalizePath "ascii"-		(decode "test-a.txt")-		(decode "test-b.txt")-	, test_CanonicalizePath "utf8"-		(fromText "\xA1\xA2-a.txt")-		(fromText "\xA1\xA2-b.txt")-	, test_CanonicalizePath "iso8859"-		(decode "\xA1\xA2\xA3-a.txt")-#ifdef CABAL_OS_DARWIN-		(decode "%A1%A2%A3-b.txt")-#else-		(decode "\xA1\xA2\xA3-b.txt")-#endif-	, test_CanonicalizePath_TrailingSlash-	]--suite_CreateDirectory :: Suite-suite_CreateDirectory = suite "createDirectory"-	[ test_CreateDirectory "ascii"-		(decode "test.d")-	, test_CreateDirectory "utf8"-		(fromText "\xA1\xA2.d")-	, test_CreateDirectory "iso8859"-		(decode "\xA1\xA2\xA3.d")-	, test_CreateDirectory_FailExists-	, test_CreateDirectory_SucceedExists-	, test_CreateDirectory_FailFileExists-	]--suite_CreateTree :: Suite-suite_CreateTree = suite "createTree"-	[ test_CreateTree "ascii"-		(decode "test.d")-	, test_CreateTree "ascii-slash"-		(decode "test.d/")-	, test_CreateTree "utf8"-		(fromText "\xA1\xA2.d")-	, test_CreateTree "utf8-slash"-		(fromText "\xA1\xA2.d/")-	, test_CreateTree "iso8859"-		(decode "\xA1\xA2\xA3.d")-	, test_CreateTree "iso8859-slash"-		(decode "\xA1\xA2\xA3.d/")-	]--suite_RemoveFile :: Suite-suite_RemoveFile = suite "removeFile"-	[ test_RemoveFile "ascii"-		(decode "test.txt")-	, test_RemoveFile "utf8"-		(fromText "\xA1\xA2.txt")-	, test_RemoveFile "iso8859"-		(decode "\xA1\xA2\xA3.txt")-	]--suite_RemoveDirectory :: Suite-suite_RemoveDirectory = suite "removeDirectory"-	[ test_RemoveDirectory "ascii"-		(decode "test.d")-	, test_RemoveDirectory "utf8"-		(fromText "\xA1\xA2.d")-	, test_RemoveDirectory "iso8859"-		(decode "\xA1\xA2\xA3.d")-	]--suite_RemoveTree :: Suite-suite_RemoveTree = suite "removeTree"-	[ test_RemoveTree "ascii"-		(decode "test.d")-	, test_RemoveTree "utf8"-		(fromText "\xA1\xA2.d")-	, test_RemoveTree "iso8859"-		(decode "\xA1\xA2\xA3.d")-	]--suite_GetWorkingDirectory :: Suite-suite_GetWorkingDirectory = suite "getWorkingDirectory"-	[ test_GetWorkingDirectory "ascii"-		(decode "test.d")-	, test_GetWorkingDirectory "utf8"-		(fromText "\xA1\xA2.d")-	, test_GetWorkingDirectory "iso8859"-		(decode "\xA1\xA2\xA3.d")-	]--suite_SetWorkingDirectory :: Suite-suite_SetWorkingDirectory = suite "setWorkingDirectory"-	[ test_SetWorkingDirectory "ascii"-		(decode "test.d")-	, test_SetWorkingDirectory "utf8"-		(fromText "\xA1\xA2.d")-	, test_SetWorkingDirectory "iso8859"-		(decode "\xA1\xA2\xA3.d")-	]--suite_GetHomeDirectory :: Suite-suite_GetHomeDirectory = suite "getHomeDirectory"-	[ test_GetHomeDirectory "ascii"-		(decode "/home/test.d")-	, test_GetHomeDirectory "utf8"-		(decode "/home/\xA1\xA2.d")-	, test_GetHomeDirectory "iso8859"-		(decode "/home/\xA1\xA2\xA3.d")-	]--suite_GetDesktopDirectory :: Suite-suite_GetDesktopDirectory = suite "getDesktopDirectory"-	[ test_GetDesktopDirectory "ascii"-		(decode "/desktop/test.d")-	, test_GetDesktopDirectory "utf8"-		(decode "/desktop/\xA1\xA2.d")-	, test_GetDesktopDirectory "iso8859"-		(decode "/desktop/\xA1\xA2\xA3.d")-	]--suite_GetModified :: Suite-suite_GetModified = suite "getModified"-	[ test_GetModified "ascii"-		(decode "test.txt")-	, test_GetModified "utf8"-		(fromText "\xA1\xA2.txt")-	, test_GetModified "iso8859"-		(decode "\xA1\xA2\xA3.txt")-	]--suite_GetSize :: Suite-suite_GetSize = suite "getSize"-	[ test_GetSize "ascii"-		(decode "test.txt")-	, test_GetSize "utf8"-		(fromText "\xA1\xA2.txt")-	, test_GetSize "iso8859"-		(decode "\xA1\xA2\xA3.txt")-	]--suite_CopyFile :: Suite-suite_CopyFile = suite "copyFile"-	[ test_CopyFile "ascii"-		(decode "old_test.txt")-		(decode "new_test.txt")-	, test_CopyFile "utf8"-		(fromText "old_\xA1\xA2.txt")-		(fromText "new_\xA1\xA2.txt")-	, test_CopyFile "iso8859"-#ifdef CABAL_OS_DARWIN-		(decode "old_%A1%A2%A3.txt")-#else-		(decode "old_\xA1\xA2\xA3.txt")-#endif-#ifdef CABAL_OS_DARWIN-		(decode "new_%A1%A2%A3.txt")-#else-		(decode "new_\xA1\xA2\xA3.txt")-#endif-	]--suite_WithFile :: Suite-suite_WithFile = suite "withFile"-	[ test_WithFile_Read "read.ascii"-		(decode "test.txt")-	, test_WithFile_Read "read.utf8"-		(fromText "\xA1\xA2.txt")-	, test_WithFile_Read "read.iso8859"-#ifdef CABAL_OS_DARWIN-		(decode "%A1%A2%A3.txt")-#else-		(decode "\xA1\xA2\xA3.txt")-#endif-	, test_WithFile_Write "write.ascii"-		(decode "test.txt")-	, test_WithFile_Write "write.utf8"-		(fromText "\xA1\xA2.txt")-	, test_WithFile_Write "write.iso8859"-		(decode "\xA1\xA2\xA3.txt")-	]--suite_WithTextFile :: Suite-suite_WithTextFile = suite "withTextFile"-	[ test_WithTextFile "ascii"-		(decode "test.txt")-	, test_WithTextFile "utf8"-		(fromText "\xA1\xA2.txt")-	, test_WithTextFile "iso8859"-#ifdef CABAL_OS_DARWIN-		(decode "%A1%A2%A3.txt")-#else-		(decode "\xA1\xA2\xA3.txt")-#endif-	]--suite_RegressionTests :: Suite-suite_RegressionTests = suite "regression-tests"-	[ test_ListDirectoryLeaksFds-	]--test_IsFile :: String -> FilePath -> Test-test_IsFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let path = tmp </> file_name-	-	before <- liftIO $ Filesystem.isFile path-	$expect (not before)-	-	touch_ffi path "contents\n"-	-	after <- liftIO $ Filesystem.isFile path-	$expect after--test_PipeIsFile :: String -> FilePath -> Test-test_PipeIsFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let path = tmp </> file_name-	-	before <- liftIO $ Filesystem.isFile path-	$expect (not before)-	-	mkfifo_ffi path-	-	after <- liftIO $ Filesystem.isFile path-	$expect after--test_IsDirectory :: String -> FilePath -> Test-test_IsDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	let path = tmp </> dir_name-	-	before <- liftIO $ Filesystem.isDirectory path-	$expect (not before)-	-	mkdir_ffi path-	-	after <- liftIO $ Filesystem.isDirectory path-	$expect after--test_Rename :: String -> FilePath -> FilePath -> Test-test_Rename test_name old_name new_name = assertionsWithTemp test_name $ \tmp -> do-	let old_path = tmp </> old_name-	let new_path = tmp </> new_name-	-	touch_ffi old_path ""-	-	old_before <- liftIO $ Filesystem.isFile old_path-	new_before <- liftIO $ Filesystem.isFile new_path-	$expect old_before-	$expect (not new_before)-	-	liftIO $ Filesystem.rename old_path new_path-	-	old_after <- liftIO $ Filesystem.isFile old_path-	new_after <- liftIO $ Filesystem.isFile new_path-	$expect (not old_after)-	$expect new_after--test_CopyFile :: String -> FilePath -> FilePath -> Test-test_CopyFile test_name old_name new_name = assertionsWithTemp test_name $ \tmp -> do-	let old_path = tmp </> old_name-	let new_path = tmp </> new_name-	-	touch_ffi old_path ""-	-	old_before <- liftIO $ Filesystem.isFile old_path-	new_before <- liftIO $ Filesystem.isFile new_path-	$expect old_before-	$expect (not new_before)-	-	liftIO $ Filesystem.copyFile old_path new_path-	-	old_after <- liftIO $ Filesystem.isFile old_path-	new_after <- liftIO $ Filesystem.isFile new_path-	$expect old_after-	$expect new_after-	old_contents <- liftIO $-		Filesystem.withTextFile old_path ReadMode $-		Data.Text.IO.hGetContents-	new_contents <- liftIO $-		Filesystem.withTextFile new_path ReadMode $-		Data.Text.IO.hGetContents-	$expect (equalLines old_contents new_contents)--test_CanonicalizePath :: String -> FilePath -> FilePath -> Test-test_CanonicalizePath test_name src_name dst_name = assertionsWithTemp test_name $ \tmp -> do-	let src_path = tmp </> src_name-	let subdir = tmp </> "subdir"-	-	-- canonicalize the directory first, to avoid false negatives if-	-- it gets placed in a symlinked location.-	mkdir_ffi subdir-	canon_subdir <- liftIO (Filesystem.canonicalizePath subdir)-	-	let dst_path = canon_subdir </> dst_name-	-	touch_ffi dst_path ""-	symlink_ffi dst_path src_path-	-	canonicalized <- liftIO $ Filesystem.canonicalizePath src_path-	$expect $ equal canonicalized dst_path--test_CanonicalizePath_TrailingSlash :: Test-test_CanonicalizePath_TrailingSlash = assertionsWithTemp "trailing-slash" $ \tmp -> do-	let src_path = tmp </> "src"-	let subdir = tmp </> "subdir"-	-	-- canonicalize the directory first, to avoid false negatives if-	-- it gets placed in a symlinked location.-	mkdir_ffi subdir-	canon_subdir <- liftIO (Filesystem.canonicalizePath (tmp </> "subdir"))-	-	let dst_path = canon_subdir </> "dst"-	-	mkdir_ffi dst_path-	symlink_ffi dst_path src_path-	-	canonicalized <- liftIO (Filesystem.canonicalizePath (src_path </> empty))-	$expect (equal canonicalized (dst_path </> empty))--test_CreateDirectory :: String -> FilePath -> Test-test_CreateDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	let dir_path = tmp </> dir_name-	-	exists_before <- liftIO $ Filesystem.isDirectory dir_path-	$assert (not exists_before)-	-	liftIO $ Filesystem.createDirectory False dir_path-	exists_after <- liftIO $ Filesystem.isDirectory dir_path-	-	$expect exists_after--test_CreateDirectory_FailExists :: Test-test_CreateDirectory_FailExists = assertionsWithTemp "fail-if-exists" $ \tmp -> do-	let dir_path = tmp </> "subdir"-	mkdir_ffi dir_path-	-	$expect $ throwsEq-		(mkAlreadyExists "createDirectory" dir_path)-		(Filesystem.createDirectory False dir_path)--test_CreateDirectory_SucceedExists :: Test-test_CreateDirectory_SucceedExists = assertionsWithTemp "succeed-if-exists" $ \tmp -> do-	let dir_path = tmp </> "subdir"-	mkdir_ffi dir_path-	-	liftIO $ Filesystem.createDirectory True dir_path--test_CreateDirectory_FailFileExists :: Test-test_CreateDirectory_FailFileExists = assertionsWithTemp "fail-if-file-exists" $ \tmp -> do-	let dir_path = tmp </> "subdir"-	touch_ffi dir_path ""-	-	$expect $ throwsEq-		(mkAlreadyExists "createDirectory" dir_path)-		(Filesystem.createDirectory False dir_path)-	$expect $ throwsEq-		(mkAlreadyExists "createDirectory" dir_path)-		(Filesystem.createDirectory True dir_path)--mkAlreadyExists :: String -> FilePath -> GHC.IOError-mkAlreadyExists loc path = GHC.IOError Nothing GHC.AlreadyExists loc "File exists"-#if MIN_VERSION_base(4,2,0)-	(Just (errnoCInt eEXIST))-#endif-	(Just (CurrentOS.encodeString path))--test_CreateTree :: String -> FilePath -> Test-test_CreateTree test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	let dir_path = tmp </> dir_name-	let subdir = dir_path </> "subdir"-	-	dir_exists_before <- liftIO $ Filesystem.isDirectory dir_path-	subdir_exists_before <- liftIO $ Filesystem.isDirectory subdir-	$assert (not dir_exists_before)-	$assert (not subdir_exists_before)-	-	liftIO $ Filesystem.createTree subdir-	dir_exists_after <- liftIO $ Filesystem.isDirectory dir_path-	subdir_exists_after <- liftIO $ Filesystem.isDirectory subdir-	-	$expect dir_exists_after-	$expect subdir_exists_after--test_ListDirectory :: Test-test_ListDirectory = assertionsWithTemp "listDirectory" $ \tmp -> do-	-- OSX replaces non-UTF8 filenames with http-style %XX escapes-	let paths =-#ifdef CABAL_OS_DARWIN-		[ tmp </> decode "%A1%A2%A3.txt"-		, tmp </> decode "test.txt"-		, tmp </> fromText "\xA1\xA2.txt"-		]-#else-		[ tmp </> decode "test.txt"-		, tmp </> fromText "\xA1\xA2.txt"-		, tmp </> decode "\xA1\xA2\xA3.txt"-		]-#endif-	forM_ paths (\path -> touch_ffi path "")-	-	names <- liftIO $ Filesystem.listDirectory tmp-	$expect $ sameItems paths names--test_RemoveFile :: String -> FilePath -> Test-test_RemoveFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	-	touch_ffi file_path "contents\n"-	-	before <- liftIO $ Filesystem.isFile file_path-	$assert before-	-	liftIO $ Filesystem.removeFile file_path-	-	after <- liftIO $ Filesystem.isFile file_path-	$expect (not after)--test_RemoveDirectory :: String -> FilePath -> Test-test_RemoveDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	let dir_path = tmp </> dir_name-	-	mkdir_ffi dir_path-	-	before <- liftIO $ Filesystem.isDirectory dir_path-	$assert before-	-	liftIO $ Filesystem.removeDirectory dir_path-	-	after <- liftIO $ Filesystem.isDirectory dir_path-	$expect (not after)--test_RemoveTree :: String -> FilePath -> Test-test_RemoveTree test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	let dir_path = tmp </> dir_name-	let subdir = dir_path </> "subdir"-	-	mkdir_ffi dir_path-	mkdir_ffi subdir-	-	dir_before <- liftIO $ Filesystem.isDirectory dir_path-	subdir_before <- liftIO $ Filesystem.isDirectory subdir-	$assert dir_before-	$assert subdir_before-	-	liftIO $ Filesystem.removeTree dir_path-	-	dir_after <- liftIO $ Filesystem.isDirectory dir_path-	subdir_after <- liftIO $ Filesystem.isDirectory subdir-	$expect (not dir_after)-	$expect (not subdir_after)--test_GetWorkingDirectory :: String -> FilePath -> Test-test_GetWorkingDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	-- canonicalize to avoid issues with symlinked temp dirs-	canon_tmp <- liftIO (Filesystem.canonicalizePath tmp)-	let dir_path = canon_tmp </> dir_name-	-	mkdir_ffi dir_path-	chdir_ffi dir_path-	-	cwd <- liftIO $ Filesystem.getWorkingDirectory-	$expect (equal cwd dir_path)--test_SetWorkingDirectory :: String -> FilePath -> Test-test_SetWorkingDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do-	-- canonicalize to avoid issues with symlinked temp dirs-	canon_tmp <- liftIO (Filesystem.canonicalizePath tmp)-	let dir_path = canon_tmp </> dir_name-	-	mkdir_ffi dir_path-	liftIO $ Filesystem.setWorkingDirectory dir_path-	-	cwd <- getcwd_ffi-	$expect (equal cwd dir_path)--test_GetHomeDirectory :: String -> FilePath -> Test-test_GetHomeDirectory test_name dir_name = assertions test_name $ do-	path <- liftIO $ withEnv "HOME" (Just dir_name) Filesystem.getHomeDirectory-	$expect (equal path dir_name)--test_GetDesktopDirectory :: String -> FilePath -> Test-test_GetDesktopDirectory test_name dir_name = assertions test_name $ do-	path <- liftIO $-		withEnv "XDG_DESKTOP_DIR" (Just dir_name) $-		Filesystem.getDesktopDirectory-	$expect (equal path dir_name)-	-	fallback <- liftIO $-		withEnv "XDG_DESKTOP_DIR" Nothing $-		withEnv "HOME" (Just dir_name) $-		Filesystem.getDesktopDirectory-	$expect (equal fallback (dir_name </> "Desktop"))--test_GetModified :: String -> FilePath -> Test-test_GetModified test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	-	touch_ffi file_path ""-	now <- liftIO getCurrentTime-	-	mtime <- liftIO $ Filesystem.getModified file_path-	$expect (equalWithin (diffUTCTime mtime now) 0 2)--test_GetSize :: String -> FilePath -> Test-test_GetSize test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	let contents = "contents\n"-	-	touch_ffi file_path contents-	-	size <- liftIO $ Filesystem.getSize file_path-	$expect (equal size (toInteger (Data.ByteString.length contents)))--test_WithFile_Read :: String -> FilePath -> Test-test_WithFile_Read test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	let contents = "contents\n"-	-	touch_ffi file_path contents-	-	read_contents <- liftIO $-		Filesystem.withFile file_path ReadMode $-		Data.ByteString.hGetContents-	$expect (equalLines contents read_contents)--test_WithFile_Write :: String -> FilePath -> Test-test_WithFile_Write test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	let contents = "contents\n"-	-	liftIO $-		Filesystem.withFile file_path WriteMode $-		(\h -> Data.ByteString.hPut h contents)-	-	read_contents <- liftIO $-		Filesystem.withFile file_path ReadMode $-		Data.ByteString.hGetContents-	$expect (equalLines contents read_contents)--test_WithTextFile :: String -> FilePath -> Test-test_WithTextFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do-	let file_path = tmp </> file_name-	let contents = "contents\n"-	-	touch_ffi file_path (Char8.pack contents)-	-	read_contents <- liftIO $-		Filesystem.withTextFile file_path ReadMode $-		Data.Text.IO.hGetContents-	$expect (equalLines (Data.Text.pack contents) read_contents)--test_ListDirectoryLeaksFds :: Test-test_ListDirectoryLeaksFds = assertionsWithTemp "listDirectory-leaks-fds" $ \tmp -> do-	-- Test that listDirectory doesn't leak file descriptors.-	let dir_path = tmp </> "subdir"-	mkdir_ffi dir_path-	-	nullfd1 <- liftIO $ PosixIO.openFd "/dev/null" PosixIO.ReadOnly Nothing PosixIO.defaultFileFlags-	liftIO $ PosixIO.closeFd nullfd1-	-	subdirContents <- liftIO $ listDirectory dir_path-	-	nullfd2 <- liftIO $ PosixIO.openFd "/dev/null" PosixIO.ReadOnly Nothing PosixIO.defaultFileFlags-	liftIO $ PosixIO.closeFd nullfd2-	-	$assert (equal nullfd1 nullfd2)--withPathCString :: FilePath -> (CString -> IO a) -> IO a-withPathCString p = Data.ByteString.useAsCString (encode p)--decode :: ByteString -> FilePath-decode = Rules.decode Rules.posix--encode :: FilePath -> ByteString-encode = Rules.encode Rules.posix--fromText :: Text -> FilePath-fromText = Rules.fromText Rules.posix---- | Create a file using the raw POSIX API, via FFI-touch_ffi :: FilePath -> Data.ByteString.ByteString -> Assertions ()-touch_ffi path contents = do-	fp <- liftIO $ withPathCString path $ \path_cstr ->-		Foreign.C.withCString "wb" $ \mode_cstr ->-		c_fopen path_cstr mode_cstr-	-	$assert (fp /= nullPtr)-	-	_ <- liftIO $ Data.ByteString.useAsCStringLen contents $ \(buf, len) ->-		c_fwrite buf 1 (fromIntegral len) fp-	-	_ <- liftIO $ c_fclose fp-	return ()---- | Create a directory using the raw POSIX API, via FFI-mkdir_ffi :: FilePath -> Assertions ()-mkdir_ffi path = do-	ret <- liftIO $ withPathCString path $ \path_cstr ->-		c_mkdir path_cstr 0o700-	-	$assert (ret == 0)---- | Create a symlink using the raw POSIX API, via FFI-symlink_ffi :: FilePath -> FilePath -> Assertions ()-symlink_ffi dst src  = do-	ret <- liftIO $-		withPathCString dst $ \dst_p ->-		withPathCString src $ \src_p ->-		c_symlink dst_p src_p-	-	$assert (ret == 0)---- | Create a FIFO using the raw POSIX API, via FFI-mkfifo_ffi :: FilePath -> Assertions ()-mkfifo_ffi path = do-	ret <- liftIO $ withPathCString path $ \path_cstr ->-		c_mkfifo path_cstr 0o700-	-	$assert (ret == 0)--getcwd_ffi :: Assertions FilePath-getcwd_ffi = do-	buf <- liftIO $ c_getcwd nullPtr 0-	$assert (buf /= nullPtr)-	bytes <- liftIO $ Data.ByteString.packCString buf-	liftIO $ c_free buf-	return (decode bytes)--chdir_ffi :: FilePath -> Assertions ()-chdir_ffi path = do-	ret <- liftIO $-		withPathCString path $ \path_p ->-		c_chdir path_p-	$assert (ret == 0)--errnoCInt :: Errno -> CInt-errnoCInt (Errno x) = x--withEnv :: ByteString -> Maybe FilePath -> IO a -> IO a-withEnv name val io = bracket set unset (\_ -> io) where-	set = do-		old <- getEnv name-		setEnv name (fmap encode val)-		return old-	unset = setEnv name--getEnv :: ByteString -> IO (Maybe ByteString)-getEnv name = Data.ByteString.useAsCString name $ \cName -> do-	ret <- liftIO (c_getenv cName)-	if ret == nullPtr-		then return Nothing-		else fmap Just (Data.ByteString.packCString ret)--setEnv :: ByteString -> Maybe ByteString -> IO ()-setEnv name Nothing = throwErrnoIfMinus1_ "setEnv" $-	Data.ByteString.useAsCString name c_unsetenv-setEnv name (Just val) = throwErrnoIfMinus1_ "setEnv" $-	Data.ByteString.useAsCString name $ \cName ->-	Data.ByteString.useAsCString val $ \cVal ->-	c_setenv cName cVal 1--foreign import ccall unsafe "fopen"-	c_fopen :: CString -> CString -> IO (Ptr ())--foreign import ccall unsafe "fclose"-	c_fclose :: Ptr () -> IO CInt--foreign import ccall unsafe "fwrite"-	c_fwrite :: CString -> CSize -> CSize -> Ptr () -> IO CSize--foreign import ccall unsafe "mkdir"-	c_mkdir :: CString -> CInt -> IO CInt--foreign import ccall unsafe "symlink"-	c_symlink :: CString -> CString -> IO CInt--foreign import ccall unsafe "mkfifo"-	c_mkfifo :: CString -> CInt -> IO CInt--foreign import ccall unsafe "getcwd"-	c_getcwd :: CString -> CSize -> IO CString--foreign import ccall unsafe "chdir"-	c_chdir :: CString -> IO CInt--foreign import ccall unsafe "free"-	c_free :: Ptr a -> IO ()--foreign import ccall unsafe "getenv"-	c_getenv :: CString -> IO CString--foreign import ccall unsafe "setenv"-	c_setenv :: CString -> CString -> CInt -> IO CInt--foreign import ccall unsafe "unsetenv"-	c_unsetenv :: CString -> IO CInt+  ( suite_Posix+  ) where++import           Prelude hiding (FilePath)+import           Control.Exception (bracket)+import           Control.Monad+import           Control.Monad.IO.Class (liftIO)+import qualified Data.ByteString+import           Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as Char8+import qualified Data.Text+import           Data.Text (Text)+import qualified Data.Text.IO+import           Data.Time.Clock (diffUTCTime, getCurrentTime)+import           Foreign+import           Foreign.C+import           Test.Chell++#if MIN_VERSION_base(4,2,0)+import qualified GHC.IO.Exception as GHC+#else+import qualified GHC.IOBase as GHC+#endif++import qualified System.Posix.IO as PosixIO++import           Filesystem+import           Filesystem.Path+import qualified Filesystem.Path.Rules as Rules+import qualified Filesystem.Path.CurrentOS as CurrentOS++import           FilesystemTests.Util (assertionsWithTemp, todo)++suite_Posix :: Suite+suite_Posix = suite "posix" $+  (concatMap suiteTests+    [ suite_IsFile+    , suite_IsDirectory+    , suite_Rename+    , suite_CanonicalizePath+    , suite_CreateDirectory+    , suite_CreateTree+    , suite_RemoveFile+    , suite_RemoveDirectory+    , suite_RemoveTree+    , suite_GetWorkingDirectory+    , suite_SetWorkingDirectory+    , suite_GetHomeDirectory+    , suite_GetDesktopDirectory+    , suite_GetModified+    , suite_GetSize+    , suite_CopyFile+    , suite_WithFile+    , suite_WithTextFile+    , suite_RegressionTests+    ]) +++  [ test_ListDirectory+  , todo "getDocumentsDirectory"+  , todo "getAppDataDirectory"+  , todo "getAppCacheDirectory"+  , todo "getAppConfigDirectory"+  , todo "openFile"+  , todo "readFile"+  , todo "writeFile"+  , todo "appendFile"+  , todo "openTextFile"+  , todo "readTextFile"+  , todo "writeTextFile"+  , todo "appendTextFile"+  ]++suite_IsFile :: Suite+suite_IsFile = suite "isFile"+  [ test_IsFile "ascii" (decode "test.txt")+  , test_IsFile "utf8" (fromText "\xA1\xA2.txt")+  , test_IsFile "iso8859" (decode "\xA1\xA2\xA3.txt")+  , test_PipeIsFile "pipe.ascii" (decode "test.txt")+  , test_PipeIsFile "pipe.utf8" (fromText "\xA1\xA2.txt")+  , test_PipeIsFile "pipe.iso8859" (decode "\xA1\xA2\xA3.txt")+  ]++suite_IsDirectory :: Suite+suite_IsDirectory = suite "isDirectory"+  [ test_IsDirectory "ascii" (decode "test.d")+  , test_IsDirectory "utf8" (fromText "\xA1\xA2.d")+  , test_IsDirectory "iso8859" (decode "\xA1\xA2\xA3.d")+  ]++suite_Rename :: Suite+suite_Rename = suite "rename"+  [ test_Rename "ascii"+    (decode "old_test.txt")+    (decode "new_test.txt")+  , test_Rename "utf8"+    (fromText "old_\xA1\xA2.txt")+    (fromText "new_\xA1\xA2.txt")+  , test_Rename "iso8859"+    (decode "old_\xA1\xA2\xA3.txt")+    (decode "new_\xA1\xA2\xA3.txt")+  ]++suite_CanonicalizePath :: Suite+suite_CanonicalizePath = suite "canonicalizePath"+  [ test_CanonicalizePath "ascii"+    (decode "test-a.txt")+    (decode "test-b.txt")+  , test_CanonicalizePath "utf8"+    (fromText "\xA1\xA2-a.txt")+    (fromText "\xA1\xA2-b.txt")+  , test_CanonicalizePath "iso8859"+    (decode "\xA1\xA2\xA3-a.txt")+#ifdef CABAL_OS_DARWIN+    (decode "%A1%A2%A3-b.txt")+#else+    (decode "\xA1\xA2\xA3-b.txt")+#endif+  , test_CanonicalizePath_TrailingSlash+  ]++suite_CreateDirectory :: Suite+suite_CreateDirectory = suite "createDirectory"+  [ test_CreateDirectory "ascii"+    (decode "test.d")+  , test_CreateDirectory "utf8"+    (fromText "\xA1\xA2.d")+  , test_CreateDirectory "iso8859"+    (decode "\xA1\xA2\xA3.d")+  , test_CreateDirectory_FailExists+  , test_CreateDirectory_SucceedExists+  , test_CreateDirectory_FailFileExists+  ]++suite_CreateTree :: Suite+suite_CreateTree = suite "createTree"+  [ test_CreateTree "ascii"+    (decode "test.d")+  , test_CreateTree "ascii-slash"+    (decode "test.d/")+  , test_CreateTree "utf8"+    (fromText "\xA1\xA2.d")+  , test_CreateTree "utf8-slash"+    (fromText "\xA1\xA2.d/")+  , test_CreateTree "iso8859"+    (decode "\xA1\xA2\xA3.d")+  , test_CreateTree "iso8859-slash"+    (decode "\xA1\xA2\xA3.d/")+  ]++suite_RemoveFile :: Suite+suite_RemoveFile = suite "removeFile"+  [ test_RemoveFile "ascii"+    (decode "test.txt")+  , test_RemoveFile "utf8"+    (fromText "\xA1\xA2.txt")+  , test_RemoveFile "iso8859"+    (decode "\xA1\xA2\xA3.txt")+  ]++suite_RemoveDirectory :: Suite+suite_RemoveDirectory = suite "removeDirectory"+  [ test_RemoveDirectory "ascii"+    (decode "test.d")+  , test_RemoveDirectory "utf8"+    (fromText "\xA1\xA2.d")+  , test_RemoveDirectory "iso8859"+    (decode "\xA1\xA2\xA3.d")+  ]++suite_RemoveTree :: Suite+suite_RemoveTree = suite "removeTree"+  [ test_RemoveTree "ascii"+    (decode "test.d")+  , test_RemoveTree "utf8"+    (fromText "\xA1\xA2.d")+  , test_RemoveTree "iso8859"+    (decode "\xA1\xA2\xA3.d")+  ]++suite_GetWorkingDirectory :: Suite+suite_GetWorkingDirectory = suite "getWorkingDirectory"+  [ test_GetWorkingDirectory "ascii"+    (decode "test.d")+  , test_GetWorkingDirectory "utf8"+    (fromText "\xA1\xA2.d")+  , test_GetWorkingDirectory "iso8859"+    (decode "\xA1\xA2\xA3.d")+  ]++suite_SetWorkingDirectory :: Suite+suite_SetWorkingDirectory = suite "setWorkingDirectory"+  [ test_SetWorkingDirectory "ascii"+    (decode "test.d")+  , test_SetWorkingDirectory "utf8"+    (fromText "\xA1\xA2.d")+  , test_SetWorkingDirectory "iso8859"+    (decode "\xA1\xA2\xA3.d")+  ]++suite_GetHomeDirectory :: Suite+suite_GetHomeDirectory = suite "getHomeDirectory"+  [ test_GetHomeDirectory "ascii"+    (decode "/home/test.d")+  , test_GetHomeDirectory "utf8"+    (decode "/home/\xA1\xA2.d")+  , test_GetHomeDirectory "iso8859"+    (decode "/home/\xA1\xA2\xA3.d")+  ]++suite_GetDesktopDirectory :: Suite+suite_GetDesktopDirectory = suite "getDesktopDirectory"+  [ test_GetDesktopDirectory "ascii"+    (decode "/desktop/test.d")+  , test_GetDesktopDirectory "utf8"+    (decode "/desktop/\xA1\xA2.d")+  , test_GetDesktopDirectory "iso8859"+    (decode "/desktop/\xA1\xA2\xA3.d")+  ]++suite_GetModified :: Suite+suite_GetModified = suite "getModified"+  [ test_GetModified "ascii"+    (decode "test.txt")+  , test_GetModified "utf8"+    (fromText "\xA1\xA2.txt")+  , test_GetModified "iso8859"+    (decode "\xA1\xA2\xA3.txt")+  ]++suite_GetSize :: Suite+suite_GetSize = suite "getSize"+  [ test_GetSize "ascii"+    (decode "test.txt")+  , test_GetSize "utf8"+    (fromText "\xA1\xA2.txt")+  , test_GetSize "iso8859"+    (decode "\xA1\xA2\xA3.txt")+  ]++suite_CopyFile :: Suite+suite_CopyFile = suite "copyFile"+  [ test_CopyFile "ascii"+    (decode "old_test.txt")+    (decode "new_test.txt")+  , test_CopyFile "utf8"+    (fromText "old_\xA1\xA2.txt")+    (fromText "new_\xA1\xA2.txt")+  , test_CopyFile "iso8859"+#ifdef CABAL_OS_DARWIN+    (decode "old_%A1%A2%A3.txt")+#else+    (decode "old_\xA1\xA2\xA3.txt")+#endif+#ifdef CABAL_OS_DARWIN+    (decode "new_%A1%A2%A3.txt")+#else+    (decode "new_\xA1\xA2\xA3.txt")+#endif+  ]++suite_WithFile :: Suite+suite_WithFile = suite "withFile"+  [ test_WithFile_Read "read.ascii"+    (decode "test.txt")+  , test_WithFile_Read "read.utf8"+    (fromText "\xA1\xA2.txt")+  , test_WithFile_Read "read.iso8859"+#ifdef CABAL_OS_DARWIN+    (decode "%A1%A2%A3.txt")+#else+    (decode "\xA1\xA2\xA3.txt")+#endif+  , test_WithFile_Write "write.ascii"+    (decode "test.txt")+  , test_WithFile_Write "write.utf8"+    (fromText "\xA1\xA2.txt")+  , test_WithFile_Write "write.iso8859"+    (decode "\xA1\xA2\xA3.txt")+  ]++suite_WithTextFile :: Suite+suite_WithTextFile = suite "withTextFile"+  [ test_WithTextFile "ascii"+    (decode "test.txt")+  , test_WithTextFile "utf8"+    (fromText "\xA1\xA2.txt")+  , test_WithTextFile "iso8859"+#ifdef CABAL_OS_DARWIN+    (decode "%A1%A2%A3.txt")+#else+    (decode "\xA1\xA2\xA3.txt")+#endif+  ]++suite_RegressionTests :: Suite+suite_RegressionTests = suite "regression-tests"+  [ test_ListDirectoryLeaksFds+  ]++test_IsFile :: String -> FilePath -> Test+test_IsFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let path = tmp </> file_name++  before <- liftIO $ Filesystem.isFile path+  $expect (not before)++  touch_ffi path "contents\n"++  after <- liftIO $ Filesystem.isFile path+  $expect after++test_PipeIsFile :: String -> FilePath -> Test+test_PipeIsFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let path = tmp </> file_name++  before <- liftIO $ Filesystem.isFile path+  $expect (not before)++  mkfifo_ffi path++  after <- liftIO $ Filesystem.isFile path+  $expect after++test_IsDirectory :: String -> FilePath -> Test+test_IsDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  let path = tmp </> dir_name++  before <- liftIO $ Filesystem.isDirectory path+  $expect (not before)++  mkdir_ffi path++  after <- liftIO $ Filesystem.isDirectory path+  $expect after++test_Rename :: String -> FilePath -> FilePath -> Test+test_Rename test_name old_name new_name = assertionsWithTemp test_name $ \tmp -> do+  let old_path = tmp </> old_name+  let new_path = tmp </> new_name++  touch_ffi old_path ""++  old_before <- liftIO $ Filesystem.isFile old_path+  new_before <- liftIO $ Filesystem.isFile new_path+  $expect old_before+  $expect (not new_before)++  liftIO $ Filesystem.rename old_path new_path++  old_after <- liftIO $ Filesystem.isFile old_path+  new_after <- liftIO $ Filesystem.isFile new_path+  $expect (not old_after)+  $expect new_after++test_CopyFile :: String -> FilePath -> FilePath -> Test+test_CopyFile test_name old_name new_name = assertionsWithTemp test_name $ \tmp -> do+  let old_path = tmp </> old_name+  let new_path = tmp </> new_name++  touch_ffi old_path ""++  old_before <- liftIO $ Filesystem.isFile old_path+  new_before <- liftIO $ Filesystem.isFile new_path+  $expect old_before+  $expect (not new_before)++  liftIO $ Filesystem.copyFile old_path new_path++  old_after <- liftIO $ Filesystem.isFile old_path+  new_after <- liftIO $ Filesystem.isFile new_path+  $expect old_after+  $expect new_after+  old_contents <- liftIO $+    Filesystem.withTextFile old_path ReadMode $+    Data.Text.IO.hGetContents+  new_contents <- liftIO $+    Filesystem.withTextFile new_path ReadMode $+    Data.Text.IO.hGetContents+  $expect (equalLines old_contents new_contents)++test_CanonicalizePath :: String -> FilePath -> FilePath -> Test+test_CanonicalizePath test_name src_name dst_name = assertionsWithTemp test_name $ \tmp -> do+  let src_path = tmp </> src_name+  let subdir = tmp </> "subdir"++  -- canonicalize the directory first, to avoid false negatives if+  -- it gets placed in a symlinked location.+  mkdir_ffi subdir+  canon_subdir <- liftIO (Filesystem.canonicalizePath subdir)++  let dst_path = canon_subdir </> dst_name++  touch_ffi dst_path ""+  symlink_ffi dst_path src_path++  canonicalized <- liftIO $ Filesystem.canonicalizePath src_path+  $expect $ equal canonicalized dst_path++test_CanonicalizePath_TrailingSlash :: Test+test_CanonicalizePath_TrailingSlash = assertionsWithTemp "trailing-slash" $ \tmp -> do+  let src_path = tmp </> "src"+  let subdir = tmp </> "subdir"++  -- canonicalize the directory first, to avoid false negatives if+  -- it gets placed in a symlinked location.+  mkdir_ffi subdir+  canon_subdir <- liftIO (Filesystem.canonicalizePath (tmp </> "subdir"))++  let dst_path = canon_subdir </> "dst"++  mkdir_ffi dst_path+  symlink_ffi dst_path src_path++  canonicalized <- liftIO (Filesystem.canonicalizePath (src_path </> empty))+  $expect (equal canonicalized (dst_path </> empty))++test_CreateDirectory :: String -> FilePath -> Test+test_CreateDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  let dir_path = tmp </> dir_name++  exists_before <- liftIO $ Filesystem.isDirectory dir_path+  $assert (not exists_before)++  liftIO $ Filesystem.createDirectory False dir_path+  exists_after <- liftIO $ Filesystem.isDirectory dir_path++  $expect exists_after++test_CreateDirectory_FailExists :: Test+test_CreateDirectory_FailExists = assertionsWithTemp "fail-if-exists" $ \tmp -> do+  let dir_path = tmp </> "subdir"+  mkdir_ffi dir_path++  $expect $ throwsEq+    (mkAlreadyExists "createDirectory" dir_path)+    (Filesystem.createDirectory False dir_path)++test_CreateDirectory_SucceedExists :: Test+test_CreateDirectory_SucceedExists = assertionsWithTemp "succeed-if-exists" $ \tmp -> do+  let dir_path = tmp </> "subdir"+  mkdir_ffi dir_path++  liftIO $ Filesystem.createDirectory True dir_path++test_CreateDirectory_FailFileExists :: Test+test_CreateDirectory_FailFileExists = assertionsWithTemp "fail-if-file-exists" $ \tmp -> do+  let dir_path = tmp </> "subdir"+  touch_ffi dir_path ""++  $expect $ throwsEq+    (mkAlreadyExists "createDirectory" dir_path)+    (Filesystem.createDirectory False dir_path)+  $expect $ throwsEq+    (mkAlreadyExists "createDirectory" dir_path)+    (Filesystem.createDirectory True dir_path)++mkAlreadyExists :: String -> FilePath -> GHC.IOError+mkAlreadyExists loc path = GHC.IOError Nothing GHC.AlreadyExists loc "File exists"+#if MIN_VERSION_base(4,2,0)+  (Just (errnoCInt eEXIST))+#endif+  (Just (CurrentOS.encodeString path))++test_CreateTree :: String -> FilePath -> Test+test_CreateTree test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  let dir_path = tmp </> dir_name+  let subdir = dir_path </> "subdir"++  dir_exists_before <- liftIO $ Filesystem.isDirectory dir_path+  subdir_exists_before <- liftIO $ Filesystem.isDirectory subdir+  $assert (not dir_exists_before)+  $assert (not subdir_exists_before)++  liftIO $ Filesystem.createTree subdir+  dir_exists_after <- liftIO $ Filesystem.isDirectory dir_path+  subdir_exists_after <- liftIO $ Filesystem.isDirectory subdir++  $expect dir_exists_after+  $expect subdir_exists_after++test_ListDirectory :: Test+test_ListDirectory = assertionsWithTemp "listDirectory" $ \tmp -> do+  -- OSX replaces non-UTF8 filenames with http-style %XX escapes+  let+    paths =+#ifdef CABAL_OS_DARWIN+      [ tmp </> decode "%A1%A2%A3.txt"+      , tmp </> decode "test.txt"+      , tmp </> fromText "\xA1\xA2.txt"+      ]+#else+      [ tmp </> decode "test.txt"+      , tmp </> fromText "\xA1\xA2.txt"+      , tmp </> decode "\xA1\xA2\xA3.txt"+      ]+#endif+  forM_ paths (\path -> touch_ffi path "")++  names <- liftIO $ Filesystem.listDirectory tmp+  $expect $ sameItems paths names++test_RemoveFile :: String -> FilePath -> Test+test_RemoveFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name++  touch_ffi file_path "contents\n"++  before <- liftIO $ Filesystem.isFile file_path+  $assert before++  liftIO $ Filesystem.removeFile file_path++  after <- liftIO $ Filesystem.isFile file_path+  $expect (not after)++test_RemoveDirectory :: String -> FilePath -> Test+test_RemoveDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  let dir_path = tmp </> dir_name++  mkdir_ffi dir_path++  before <- liftIO $ Filesystem.isDirectory dir_path+  $assert before++  liftIO $ Filesystem.removeDirectory dir_path++  after <- liftIO $ Filesystem.isDirectory dir_path+  $expect (not after)++test_RemoveTree :: String -> FilePath -> Test+test_RemoveTree test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  let dir_path = tmp </> dir_name+  let subdir = dir_path </> "subdir"++  mkdir_ffi dir_path+  mkdir_ffi subdir++  dir_before <- liftIO $ Filesystem.isDirectory dir_path+  subdir_before <- liftIO $ Filesystem.isDirectory subdir+  $assert dir_before+  $assert subdir_before++  liftIO $ Filesystem.removeTree dir_path++  dir_after <- liftIO $ Filesystem.isDirectory dir_path+  subdir_after <- liftIO $ Filesystem.isDirectory subdir+  $expect (not dir_after)+  $expect (not subdir_after)++test_GetWorkingDirectory :: String -> FilePath -> Test+test_GetWorkingDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  -- canonicalize to avoid issues with symlinked temp dirs+  canon_tmp <- liftIO (Filesystem.canonicalizePath tmp)+  let dir_path = canon_tmp </> dir_name++  mkdir_ffi dir_path+  chdir_ffi dir_path++  cwd <- liftIO $ Filesystem.getWorkingDirectory+  $expect (equal cwd dir_path)++test_SetWorkingDirectory :: String -> FilePath -> Test+test_SetWorkingDirectory test_name dir_name = assertionsWithTemp test_name $ \tmp -> do+  -- canonicalize to avoid issues with symlinked temp dirs+  canon_tmp <- liftIO (Filesystem.canonicalizePath tmp)+  let dir_path = canon_tmp </> dir_name++  mkdir_ffi dir_path+  liftIO $ Filesystem.setWorkingDirectory dir_path++  cwd <- getcwd_ffi+  $expect (equal cwd dir_path)++test_GetHomeDirectory :: String -> FilePath -> Test+test_GetHomeDirectory test_name dir_name = assertions test_name $ do+  path <- liftIO $ withEnv "HOME" (Just dir_name) Filesystem.getHomeDirectory+  $expect (equal path dir_name)++test_GetDesktopDirectory :: String -> FilePath -> Test+test_GetDesktopDirectory test_name dir_name = assertions test_name $ do+  path <- liftIO $+    withEnv "XDG_DESKTOP_DIR" (Just dir_name) $+    Filesystem.getDesktopDirectory+  $expect (equal path dir_name)++  fallback <- liftIO $+    withEnv "XDG_DESKTOP_DIR" Nothing $+    withEnv "HOME" (Just dir_name) $+    Filesystem.getDesktopDirectory+  $expect (equal fallback (dir_name </> "Desktop"))++test_GetModified :: String -> FilePath -> Test+test_GetModified test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name++  touch_ffi file_path ""+  now <- liftIO getCurrentTime++  mtime <- liftIO $ Filesystem.getModified file_path+  $expect (equalWithin (diffUTCTime mtime now) 0 2)++test_GetSize :: String -> FilePath -> Test+test_GetSize test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name+  let contents = "contents\n"++  touch_ffi file_path contents++  size <- liftIO $ Filesystem.getSize file_path+  $expect (equal size (toInteger (Data.ByteString.length contents)))++test_WithFile_Read :: String -> FilePath -> Test+test_WithFile_Read test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name+  let contents = "contents\n"++  touch_ffi file_path contents++  read_contents <- liftIO $+    Filesystem.withFile file_path ReadMode $+    Data.ByteString.hGetContents+  $expect (equalLines contents read_contents)++test_WithFile_Write :: String -> FilePath -> Test+test_WithFile_Write test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name+  let contents = "contents\n"++  liftIO $+    Filesystem.withFile file_path WriteMode $+    (\h -> Data.ByteString.hPut h contents)++  read_contents <- liftIO $+    Filesystem.withFile file_path ReadMode $+    Data.ByteString.hGetContents+  $expect (equalLines contents read_contents)++test_WithTextFile :: String -> FilePath -> Test+test_WithTextFile test_name file_name = assertionsWithTemp test_name $ \tmp -> do+  let file_path = tmp </> file_name+  let contents = "contents\n"++  touch_ffi file_path (Char8.pack contents)++  read_contents <- liftIO $+    Filesystem.withTextFile file_path ReadMode $+    Data.Text.IO.hGetContents+  $expect (equalLines (Data.Text.pack contents) read_contents)++test_ListDirectoryLeaksFds :: Test+test_ListDirectoryLeaksFds = assertionsWithTemp "listDirectory-leaks-fds" $ \tmp -> do+  -- Test that listDirectory doesn't leak file descriptors.+  let dir_path = tmp </> "subdir"+  mkdir_ffi dir_path++  nullfd1 <- liftIO openDevNull+  liftIO $ PosixIO.closeFd nullfd1++  _subdirContents <- liftIO $ listDirectory dir_path++  nullfd2 <- liftIO openDevNull+  liftIO $ PosixIO.closeFd nullfd2++  $assert (equal nullfd1 nullfd2)+  where+    openDevNull =+#if MIN_VERSION_unix(2,8,0)+      PosixIO.openFd "/dev/null" PosixIO.ReadOnly PosixIO.defaultFileFlags+#else+      PosixIO.openFd "/dev/null" PosixIO.ReadOnly Nothing PosixIO.defaultFileFlags+#endif++withPathCString :: FilePath -> (CString -> IO a) -> IO a+withPathCString p = Data.ByteString.useAsCString (encode p)++decode :: ByteString -> FilePath+decode = Rules.decode Rules.posix++encode :: FilePath -> ByteString+encode = Rules.encode Rules.posix++fromText :: Text -> FilePath+fromText = Rules.fromText Rules.posix++-- | Create a file using the raw POSIX API, via FFI+touch_ffi :: FilePath -> Data.ByteString.ByteString -> Assertions ()+touch_ffi path contents = do+  fp <- liftIO $ withPathCString path $ \path_cstr ->+    Foreign.C.withCString "wb" $ \mode_cstr ->+    c_fopen path_cstr mode_cstr++  $assert (fp /= nullPtr)++  _ <- liftIO $ Data.ByteString.useAsCStringLen contents $ \(buf, len) ->+    c_fwrite buf 1 (fromIntegral len) fp++  _ <- liftIO $ c_fclose fp+  return ()++-- | Create a directory using the raw POSIX API, via FFI+mkdir_ffi :: FilePath -> Assertions ()+mkdir_ffi path = do+  ret <- liftIO $ withPathCString path $ \path_cstr ->+    c_mkdir path_cstr 0o700++  $assert (ret == 0)++-- | Create a symlink using the raw POSIX API, via FFI+symlink_ffi :: FilePath -> FilePath -> Assertions ()+symlink_ffi dst src  = do+  ret <- liftIO $+    withPathCString dst $ \dst_p ->+    withPathCString src $ \src_p ->+    c_symlink dst_p src_p++  $assert (ret == 0)++-- | Create a FIFO using the raw POSIX API, via FFI+mkfifo_ffi :: FilePath -> Assertions ()+mkfifo_ffi path = do+  ret <- liftIO $ withPathCString path $ \path_cstr ->+    c_mkfifo path_cstr 0o700++  $assert (ret == 0)++getcwd_ffi :: Assertions FilePath+getcwd_ffi = do+  buf <- liftIO $ c_getcwd nullPtr 0+  $assert (buf /= nullPtr)+  bytes <- liftIO $ Data.ByteString.packCString buf+  liftIO $ c_free buf+  return (decode bytes)++chdir_ffi :: FilePath -> Assertions ()+chdir_ffi path = do+  ret <- liftIO $+    withPathCString path $ \path_p ->+    c_chdir path_p+  $assert (ret == 0)++errnoCInt :: Errno -> CInt+errnoCInt (Errno x) = x++withEnv :: ByteString -> Maybe FilePath -> IO a -> IO a+withEnv name val io = bracket set unset (\_ -> io) where+  set = do+    old <- getEnv name+    setEnv name (fmap encode val)+    return old+  unset = setEnv name++getEnv :: ByteString -> IO (Maybe ByteString)+getEnv name = Data.ByteString.useAsCString name $ \cName -> do+  ret <- liftIO (c_getenv cName)+  if ret == nullPtr+    then return Nothing+    else fmap Just (Data.ByteString.packCString ret)++setEnv :: ByteString -> Maybe ByteString -> IO ()+setEnv name Nothing = throwErrnoIfMinus1_ "setEnv" $+  Data.ByteString.useAsCString name c_unsetenv+setEnv name (Just val) = throwErrnoIfMinus1_ "setEnv" $+  Data.ByteString.useAsCString name $ \cName ->+  Data.ByteString.useAsCString val $ \cVal ->+  c_setenv cName cVal 1++foreign import ccall unsafe "fopen"+  c_fopen :: CString -> CString -> IO (Ptr ())++foreign import ccall unsafe "fclose"+  c_fclose :: Ptr () -> IO CInt++foreign import ccall unsafe "fwrite"+  c_fwrite :: CString -> CSize -> CSize -> Ptr () -> IO CSize++foreign import ccall unsafe "mkdir"+  c_mkdir :: CString -> CInt -> IO CInt++foreign import ccall unsafe "symlink"+  c_symlink :: CString -> CString -> IO CInt++foreign import ccall unsafe "mkfifo"+  c_mkfifo :: CString -> CInt -> IO CInt++foreign import ccall unsafe "getcwd"+  c_getcwd :: CString -> CSize -> IO CString++foreign import ccall unsafe "chdir"+  c_chdir :: CString -> IO CInt++foreign import ccall unsafe "free"+  c_free :: Ptr a -> IO ()++foreign import ccall unsafe "getenv"+  c_getenv :: CString -> IO CString++foreign import ccall unsafe "setenv"+  c_setenv :: CString -> CString -> CInt -> IO CInt++foreign import ccall unsafe "unsetenv"+  c_unsetenv :: CString -> IO CInt
tests/FilesystemTests/Util.hs view
@@ -5,9 +5,9 @@ -- -- See license.txt for details module FilesystemTests.Util-	( assertionsWithTemp-	, todo-	) where+  ( assertionsWithTemp+  , todo+  ) where  import           Prelude hiding (FilePath) @@ -20,15 +20,15 @@  assertionsWithTemp :: String -> (FilePath -> Assertions a) -> Test assertionsWithTemp name io = test name impl where-	impl options = withTempDir name $ \dir -> do-		runTest (assertions name (io dir)) options+  impl options = withTempDir name $ \dir -> do+    runTest (assertions name (io dir)) options  withTempDir :: String -> (FilePath -> IO a) -> IO a withTempDir name io = withSystemTempDirectory-	("tests." ++ name ++ ".")-	(\dir ->-		let dir' = decodeString dir in-		finally (io dir') (removeTree dir'))+  ("tests." ++ name ++ ".")+  (\dir ->+    let dir' = decodeString dir in+    finally (io dir') (removeTree dir'))  todo :: String -> Test todo name = skipIf True (assertions name (return ()))
tests/FilesystemTests/Windows.hs view
@@ -5,8 +5,8 @@ -- -- See license.txt for details module FilesystemTests.Windows-	( suite_Windows-	) where+  ( suite_Windows+  ) where  import           Control.Monad import           Control.Monad.IO.Class (liftIO)@@ -19,48 +19,49 @@  suite_Windows :: Suite suite_Windows = suite "windows"-	[ todo "isFile"-	, todo "isDirectory"-	, todo "rename"-	, todo "canonicalizePath"-	, todo "createDirectory"-	, todo "createTree"-	, test_ListDirectory-	, todo "removeFile"-	, todo "removeDirectory"-	, todo "removeTree"-	, todo "getWorkingDirectory"-	, todo "setWorkingDirectory"-	, todo "getHomeDirectory"-	, todo "getDesktopDirectory"-	, todo "getDocumentsDirectory"-	, todo "getAppDataDirectory"-	, todo "getAppCacheDirectory"-	, todo "getAppConfigDirectory"-	, todo "copyFile"-	, todo "getModified"-	, todo "getSize"-	, todo "openFile"-	, todo "withFile"-	, todo "readFile"-	, todo "writeFile"-	, todo "appendFile"-	, todo "openTextFile"-	, todo "withTextFile"-	, todo "readTextFile"-	, todo "writeTextFile"-	, todo "appendTextFile"-	]+  [ todo "isFile"+  , todo "isDirectory"+  , todo "rename"+  , todo "canonicalizePath"+  , todo "createDirectory"+  , todo "createTree"+  , test_ListDirectory+  , todo "removeFile"+  , todo "removeDirectory"+  , todo "removeTree"+  , todo "getWorkingDirectory"+  , todo "setWorkingDirectory"+  , todo "getHomeDirectory"+  , todo "getDesktopDirectory"+  , todo "getDocumentsDirectory"+  , todo "getAppDataDirectory"+  , todo "getAppCacheDirectory"+  , todo "getAppConfigDirectory"+  , todo "copyFile"+  , todo "getModified"+  , todo "getSize"+  , todo "openFile"+  , todo "withFile"+  , todo "readFile"+  , todo "writeFile"+  , todo "appendFile"+  , todo "openTextFile"+  , todo "withTextFile"+  , todo "readTextFile"+  , todo "writeTextFile"+  , todo "appendTextFile"+  ]  test_ListDirectory :: Test test_ListDirectory = assertionsWithTemp "listDirectory" $ \dir -> do-	let paths =-		[ dir </> decode "test.txt"-		, dir </> decode "\12354\946\1076\119070.txt"-		, dir </> decode "\xA1\xA2\xA3.txt"-		]-	-	liftIO $ forM_ paths (\path -> writeTextFile path "")-	-	names <- liftIO $ Filesystem.listDirectory dir-	$expect $ sameItems paths names+  let+    paths =+      [ dir </> decode "test.txt"+      , dir </> decode "\12354\946\1076\119070.txt"+      , dir </> decode "\xA1\xA2\xA3.txt"+      ]++  liftIO $ forM_ paths (\path -> writeTextFile path "")++  names <- liftIO $ Filesystem.listDirectory dir+  $expect $ sameItems paths names