mirror of
https://github.com/composewell/streamly.git
synced 2024-09-11 11:37:22 +03:00
Fix docs and enable test cases for common FS Event module
This commit is contained in:
parent
a9589afc3a
commit
6b0b50207b
@ -104,8 +104,22 @@ import qualified Streamly.Internal.FileSystem.Event.Windows as Event
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
watch :: NonEmpty (Array Word8) -> SerialT IO Event.Event
|
||||
watch :: NonEmpty (Array Word8) -> SerialT IO Event
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
watch = Event.watch
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
watch = Event.watchWithFlags
|
||||
[ 0x00000002 -- File was modified.
|
||||
, 0x00000004 -- Metadata changed.
|
||||
, 0x00000100 -- Subfile was created.
|
||||
, 0x00000200 -- Subfile was deleted.
|
||||
, 0x00000400 -- Root was deleted.
|
||||
, 0x00000040 -- File was moved from X.
|
||||
, 0x00000080 -- File was moved to Y.
|
||||
]
|
||||
#elif defined(CABAL_OS_DARWIN)
|
||||
watch = Event.watch
|
||||
#endif
|
||||
|
||||
-- | Like 'watch' except that if a watched path is a directory the whole
|
||||
-- directory tree under it is watched recursively.
|
||||
@ -115,7 +129,21 @@ watch = Event.watch
|
||||
-- /Pre-release/
|
||||
--
|
||||
watchRecursive :: NonEmpty (Array Word8) -> SerialT IO Event
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
watchRecursive = Event.watchRecursive
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
watchRecursive = Event.watchRecursiveWithFlags
|
||||
[ 0x00000002 -- File was modified.
|
||||
, 0x00000004 -- Metadata changed.
|
||||
, 0x00000100 -- Subfile was created.
|
||||
, 0x00000200 -- Subfile was deleted.
|
||||
, 0x00000400 -- Root was deleted.
|
||||
, 0x00000040 -- File was moved from X.
|
||||
, 0x00000080 -- File was moved to Y.
|
||||
]
|
||||
#elif defined(CABAL_OS_DARWIN)
|
||||
watchRecursive = Event.watchRecursive
|
||||
#endif
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Handling Events
|
||||
@ -134,7 +162,8 @@ getAbsPath = Event.getAbsPath
|
||||
-- | Determine whether the event indicates creation of an object within the
|
||||
-- monitored path. This event is generated when any file system object other
|
||||
-- than a hard link is created.
|
||||
--
|
||||
-- Hard link behaviours:
|
||||
-- On Linux and Windows hard lnik creation generates 'Created' event.
|
||||
-- /Pre-release/
|
||||
--
|
||||
isCreated :: Event -> Bool
|
||||
@ -143,8 +172,20 @@ isCreated = Event.isCreated
|
||||
-- XXX Test and document the hard link deletion on each platform.
|
||||
--
|
||||
-- | Determine whether the event indicates deletion of an object within the
|
||||
-- monitored path. This is true when a file or a hardlink is deleted.
|
||||
-- monitored path. This is true when a file or a hardlink is deleted.--
|
||||
-- Hard link behaviours:
|
||||
-- On Linux and Windows hard lnik deletion generates 'Deleted' event
|
||||
-- @
|
||||
-- Deletion of Root path:
|
||||
--
|
||||
-- In 'Linux' the deletion of root path only generates 'RootDeleted' event for
|
||||
-- the root path, whereas the nested directory inside the root path gets
|
||||
-- 'Deleted' and 'RootDeleted' events.
|
||||
--
|
||||
-- In Windows from GUI the deletion of root path is not allowed , from CLI the
|
||||
-- content inside the root path is deleted and 'Deleted' event is generated
|
||||
-- for each nested paths.There is no event generated for root path itself.
|
||||
-- @
|
||||
-- /Pre-release/
|
||||
--
|
||||
isDeleted :: Event -> Bool
|
||||
@ -156,6 +197,8 @@ isDeleted = Event.isDeleted
|
||||
-- monitored path. This event is generated when an object is renamed within the
|
||||
-- watched directory or if it is moved out of or in the watched directory.
|
||||
--
|
||||
-- Hard link behaviours:
|
||||
-- On Linux and Windows hard lnik move generates 'MovedFrom' and ' MovedTo' events
|
||||
-- /Pre-release/
|
||||
--
|
||||
isMoved :: Event -> Bool
|
||||
@ -163,6 +206,8 @@ isMoved = Event.isMoved
|
||||
|
||||
-- | Determine whether the event indicates modification of an object within the
|
||||
-- monitored path. This event is generated only for files and not directories.
|
||||
-- Unlike Linux in Windows in recursive mode when a file is created or deleted the Modified
|
||||
-- event is generated for the parent directory as well.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
|
@ -66,6 +66,7 @@ module Streamly.Internal.FileSystem.Event.Linux
|
||||
Config (..)
|
||||
, Toggle (..)
|
||||
, defaultConfig
|
||||
, setRecursiveMode
|
||||
|
||||
-- ** Watch Behavior
|
||||
, setFollowSymLinks
|
||||
@ -80,6 +81,7 @@ module Streamly.Internal.FileSystem.Event.Linux
|
||||
, setRootDeleted
|
||||
, setRootMoved
|
||||
-- XXX make a setRootPathEvents to include all root events
|
||||
, setRootPathEvents
|
||||
|
||||
-- *** Item Level Metadata change
|
||||
, setMetadataChanged
|
||||
@ -103,6 +105,8 @@ module Streamly.Internal.FileSystem.Event.Linux
|
||||
, watch
|
||||
, watchRecursive
|
||||
, watchWith
|
||||
, watchWithFlags
|
||||
, watchRecursiveWithFlags
|
||||
|
||||
-- Low level watch APIs
|
||||
, addToWatch
|
||||
@ -117,6 +121,7 @@ module Streamly.Internal.FileSystem.Event.Linux
|
||||
|
||||
-- ** Root Level Events
|
||||
-- XXX create a isRootPathEvent similar to macOS.
|
||||
, isRootPathEvent
|
||||
, isRootUnwatched
|
||||
, isRootDeleted
|
||||
, isRootMoved
|
||||
@ -360,6 +365,15 @@ foreign import capi
|
||||
setRootMoved :: Toggle -> Config -> Config
|
||||
setRootMoved = setFlag iN_MOVE_SELF
|
||||
|
||||
-- | Report when the watched root path itself gets deleted or renamed.
|
||||
--
|
||||
-- /default: On/
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
setRootPathEvents :: Toggle -> Config -> Config
|
||||
setRootPathEvents = setFlag (iN_DELETE_SELF .|. iN_MOVE_SELF)
|
||||
|
||||
foreign import capi
|
||||
"sys/inotify.h value IN_ATTRIB" iN_ATTRIB :: Word32
|
||||
|
||||
@ -904,6 +918,31 @@ watchRecursive = watchWith id
|
||||
watch :: NonEmpty (Array Word8) -> SerialT IO Event
|
||||
watch = watchWith (setRecursiveMode False)
|
||||
|
||||
-- | In recursive mode when a nested directory is created,
|
||||
-- 'Created' event is generated only for the top directory.
|
||||
-- No recursive Created events are generated for nested contents.
|
||||
-- When a nested directory is deleted 'Deleted' events are generated
|
||||
-- for the nested content recursively.
|
||||
-- The nested directories are added into watch list for future events.
|
||||
-- [flags] are used to filter the events with specific event flag.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
watchRecursiveWithFlags ::
|
||||
[Word32] -> NonEmpty (Array Word8) -> SerialT IO Event
|
||||
watchRecursiveWithFlags flags =
|
||||
S.filter (\ev -> any (flip getFlag ev) flags) . watchRecursive
|
||||
|
||||
-- | When a nested directory is created,
|
||||
-- Created event is generated only for the top directory.
|
||||
-- [flags] are used to filter the events with specific event flag.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
watchWithFlags :: [Word32] -> NonEmpty (Array Word8) -> SerialT IO Event
|
||||
watchWithFlags flags =
|
||||
S.filter (\ev -> any (flip getFlag ev) flags) . watch
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Examine event stream
|
||||
-------------------------------------------------------------------------------
|
||||
@ -942,7 +981,7 @@ getRelPath Event{..} = eventRelPath
|
||||
-- /Pre-release/
|
||||
--
|
||||
getAbsPath :: Event -> Array Word8
|
||||
getAbsPath ev = getRoot ev <> A.fromCString# "/"# <> getRelPath ev
|
||||
getAbsPath ev = ensureTrailingSlash (getRoot ev) <> getRelPath ev
|
||||
|
||||
-- XXX should we use a Maybe?
|
||||
-- | Cookie is set when a rename occurs. The cookie value can be used to
|
||||
@ -1037,6 +1076,17 @@ foreign import capi
|
||||
isRootUnmounted :: Event -> Bool
|
||||
isRootUnmounted = getFlag iN_UNMOUNT
|
||||
|
||||
-- | Determine whether the event indicates a change of path of the monitored
|
||||
-- object itself. Note that the object may become unreachable or deleted after
|
||||
-- a change of path.
|
||||
--
|
||||
-- /Occurs only for a watched path/
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
isRootPathEvent :: Event -> Bool
|
||||
isRootPathEvent = getFlag (iN_DELETE_SELF .|. iN_MOVE_SELF .|. iN_UNMOUNT)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Metadata change Events
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -64,11 +64,11 @@ module Streamly.Internal.FileSystem.Event.Windows
|
||||
|
||||
-- ** Watch APIs
|
||||
, watch
|
||||
, watchTrees
|
||||
, watchTreesWith
|
||||
, watchRecursive
|
||||
, watchWith
|
||||
|
||||
-- * Handling Events
|
||||
, Event
|
||||
, Event(..)
|
||||
, getRoot
|
||||
, getRelPath
|
||||
, getAbsPath
|
||||
@ -76,9 +76,10 @@ module Streamly.Internal.FileSystem.Event.Windows
|
||||
-- ** Item CRUD events
|
||||
, isCreated
|
||||
, isDeleted
|
||||
, isModified
|
||||
, isMoved
|
||||
, isMovedFrom
|
||||
, isMovedTo
|
||||
, isModified
|
||||
|
||||
-- ** Exception Conditions
|
||||
, isEventsLost
|
||||
@ -410,7 +411,7 @@ closePathHandleStream = S.mapM_ (\(h, _, _) -> closeHandle h)
|
||||
-- path is a directory, only the files and directories directly under the
|
||||
-- watched directory are monitored, contents of subdirectories are not
|
||||
-- monitored. Monitoring starts from the current time onwards. The paths are
|
||||
-- specified as UTF-8 encoded 'Array' of 'Word8'.
|
||||
-- specified as encoded 'Array' of 'Word8'.
|
||||
--
|
||||
-- @
|
||||
-- watchWith
|
||||
@ -468,11 +469,46 @@ getRoot :: Event -> Array Word8
|
||||
getRoot Event{..} = (UTF8.toArray . UTF8.pack) eventRootPath
|
||||
|
||||
getAbsPath :: Event -> Array Word8
|
||||
getAbsPath ev = getRoot ev <> getRelPath ev
|
||||
getAbsPath ev = getRoot ev <> A.fromCString# "\\"# <> (getRelPath ev)
|
||||
|
||||
-- XXX need to document the exact semantics of these.
|
||||
--
|
||||
-- | File/directory created in watched directory.
|
||||
-- ** In non-recursive mode
|
||||
-- @
|
||||
-- When a file or directory is created, Created and Modified events are
|
||||
-- generated for corresponding file or directory. Parent directory will not
|
||||
-- generate any events.
|
||||
--
|
||||
-- When a nested directory is created following events are generated:
|
||||
-- Created event for the directory created.
|
||||
-- Modified event for the directory created.
|
||||
-- Modified event for each entry inside it.
|
||||
-- If a nested directory contains 5 entries on top level then we will get
|
||||
-- one Created and six Modified events for the created top directory path.
|
||||
-- @
|
||||
--
|
||||
-- ** In recursive mode
|
||||
-- @
|
||||
-- When a file is created we get following events:
|
||||
-- Created event for the file got created.
|
||||
-- Modified event for the file got created.
|
||||
-- Modified event for the parent directory.
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- When an empty directory is created we get following events:
|
||||
-- Created event for the directory got created.
|
||||
-- Modified event for the parent directory.
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- When a nested directory is created we get
|
||||
-- following events:
|
||||
-- Created and Modified events for all the files and subdirectories
|
||||
-- recursively inside the given directory.
|
||||
-- Modified event for the parent directory.
|
||||
-- @
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
@ -480,7 +516,13 @@ isCreated :: Event -> Bool
|
||||
isCreated = getFlag fILE_ACTION_ADDED
|
||||
|
||||
-- | File/directory deleted from watched directory.
|
||||
-- ** In non-recursive mode:
|
||||
-- Deleted event is generated for object deleted from watched directory.
|
||||
-- No events are generated for nested objects.
|
||||
--
|
||||
-- ** In recursive mode:
|
||||
-- If a nested directory is deleted Modified events are received for nested
|
||||
-- sub-directories recursively. No events are generated for nested files.
|
||||
-- /Pre-release/
|
||||
--
|
||||
isDeleted :: Event -> Bool
|
||||
@ -488,6 +530,7 @@ isDeleted = getFlag fILE_ACTION_REMOVED
|
||||
|
||||
-- | Generated for the original path when an object is moved from under a
|
||||
-- monitored directory.
|
||||
-- In recursive mode Modified events is generated for parent directory.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
@ -496,17 +539,32 @@ isMovedFrom = getFlag fILE_ACTION_RENAMED_OLD_NAME
|
||||
|
||||
-- | Generated for the new path when an object is moved under a monitored
|
||||
-- directory.
|
||||
-- In recursive mode Modified events is generated for parent directory.
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
isMovedTo :: Event -> Bool
|
||||
isMovedTo = getFlag fILE_ACTION_RENAMED_NEW_NAME
|
||||
|
||||
-- | Generated for a path that is moved from or moved to the monitored
|
||||
-- directory.
|
||||
--
|
||||
-- >>> isMoved ev = isMovedFrom ev || isMovedTo ev
|
||||
--
|
||||
-- /Occurs only for an object inside the watched directory/
|
||||
--
|
||||
-- /Pre-release/
|
||||
--
|
||||
isMoved :: Event -> Bool
|
||||
isMoved ev = isMovedFrom ev || isMovedTo ev
|
||||
|
||||
-- XXX This event is generated only for files and not directories?
|
||||
--
|
||||
-- | Determine whether the event indicates modification of an object within the
|
||||
-- monitored path.
|
||||
--
|
||||
-- In non-recursive mode Modified event is not generated for a directory.
|
||||
-- In recursive mode Modified event is generated for parent directory if a file
|
||||
-- or directory is created or renamed.
|
||||
-- /Pre-release/
|
||||
--
|
||||
isModified :: Event -> Bool
|
||||
@ -531,6 +589,7 @@ showEvent ev@Event{..} =
|
||||
"--------------------------"
|
||||
++ "\nRoot = " ++ utf8ToString (getRoot ev)
|
||||
++ "\nPath = " ++ utf8ToString (getRelPath ev)
|
||||
++ "\ngetAbsPath = " ++ utf8ToString (getAbsPath ev)
|
||||
++ "\nFlags " ++ show eventFlags
|
||||
++ showev isEventsLost "Overflow"
|
||||
++ showev isCreated "Created"
|
||||
|
@ -18,6 +18,7 @@ import Data.Maybe (fromJust)
|
||||
import Data.Word (Word8)
|
||||
import System.Directory
|
||||
( createDirectoryIfMissing
|
||||
, createDirectoryLink
|
||||
, removeFile
|
||||
, removeDirectory
|
||||
, removePathForcibly
|
||||
@ -33,6 +34,7 @@ import System.IO.Unsafe (unsafePerformIO)
|
||||
import Streamly.Internal.Data.Array.Foreign (Array)
|
||||
|
||||
import qualified Data.List.NonEmpty as NonEmpty
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import qualified Data.Set as Set
|
||||
import qualified Streamly.Unicode.Stream as Unicode
|
||||
import qualified Streamly.Internal.Data.Array.Foreign as Array
|
||||
@ -40,6 +42,7 @@ import qualified Streamly.Internal.Data.Fold as FL
|
||||
import qualified Streamly.Internal.Data.Parser as PR
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as S
|
||||
import qualified Streamly.Internal.Unicode.Stream as U
|
||||
import qualified Streamly.Internal.FileSystem.Event as CommonEvent
|
||||
#if defined(CABAL_OS_DARWIN)
|
||||
import qualified Streamly.Internal.FileSystem.Event.Darwin as Event
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
@ -74,11 +77,7 @@ eoTask = "EOTask"
|
||||
-- XXX Make the getRelPath type same on windows and other platforms
|
||||
eventPredicate :: Event.Event -> Bool
|
||||
eventPredicate ev =
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
if (utf8ToString $ Event.getRelPath ev) == eoTask
|
||||
#else
|
||||
if (utf8ToString $ Event.getRelPath ev) == eoTask
|
||||
#endif
|
||||
then False
|
||||
else True
|
||||
|
||||
@ -122,18 +121,37 @@ showEventShort ev@Event.Event{..} =
|
||||
#error "Unsupported OS"
|
||||
#endif
|
||||
|
||||
rootPathRemovedEventCount :: Int
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
rootPathRemovedEventCount = 3
|
||||
#else
|
||||
rootPathRemovedEventCount = 10
|
||||
eventListWithFixLenSymLink :: ToEventList
|
||||
eventListWithFixLenSymLink = S.toList . S.take 1
|
||||
#endif
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Event Watcher
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
checkEvents :: FilePath -> MVar () -> [String] -> IO String
|
||||
checkEvents rootPath m matchList = do
|
||||
type EventChecker = FilePath -> MVar () -> [String] -> IO String
|
||||
type EventWatch = NonEmpty (Array Word8) -> S.SerialT IO Event.Event
|
||||
type ToEventList = S.SerialT IO Event.Event -> IO [Event.Event]
|
||||
|
||||
eventListWithFixLen :: ToEventList
|
||||
eventListWithFixLen = S.toList . S.take rootPathRemovedEventCount
|
||||
|
||||
eventListWithEOtask :: ToEventList
|
||||
eventListWithEOtask = S.parse (PR.takeWhile eventPredicate FL.toList)
|
||||
|
||||
checkEvents :: ToEventList -> EventWatch -> EventChecker
|
||||
checkEvents toEL ew rootPath m matchList = do
|
||||
let args = [rootPath]
|
||||
paths <- mapM toUtf8 args
|
||||
putStrLn ("Watch started !!!! on Path " ++ rootPath)
|
||||
events <- S.parse (PR.takeWhile eventPredicate FL.toList)
|
||||
events <- toEL
|
||||
$ S.before (putMVar m ())
|
||||
$ Event.watchTrees (NonEmpty.fromList paths)
|
||||
$ ew (NonEmpty.fromList paths)
|
||||
let eventStr = map showEventShort events
|
||||
let baseSet = Set.fromList matchList
|
||||
resultSet = Set.fromList eventStr
|
||||
@ -150,9 +168,9 @@ checkEvents rootPath m matchList = do
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
checker :: S.IsStream t =>
|
||||
FilePath -> MVar () -> [String] -> t IO String
|
||||
checker rootPath synch matchList =
|
||||
S.fromEffect (checkEvents rootPath synch matchList)
|
||||
EventChecker -> FilePath -> MVar () -> [String] -> t IO String
|
||||
checker ec rootPath synch matchList =
|
||||
S.fromEffect (ec rootPath synch matchList)
|
||||
`S.parallelFst`
|
||||
S.fromEffect timeout
|
||||
|
||||
@ -161,30 +179,41 @@ checker rootPath synch matchList =
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
driver ::
|
||||
( String
|
||||
EventChecker
|
||||
-> ( String
|
||||
, FilePath -> IO ()
|
||||
, FilePath -> IO ()
|
||||
, [String]
|
||||
, Bool
|
||||
)
|
||||
-> SpecWith ()
|
||||
driver (desc, pre, ops, events) = it desc $ runTest `shouldReturn` "PASS"
|
||||
driver ec (desc, pre, ops, events, sym) = it desc $ runTest `shouldReturn` "PASS"
|
||||
|
||||
where
|
||||
|
||||
runTest = do
|
||||
sync <- newEmptyMVar
|
||||
withSystemTempDirectory fseventDir $ \fp -> do
|
||||
pre fp
|
||||
let eventStream = checker fp sync events
|
||||
fsOps = S.fromEffect $ runFSOps fp sync
|
||||
fmap fromJust $ S.head $ eventStream `S.parallelFst` fsOps
|
||||
withSystemTempDirectory fseventDir $ \fp ->
|
||||
if sym
|
||||
then do
|
||||
createDirectoryLink fp (fp ++ "SymLink")
|
||||
pre (fp ++ "SymLink")
|
||||
let eventStream = checker ec (fp ++ "SymLink") sync events
|
||||
fsOps = S.fromEffect $ runFSOps (fp ++ "SymLink") sync
|
||||
fmap fromJust $ S.head $ eventStream `S.parallelFst` fsOps
|
||||
else do
|
||||
pre fp
|
||||
let eventStream = checker ec fp sync events
|
||||
fsOps = S.fromEffect $ runFSOps fp sync
|
||||
fmap fromJust $ S.head $ eventStream `S.parallelFst` fsOps
|
||||
|
||||
runFSOps fp sync = do
|
||||
_ <- takeMVar sync
|
||||
threadDelay 200000
|
||||
ops fp
|
||||
-- 'EOTask Created dir' event gets out of order so need to wait here
|
||||
threadDelay 200000 -- Why this delay?
|
||||
createDirectoryIfMissing True (fp </> "EOTask")
|
||||
createDirectoryIfMissing True (fp </> eoTask)
|
||||
threadDelay 10000000
|
||||
error "fs ops timed out"
|
||||
|
||||
@ -192,11 +221,12 @@ driver (desc, pre, ops, events) = it desc $ runTest `shouldReturn` "PASS"
|
||||
-- Main
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
testDesc ::
|
||||
testDesc, testDescRootDir ::
|
||||
[ ( String -- test description
|
||||
, FilePath -> IO () -- pre test operation
|
||||
, FilePath -> IO () -- file system actions
|
||||
, [String]) -- expected events
|
||||
, [String] -- expected events
|
||||
, Bool ) -- SymLink
|
||||
]
|
||||
testDesc =
|
||||
[
|
||||
@ -206,12 +236,9 @@ testDesc =
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
, [ "dir1Single_1" ]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1Single_1073742080_Dir"
|
||||
, "dir1Single_1073741856_Dir"
|
||||
, "dir1Single_1073741825_Dir"
|
||||
, "dir1Single_1073741840_Dir"
|
||||
]
|
||||
, ["dir1Single_1073742080_Dir"]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Remove a single directory"
|
||||
, \fp -> createDirectoryIfMissing True (fp </> "dir1Single")
|
||||
@ -219,10 +246,11 @@ testDesc =
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
, [ "dir1Single_2" ]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1Single_1024"
|
||||
, "dir1Single_32768"
|
||||
, [
|
||||
"dir1Single_1073742336_Dir"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Rename a single directory"
|
||||
, \fp -> createDirectoryIfMissing True (fp </> "dir1Single")
|
||||
@ -239,6 +267,7 @@ testDesc =
|
||||
, "dir1SingleRenamed_1073741952_Dir"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Create a nested directory"
|
||||
, const (return ())
|
||||
@ -251,28 +280,9 @@ testDesc =
|
||||
]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1_1073742080_Dir"
|
||||
, "dir1_1073741856_Dir"
|
||||
, "dir1_1073741825_Dir"
|
||||
, "dir1_1073741840_Dir"
|
||||
]
|
||||
#endif
|
||||
)
|
||||
, ( "Remove a nested directory"
|
||||
, \fp ->
|
||||
createDirectoryIfMissing True (fp </> "dir1" </> "dir2" </> "dir3")
|
||||
, \fp -> removePathForcibly (fp </> "dir1")
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
, [ "dir1_3"
|
||||
, "dir1\\dir2_3"
|
||||
, "dir1\\dir2\\dir3_2"
|
||||
, "dir1\\dir2_2","dir1_2"
|
||||
]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1/dir2/dir3_1073742336_Dir"
|
||||
, "dir1/dir2_1073742336_Dir"
|
||||
, "dir1_1073742336_Dir"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Rename a nested directory"
|
||||
, \fp -> createDirectoryIfMissing True
|
||||
@ -292,6 +302,7 @@ testDesc =
|
||||
, "dir1/dir2/dir3Renamed_1073741952_Dir"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Create a file in root Dir"
|
||||
, const (return ())
|
||||
@ -303,10 +314,10 @@ testDesc =
|
||||
]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "FileCreated.txt_256"
|
||||
, "FileCreated.txt_32"
|
||||
, "FileCreated.txt_2"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Remove a file in root Dir"
|
||||
, \fp -> writeFile (fp </> "FileCreated.txt") "Test Data"
|
||||
@ -316,6 +327,7 @@ testDesc =
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "FileCreated.txt_512" ]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Rename a file in root Dir"
|
||||
, \fp -> writeFile (fp </> "FileCreated.txt") "Test Data"
|
||||
@ -332,6 +344,7 @@ testDesc =
|
||||
, "FileRenamed.txt_128"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Create a file in a nested Dir"
|
||||
, \fp ->
|
||||
@ -345,11 +358,10 @@ testDesc =
|
||||
]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1/dir2/dir3/FileCreated.txt_256"
|
||||
, "dir1/dir2/dir3/FileCreated.txt_32"
|
||||
, "dir1/dir2/dir3/FileCreated.txt_2"
|
||||
, "dir1/dir2/dir3/FileCreated.txt_8"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Remove a file in a nested Dir"
|
||||
, \fp ->
|
||||
@ -366,6 +378,7 @@ testDesc =
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, ["dir1/dir2/dir3/FileCreated.txt_512"]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Rename a file in a nested Dir"
|
||||
, \fp ->
|
||||
@ -388,13 +401,110 @@ testDesc =
|
||||
, "dir1/dir2/dir3/FileRenamed.txt_128"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
, ( "Remove the nested directory"
|
||||
, \fp ->
|
||||
createDirectoryIfMissing True (fp </> "dir1" </> "dir2" </> "dir3")
|
||||
, \fp -> removePathForcibly (fp </> "dir1")
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
, [ "dir1_3"
|
||||
, "dir1\\dir2_3"
|
||||
, "dir1\\dir2\\dir3_2"
|
||||
, "dir1\\dir2_2","dir1_2"
|
||||
]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "dir1_1073741828_Dir"
|
||||
, "dir1_1073741828_Dir"
|
||||
, "dir1/dir2_1073741828_Dir"
|
||||
, "dir1/dir2_1073741828_Dir"
|
||||
, "dir1/dir2/dir3_1073741828_Dir"
|
||||
, "dir1/dir2/dir3_1073741828_Dir"
|
||||
, "dir1/dir2/dir3_1024"
|
||||
, "dir1/dir2/dir3_1073742336_Dir"
|
||||
, "dir1/dir2_1024"
|
||||
, "dir1/dir2_1073742336_Dir"
|
||||
, "dir1_1024"
|
||||
, "dir1_1073742336_Dir"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
]
|
||||
|
||||
testDescRootDir =
|
||||
[ ( "Remove the root directory"
|
||||
, \fp ->
|
||||
createDirectoryIfMissing True (fp </> "dir1" </> "dir2")
|
||||
, \fp -> removePathForcibly fp
|
||||
#if defined(CABAL_OS_WINDOWS)
|
||||
, ["dir1_2", "dir1_3", "dir1\\dir2_2"]
|
||||
#elif defined(CABAL_OS_LINUX)
|
||||
, [ "_1073741828_Dir"
|
||||
, "dir1_1073741828_Dir"
|
||||
, "dir1_1073741828_Dir"
|
||||
, "dir1/dir2_1073741828_Dir"
|
||||
, "dir1/dir2_1073741828_Dir"
|
||||
, "dir1/dir2_1024"
|
||||
, "dir1/dir2_1073742336_Dir"
|
||||
, "dir1_1024"
|
||||
, "dir1_1073742336_Dir"
|
||||
, "_1024"
|
||||
]
|
||||
#endif
|
||||
, False
|
||||
)
|
||||
]
|
||||
|
||||
#if defined(CABAL_OS_LINUX)
|
||||
testDescRootDirSymLink ::
|
||||
[ ( String -- test description
|
||||
, FilePath -> IO () -- pre test operation
|
||||
, FilePath -> IO () -- file system actions
|
||||
, [String] -- expected events
|
||||
, Bool ) -- SymLink
|
||||
]
|
||||
testDescRootDirSymLink =
|
||||
[ ( "Remove the root directory as SymLink"
|
||||
, \fp ->
|
||||
createDirectoryIfMissing True (fp </> "dir1" </> "dir2")
|
||||
, \fp -> removePathForcibly fp
|
||||
, ["_1073741828_Dir"]
|
||||
, True
|
||||
)
|
||||
]
|
||||
#endif
|
||||
|
||||
moduleName :: String
|
||||
moduleName = "FileSystem.Event"
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
hSetBuffering stdout NoBuffering
|
||||
hspec $ describe moduleName $ mapM_ driver testDesc
|
||||
#if defined(CABAL_OS_LINUX)
|
||||
hspec
|
||||
$ describe moduleName
|
||||
$ mapM_
|
||||
(driver $ checkEvents eventListWithEOtask Event.watchRecursive)
|
||||
testDesc
|
||||
hspec
|
||||
$ describe moduleName
|
||||
$ mapM_
|
||||
(driver $ checkEvents eventListWithEOtask CommonEvent.watchRecursive)
|
||||
(map (\(a, b, c, d, _) -> (a, b, c, d, True)) testDesc)
|
||||
hspec
|
||||
$ describe moduleName
|
||||
$ mapM_
|
||||
(driver $ checkEvents eventListWithFixLenSymLink CommonEvent.watchRecursive)
|
||||
testDescRootDirSymLink
|
||||
#endif
|
||||
hspec
|
||||
$ describe moduleName
|
||||
$ mapM_
|
||||
(driver $ checkEvents eventListWithEOtask CommonEvent.watchRecursive)
|
||||
testDesc
|
||||
hspec
|
||||
$ describe moduleName
|
||||
$ mapM_
|
||||
(driver $ checkEvents eventListWithFixLen CommonEvent.watchRecursive)
|
||||
testDescRootDir
|
||||
|
Loading…
Reference in New Issue
Block a user