cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=d958afd9fd7078a6eaee17df0a0b1e71504fc3b1

commit d958afd9fd7078a6eaee17df0a0b1e71504fc3b1
Author: pierre lamot <pierre.la...@openwide.fr>
Date:   Thu Feb 26 14:37:45 2015 +0100

    eio: add OSX implementation of eio_monitor based on FSEvent
    
    this patch adds an implementation of eio_monitor based on FSEvent
    for OSX. This implentation has some limitations compared to inotify
    implementation. Folowing events are not detected:
      - EIO_MONITOR_FILE_CLOSED
      - EIO_MONITOR_SELF_RENAME
      - EIO_MONITOR_SELF_DELETED
    
    It should be noted that some events that happend before the call
    to eio_monitor_add can be catched. This is why sleep timers have
    been added in the test suite.
    
    Tests have been added to check uncovered scenarios.
    
    some things might still be improved:
      - self_deleted events for files might be handled by checking the
        file_name manually
    
      - self_deleted events for directories might be handled by setting
        kFSEventStreamCreateFlagWatchRoot. I've noticed by doing so that
        a lot more unwanted event are raised
    
    Signed-off-by: Cedric BAIL <ced...@osg.samsung.com>
---
 configure.ac                     |  67 +++++--
 src/Makefile_Eio.am              |   7 +
 src/lib/eio/Eio.h                |   8 +-
 src/lib/eio/eio_monitor_cocoa.c  | 405 +++++++++++++++++++++++++++++++++++++++
 src/lib/eio/eio_monitor_poll.c   |   2 +-
 src/tests/eio/eio_test_monitor.c | 404 +++++++++++++++++++++++++++++---------
 6 files changed, 784 insertions(+), 109 deletions(-)

diff --git a/configure.ac b/configure.ac
index 82da49d..2996474 100644
--- a/configure.ac
+++ b/configure.ac
@@ -417,19 +417,8 @@ sys/mman.h \
 netinet/in.h \
 ])
 
-have_inotify="${ac_cv_header_sys_inotify_h}"
-AM_CONDITIONAL([HAVE_INOTIFY], [test "x${have_inotify}" = "xyes"])
-
-have_notify_win32="${have_win32}"
-AC_DEFINE_IF([HAVE_NOTIFY_WIN32],
-   [test "x${have_notify_win32}" = "xyes"], [1],
-   [File monitoring with Windows notification])
-AM_CONDITIONAL([HAVE_NOTIFY_WIN32], [test "x${have_notify_win32}" = "xyes"])
-
-
 EFL_CHECK_PATH_MAX
 
-
 #### Checks for types
 
 # wchar_t
@@ -1329,11 +1318,11 @@ AC_ARG_ENABLE([cocoa],
     ],
     [want_cocoa="no"])
 
- if test "${want_cocoa}" = "yes"; then
-    #test cocoa requirements (objc and Cocoa/Cocoa.h)
-       cocoa_ldflags=""
-   have_cocoa="no"
-   m4_ifdef([AC_PROG_OBJC],
+if test "${want_cocoa}" = "yes"; then
+   #test cocoa requirements (objc and Cocoa/Cocoa.h)
+    cocoa_ldflags=""
+    have_cocoa="no"
+    m4_ifdef([AC_PROG_OBJC],
       [
        if test "x${have_gnu_objc}" = "xyes" ; then
           AC_LANG_PUSH([Objective C])
@@ -1368,6 +1357,38 @@ window = [[NSWindow alloc]
 fi
 AC_SUBST(cocoa_ldflags)
 
+if test "x${want_cocoa}" = "xyes"; then
+    #test cocoa requirements (objc and Cocoa/Cocoa.h)
+    cocoa_coreservices_ldflags=""
+    have_cocoa_coreservices="no"
+    m4_ifdef([AC_PROG_OBJC],
+      [
+       if test "x${have_gnu_objc}" = "xyes" ; then
+          AC_LANG_PUSH([Objective C])
+          LIBS_save="$LIBS"
+          LIBS="$LIBS -framework CoreServices"
+          AC_LINK_IFELSE(
+             [AC_LANG_PROGRAM(
+                 [[
+#include <CoreServices/CoreServices.h>
+                 ]],
+                 [[
+//test function here
+                 ]])],
+             [
+              have_cocoa_coreservices="yes"
+              cocoa_coreservices_ldflags="-framework CoreServices"
+             ],
+             [have_cocoa_coreservices="no"])
+          LIBS="$LIBS_save"
+          AC_MSG_CHECKING([whether Cocoa CoreServices framework is supported])
+          AC_MSG_RESULT([${have_cocoa_coreservices}])
+          AC_LANG_POP([Objective C])
+       fi
+   ])
+fi
+AC_SUBST(cocoa_coreservices_ldflags)
+
 # Drm
 AC_ARG_ENABLE([drm],
    [AS_HELP_STRING([--enable-drm],[enable drm engine. 
@<:@default=disabled@:>@])],
@@ -3969,6 +3990,20 @@ EFL_ADD_LIBS([EIO], [-lm])
 ### Checks for linker characteristics
 
 ### Checks for library functions
+have_inotify="${ac_cv_header_sys_inotify_h}"
+AM_CONDITIONAL([HAVE_INOTIFY], [test "x${have_inotify}" = "xyes"])
+
+have_notify_win32="${have_win32}"
+AC_DEFINE_IF([HAVE_NOTIFY_WIN32],
+   [test "x${have_notify_win32}" = "xyes"], [1],
+   [File monitoring with Windows notification])
+AM_CONDITIONAL([HAVE_NOTIFY_WIN32], [test "x${have_notify_win32}" = "xyes"])
+
+AC_DEFINE_IF([HAVE_NOTIFY_COCOA],
+   [test "x${have_darwin}" = "xyes"], [1],
+   [File monitoring with fsevent notification])
+AM_CONDITIONAL([HAVE_NOTIFY_COCOA], [test "x${have_darwin}" = "xyes"])
+
 
 EFL_LIB_END([Eio])
 dnl TODO: remove these ifdefs from code!
diff --git a/src/Makefile_Eio.am b/src/Makefile_Eio.am
index d314439..ee118a3 100644
--- a/src/Makefile_Eio.am
+++ b/src/Makefile_Eio.am
@@ -23,6 +23,10 @@ lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_inotify.c
 else
 if HAVE_NOTIFY_WIN32
 lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_win32.c
+else
+if HAVE_NOTIFY_COCOA
+lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_cocoa.c
+endif
 endif
 endif
 
@@ -30,6 +34,9 @@ lib_eio_libeio_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl 
@EIO_CFLAGS@
 lib_eio_libeio_la_LIBADD = @EIO_LIBS@
 lib_eio_libeio_la_DEPENDENCIES = @EIO_INTERNAL_LIBS@
 lib_eio_libeio_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
+if HAVE_NOTIFY_COCOA
+lib_eio_libeio_la_LDFLAGS += -framework CoreServices
+endif
 
 if EFL_ENABLE_TESTS
 
diff --git a/src/lib/eio/Eio.h b/src/lib/eio/Eio.h
index 0eb38c8..8edd4ab 100644
--- a/src/lib/eio/Eio.h
+++ b/src/lib/eio/Eio.h
@@ -1219,13 +1219,13 @@ EAPI Eio_File *eio_eet_write_cipher(Eet_File *ef,
 EAPI extern int EIO_MONITOR_FILE_CREATED; /**< A new file was created in a 
watched directory */
 EAPI extern int EIO_MONITOR_FILE_DELETED; /**< A watched file was deleted, or 
a file in a watched directory was deleted */
 EAPI extern int EIO_MONITOR_FILE_MODIFIED; /**< A file was modified in a 
watched directory */
-EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< A file was closed in a watched 
directory. This event is never sent on Windows */
+EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< A file was closed in a watched 
directory. This event is never sent on Windows and OSX */
 EAPI extern int EIO_MONITOR_DIRECTORY_CREATED; /**< A new directory was 
created in a watched directory */
 EAPI extern int EIO_MONITOR_DIRECTORY_DELETED; /**< A directory has been 
deleted: this can be either a watched directory or one of its subdirectories */
 EAPI extern int EIO_MONITOR_DIRECTORY_MODIFIED; /**< A directory has been 
modified in a watched directory */
-EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< A directory has been closed 
in a watched directory. This event is never sent on Windows */
-EAPI extern int EIO_MONITOR_SELF_RENAME; /**< The monitored path has been 
renamed, an error could happen just after if the renamed path doesn't exist */
-EAPI extern int EIO_MONITOR_SELF_DELETED; /**< The monitored path has been 
removed */
+EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< A directory has been closed 
in a watched directory. This event is never sent on Windows and OSX */
+EAPI extern int EIO_MONITOR_SELF_RENAME; /**< The monitored path has been 
renamed, an error could happen just after if the renamed path doesn't exist. 
This event is never sent on OSX */
+EAPI extern int EIO_MONITOR_SELF_DELETED; /**< The monitored path has been 
removed. This event is never sent on OSX */
 EAPI extern int EIO_MONITOR_ERROR; /**< During operation the monitor failed 
and will no longer work. eio_monitor_del must be called on it. */
 
 typedef struct _Eio_Monitor Eio_Monitor;
diff --git a/src/lib/eio/eio_monitor_cocoa.c b/src/lib/eio/eio_monitor_cocoa.c
new file mode 100644
index 0000000..ea1d793
--- /dev/null
+++ b/src/lib/eio/eio_monitor_cocoa.c
@@ -0,0 +1,405 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2015 Enlightenment Developers:
+ *           Pierre Lamot <pierre.la...@openwide.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "eio_private.h"
+#include "Eio.h"
+
+#import <CoreServices/CoreServices.h>
+
+static CFTimeInterval _latency  = 0.1;
+
+/*============================================================================*
+ *                                  Local                                     *
+ 
*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+struct _Eio_Monitor_Backend
+{
+   Eio_Monitor *parent;
+   ///the monitored path
+   char *mon_path;
+   ///the actual file path
+   char *real_path;
+};
+
+typedef struct _FSEvent_Info FSEvent_Info;
+
+struct _FSEvent_Info {
+   char *path;
+   FSEventStreamEventFlags flags;
+
+};
+
+typedef struct _Eio_FSEvent_Table Eio_FSEvent_Table;
+
+struct _Eio_FSEvent_Table
+{
+   int mask;
+   int *ev_file_code;
+   int *ev_dir_code;
+};
+
+#define EIO_FSEVENT_LINE(FSe, Ef, Ed)          \
+  { kFSEventStreamEventFlag##FSe, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed }
+
+static const Eio_FSEvent_Table match[] = {
+  EIO_FSEVENT_LINE(ItemChangeOwner, FILE_MODIFIED, DIRECTORY_MODIFIED),
+  EIO_FSEVENT_LINE(ItemInodeMetaMod, FILE_MODIFIED, DIRECTORY_MODIFIED),
+  EIO_FSEVENT_LINE(ItemXattrMod, FILE_MODIFIED, DIRECTORY_MODIFIED),
+  EIO_FSEVENT_LINE(ItemModified, FILE_MODIFIED, DIRECTORY_MODIFIED),
+  EIO_FSEVENT_LINE(ItemRemoved, FILE_DELETED, DIRECTORY_DELETED),
+  EIO_FSEVENT_LINE(ItemCreated, FILE_CREATED, DIRECTORY_CREATED),
+  EIO_FSEVENT_LINE(RootChanged, SELF_DELETED, SELF_DELETED)
+};
+
+static FSEventStreamRef _stream = NULL;
+static Eina_Hash *_fsevent_monitors = NULL;
+static CFMutableArrayRef _paths_to_watch = NULL;
+static dispatch_queue_t _dispatch_queue;
+
+static Eina_Bool
+_handle_fsevent_with_monitor(const Eina_Hash *hash EINA_UNUSED,
+                             const void *key EINA_UNUSED,
+                             void *data,
+                             void *fdata)
+{
+   FSEvent_Info *event_info = (FSEvent_Info*)fdata;
+   Eio_Monitor_Backend *backend = (Eio_Monitor_Backend*)data;
+   FSEventStreamEventFlags flags = event_info->flags;
+   unsigned int i;
+   Eina_Bool is_dir;
+   unsigned int length, tmp_length;
+
+   char *tmp = NULL;
+
+   if (backend->parent->delete_me)
+     return 1;
+
+   if (!eina_str_has_prefix(event_info->path, backend->real_path))
+     {
+        return 1;
+     }
+
+   length = strlen(event_info->path) - strlen(backend->real_path);
+   if (length == 0)
+     {
+        tmp = strdup(backend->parent->path);
+     }
+   else
+     {
+        tmp_length =
+          eina_stringshare_strlen(backend->parent->path) + length + 2;
+
+        tmp = malloc(sizeof(char) * tmp_length);
+        snprintf(tmp, tmp_length, "%s/%s",
+                 backend->parent->path,
+                 &(event_info->path[strlen(backend->real_path) + 1]));
+     }
+
+   is_dir = !!(flags & kFSEventStreamEventFlagItemIsDir);
+
+   for (i = 0; i < sizeof (match) / sizeof (Eio_FSEvent_Table); ++i)
+     if (match[i].mask & flags)
+       {
+          DBG("send event from %s with event %X\n", event_info->path, flags);
+          _eio_monitor_send(backend->parent,
+                            tmp,
+                            is_dir ? *match[i].ev_dir_code : 
*match[i].ev_file_code);
+       }
+
+   free(tmp);
+   //we have found the right event, no need to continue
+   return 0;
+}
+
+
+static void
+_main_loop_send_event(void *data)
+{
+   FSEvent_Info *info = (FSEvent_Info*)data;
+
+   if (!_stream)
+     {
+        //this can happen, when eio_shutdown is called
+        goto cleanup;
+     }
+
+   if ((info->flags & kFSEventStreamEventFlagKernelDropped) != 0)
+     {
+        _eio_monitor_send(NULL, "", EIO_MONITOR_ERROR);
+        goto cleanup;
+     }
+
+   eina_hash_foreach(_fsevent_monitors,
+                     _handle_fsevent_with_monitor,
+                     info);
+
+ cleanup:
+   free(info->path);
+   free(info);
+}
+
+
+static void
+_eio_fsevent_cb(ConstFSEventStreamRef stream_ref EINA_UNUSED,
+                void *ctx EINA_UNUSED,
+                size_t count,
+                void *event_paths,
+                const FSEventStreamEventFlags event_flags[],
+                const FSEventStreamEventId event_ids[] EINA_UNUSED
+                )
+{
+   size_t i;
+   FSEvent_Info *event_info;
+
+   for (i = 0; i < count; i++)
+     {
+        event_info = malloc(sizeof(FSEvent_Info));
+        event_info->path = strdup(((char**)event_paths)[i]);
+        event_info->flags = event_flags[i];
+
+        ecore_main_loop_thread_safe_call_async(_main_loop_send_event,
+                                               event_info);
+     }
+}
+
+static void
+_eio_fsevent_del(void *data)
+{
+   Eio_Monitor_Backend *backend = (Eio_Monitor_Backend *)data;
+   free(backend);
+}
+
+static void
+_eio_get_monitor_path(const char *path, char **monpath, char **fullpath)
+{
+   char realPath[PATH_MAX];
+   char *realPathOk;
+   char *dname = NULL;
+   char *fname = NULL;
+   struct stat sb;
+
+   realPathOk = realpath(path, realPath);
+   if (realPathOk == NULL)
+     {
+        dname = dirname((char*)path);
+        if (strcmp(dname, ".") == 0)
+          {
+             realPathOk = realpath("./", realPath);
+          }
+        else
+          {
+             realPathOk = realpath(dname, realPath);
+          }
+
+        if (realPathOk == NULL)
+          return;
+     }
+
+   if (stat(realPath, &sb) < 0)
+     {
+        return;
+     }
+
+   if (S_ISDIR(sb.st_mode))
+     {
+        if (fullpath)
+          *fullpath = strdup(realPath);
+        if (monpath)
+          *monpath = strdup(realPath);
+     }
+   else
+     {
+        //not a directory, monitor parent
+        if (fullpath)
+          *fullpath = strdup(realPath);
+        dname = dirname(realPath);
+        if (monpath)
+          *monpath = strdup(dname);
+     }
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ 
*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+/**
+ * @endcond
+ */
+
+void eio_monitor_backend_init(void)
+{
+   _dispatch_queue = dispatch_queue_create("org.elf.fseventqueue", NULL);
+   _fsevent_monitors = eina_hash_string_small_new(_eio_fsevent_del);
+   _paths_to_watch = CFArrayCreateMutable(kCFAllocatorDefault,
+                                          0,
+                                          &kCFTypeArrayCallBacks);
+}
+
+void eio_monitor_backend_shutdown(void)
+{
+   if (_stream)
+     {
+        FSEventStreamStop(_stream);
+        FSEventStreamInvalidate(_stream);
+        FSEventStreamRelease(_stream);
+        _stream = NULL;
+     }
+   dispatch_release(_dispatch_queue);
+   eina_hash_free(_fsevent_monitors);
+   CFRelease(_paths_to_watch);
+}
+
+
+void eio_monitor_backend_add(Eio_Monitor *monitor)
+{
+   Eio_Monitor_Backend *backend;
+
+   FSEventStreamEventId eventid;
+
+   CFStringRef path = NULL;
+
+   //the path we should monitor
+   char *monitor_path = NULL;
+   //the real file path
+   char *real_path = NULL;
+
+   _eio_get_monitor_path(monitor->path, &monitor_path, &real_path);
+
+   backend = calloc(1, sizeof (Eio_Monitor_Backend));
+   if (!backend)
+     {
+        free(monitor_path);
+        eio_monitor_fallback_add(monitor);
+        return;
+     }
+
+   path = CFStringCreateWithCString(NULL,
+                                    monitor_path,
+                                    kCFStringEncodingUTF8);
+
+   CFArrayAppendValue(_paths_to_watch, path);
+
+   if (_stream)
+     {
+        eventid = FSEventStreamGetLatestEventId(_stream);
+        FSEventStreamRelease(_stream);
+        _stream = NULL;
+     }
+   else
+     {
+        eventid = kFSEventStreamEventIdSinceNow;
+     }
+
+   _stream = FSEventStreamCreate(NULL,
+                                 _eio_fsevent_cb,
+                                 NULL,
+                                 _paths_to_watch,
+                                 eventid,
+                                 _latency,
+                                 kFSEventStreamCreateFlagFileEvents
+                                 | kFSEventStreamCreateFlagNoDefer
+                                );
+
+   if (!_stream)
+     {
+        eio_monitor_fallback_add(monitor);
+        return;
+     }
+
+   backend->parent = monitor;
+   backend->mon_path = monitor_path;
+   backend->real_path = real_path;
+   monitor->backend = backend;
+
+   eina_hash_direct_add(_fsevent_monitors, monitor->path, backend);
+
+   FSEventStreamSetDispatchQueue(_stream, _dispatch_queue);
+   FSEventStreamStart(_stream);
+
+
+}
+
+void eio_monitor_backend_del(Eio_Monitor *monitor)
+{
+   Eio_Monitor_Backend *backend;
+   CFStringRef path = NULL;
+   FSEventStreamEventId eventid;
+   char *monitor_path;
+
+   if (!_stream)
+     {
+        eio_monitor_fallback_del(monitor);
+        return;
+     }
+
+   _eio_get_monitor_path(monitor->path, &monitor_path, NULL);
+
+   eventid = FSEventStreamGetLatestEventId(_stream);
+   FSEventStreamRelease(_stream);
+   _stream = NULL;
+
+   path = CFStringCreateWithCString(NULL,
+                                    monitor_path,
+                                    kCFStringEncodingUTF8);
+
+   CFIndex idx =
+     CFArrayGetFirstIndexOfValue(_paths_to_watch,
+                                 CFRangeMake(0,
+                                             CFArrayGetCount(_paths_to_watch)
+                                             ),
+                                 path);
+
+   if (idx != -1)
+     {
+        CFArrayRemoveValueAtIndex(_paths_to_watch, idx);
+     }
+
+   _stream = FSEventStreamCreate(NULL,
+                                 _eio_fsevent_cb,
+                                 NULL,
+                                 _paths_to_watch,
+                                 eventid,
+                                 _latency,
+                                 kFSEventStreamCreateFlagFileEvents
+                                 | kFSEventStreamCreateFlagNoDefer
+                                );
+   backend = monitor->backend;
+   monitor->backend = NULL;
+   if (!backend) return;
+
+   eina_hash_del(_fsevent_monitors, monitor->path, backend);
+}
+
+
+/*============================================================================*
+ *                                   API                                      *
+ 
*============================================================================*/
diff --git a/src/lib/eio/eio_monitor_poll.c b/src/lib/eio/eio_monitor_poll.c
index c93ac4d..0e222f5 100644
--- a/src/lib/eio/eio_monitor_poll.c
+++ b/src/lib/eio/eio_monitor_poll.c
@@ -270,7 +270,7 @@ _eio_monitor_fallback_timer_cb(void *data)
  * @cond LOCAL
  */
 
-#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32
+#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32 && !defined 
HAVE_NOTIFY_COCOA
 void eio_monitor_backend_init(void)
 {
 }
diff --git a/src/tests/eio/eio_test_monitor.c b/src/tests/eio/eio_test_monitor.c
index c1f10a4..378c427 100644
--- a/src/tests/eio/eio_test_monitor.c
+++ b/src/tests/eio/eio_test_monitor.c
@@ -17,9 +17,9 @@
 #define TEST_TIMEOUT_SEC 10
 #define TEST_OPERATION_DELAY 0.5
 
-static Ecore_Timer * test_timeout_timer;
+static Ecore_Timer *test_timeout_timer;
 
-static Eina_Bool _test_timeout_cb(void* data EINA_UNUSED)
+static Eina_Bool _test_timeout_cb(void *data EINA_UNUSED)
 {
    ck_abort_msg("test timeout");
    ecore_main_loop_quit();
@@ -35,16 +35,26 @@ static void _cancel_timeout()
      }
 }
 
+static Eina_Bool _test_timeout_expected(void *data EINA_UNUSED)
+{
+   if (test_timeout_timer != NULL)
+     {
+        _cancel_timeout();
+     }
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_CANCEL;
+}
+
 ///////////////// file and directory operations
 
 typedef struct {
-   const char* src;
-   const char* dst;
+   const char *src;
+   const char *dst;
 } RenameOperation;
 
-static Eina_Bool _delete_directory(void* data)
+static Eina_Bool _delete_directory(void *data)
 {
-   const char* dirname = (const char*)data;
+   const char *dirname = (const char*)data;
    if (ecore_file_is_dir(dirname))
      {
         ecore_file_recursive_rm(dirname);
@@ -52,40 +62,40 @@ static Eina_Bool _delete_directory(void* data)
    return ECORE_CALLBACK_CANCEL;
 }
 
-static Eina_Bool _create_directory(void* data)
+static Eina_Bool _create_directory(void *data)
 {
-   const char* dirname = (const char*)data;
+   const char *dirname = (const char*)data;
    ecore_file_mkpath(dirname);
    return ECORE_CALLBACK_CANCEL;
 }
 
 
-static Eina_Bool _create_file(void* data)
+static Eina_Bool _create_file(void *data)
 {
-   FILE* fd = fopen((const char*)data, "w+");
+   FILE *fd = fopen((const char*)data, "w+");
    ck_assert_ptr_ne(fd, NULL);
    fprintf(fd, "test test");
    fclose(fd);
    return ECORE_CALLBACK_CANCEL;
 }
 
-static Eina_Bool _delete_file(void* data)
+static Eina_Bool _delete_file(void *data)
 {
    Eina_Bool file_removed = ecore_file_remove((const char*)data);
    ck_assert(file_removed);
    return ECORE_CALLBACK_CANCEL;
 }
 
-static Eina_Bool _modify_file(void* data)
+static Eina_Bool _modify_file(void *data)
 {
-   FILE* fd = fopen((const char*)data, "a");
+   FILE *fd = fopen((const char*)data, "a");
    ck_assert_ptr_ne(fd, NULL);
    fprintf(fd, "appened");
    fclose(fd);
    return ECORE_CALLBACK_CANCEL;
 }
 
-static Eina_Bool _modify_attrib_file(void* data)
+static Eina_Bool _modify_attrib_file(void *data)
 {
    int ret = chmod((const char*)data, 0666);
    ck_assert_int_eq(ret, 0);
@@ -94,16 +104,17 @@ static Eina_Bool _modify_attrib_file(void* data)
 
 /////// helper functions
 
-static void _check_event_path(void* data, void* event)
+static Eina_Bool _check_event_path(void *data, void *event)
 {
-   const char* expected_path = ecore_file_realpath((const char*)data);
-   const char* actual_path = 
ecore_file_realpath(((Eio_Monitor_Event*)event)->filename);
-   ck_assert_str_eq(actual_path, expected_path);
+   const char *expected_path = (const char*)data;
+   const char *actual_path = ((Eio_Monitor_Event*)event)->filename;
+   ck_assert_str_eq((const char*)data, ((Eio_Monitor_Event*)event)->filename);
+   return EINA_TRUE;
 }
 
-static Eina_Tmpstr* _common_init()
+static Eina_Tmpstr *_common_init()
 {
-   Eina_Tmpstr* dirname;
+   Eina_Tmpstr *dirname;
    fail_if(eio_init() != 1);
    ecore_file_init();
 
@@ -114,7 +125,7 @@ static Eina_Tmpstr* _common_init()
    return dirname;
 }
 
-static void _common_shutdown(Eina_Tmpstr* dirname)
+static void _common_shutdown(Eina_Tmpstr *dirname)
 {
    _delete_directory((void*)dirname);
    ecore_file_shutdown();
@@ -124,21 +135,26 @@ static void _common_shutdown(Eina_Tmpstr* dirname)
 
 /////// tests monitoring a directory
 
-static void _file_created_cb(void* data, int type, void* event)
+static void _file_created_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_CREATED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 
 START_TEST(eio_test_monitor_directory_file_created_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_file_created_notify", 
dirname);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
 
    //monitor directory
    eio_monitor_add(dirname);
@@ -152,22 +168,27 @@ START_TEST(eio_test_monitor_directory_file_created_notify)
 }
 END_TEST
 
-static void _file_deleted_cb(void* data, int type, void* event)
+static void _file_deleted_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_DELETED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 START_TEST(eio_test_monitor_directory_file_deleted_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_file_deleted_notify", 
dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor directory
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_FILE_DELETED, 
(Ecore_Event_Handler_Cb)_file_deleted_cb, filename);
@@ -180,22 +201,27 @@ START_TEST(eio_test_monitor_directory_file_deleted_notify)
 }
 END_TEST
 
-static void _file_modified_cb(void* data, int type, void* event)
+static void _file_modified_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_MODIFIED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if(_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 START_TEST(eio_test_monitor_directory_file_modified_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_file_modified_notify", 
dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor directory
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, 
(Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@@ -209,22 +235,27 @@ 
START_TEST(eio_test_monitor_directory_file_modified_notify)
 }
 END_TEST
 
-static void _file_closed_cb(void* data, int type, void* event)
+static void _file_closed_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_FILE_CLOSED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 START_TEST(eio_test_monitor_directory_file_closed_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_file_closed_notify", 
dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor directory
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, 
(Ecore_Event_Handler_Cb)_file_closed_cb, filename);
@@ -236,20 +267,25 @@ START_TEST(eio_test_monitor_directory_file_closed_notify)
 }
 END_TEST
 
-static void _directory_created_cb(void* data, int type, void* event)
+static void _directory_created_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_CREATED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 START_TEST(eio_test_monitor_directory_directory_created_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/dircreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_directory_created_notify",
 dirname);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
 
    //monitor directory
    eio_monitor_add(dirname);
@@ -263,22 +299,27 @@ 
START_TEST(eio_test_monitor_directory_directory_created_notify)
 }
 END_TEST
 
-static void _directory_deleted_cb(void* data, int type, void* event)
+static void _directory_deleted_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_DELETED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 START_TEST(eio_test_monitor_directory_directory_deleted_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/dircreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_directory_deleted_notify",
 dirname);
    _create_directory((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor directory
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_DIRECTORY_DELETED, 
(Ecore_Event_Handler_Cb)_directory_deleted_cb, filename);
@@ -291,23 +332,28 @@ 
START_TEST(eio_test_monitor_directory_directory_deleted_notify)
 }
 END_TEST
 
-static void _directory_modified_cb(void* data, int type, void* event)
+static void _directory_modified_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_DIRECTORY_MODIFIED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 
 START_TEST(eio_test_monitor_directory_directory_modified_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_directory_directory_modified_notify",
 dirname);
    _create_directory((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor directory
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_DIRECTORY_MODIFIED, 
(Ecore_Event_Handler_Cb)_directory_modified_cb, filename);
@@ -321,18 +367,23 @@ 
START_TEST(eio_test_monitor_directory_directory_modified_notify)
 END_TEST
 
 
-static void _directory_self_deleted_cb(void* data, int type, void* event)
+static void _directory_self_deleted_cb(void *data, int type, void *event)
 {
    ck_assert_int_eq(type, (int)EIO_MONITOR_SELF_DELETED);
-   _check_event_path(data, event);
-   _cancel_timeout();
-   ecore_main_loop_quit();
+   if (_check_event_path(data, event))
+     {
+        _cancel_timeout();
+        ecore_main_loop_quit();
+     }
 }
 
 
 START_TEST(eio_test_monitor_directory_directory_self_deleted_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
+   Eina_Tmpstr *dirname = _common_init();
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
 
    //monitor directory
    eio_monitor_add(dirname);
@@ -350,12 +401,15 @@ END_TEST
 
 START_TEST(eio_test_monitor_file_file_modified_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
    filename = eina_stringshare_printf("%s/filecreated", dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor file
    eio_monitor_add(filename);
    ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, 
(Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@@ -371,12 +425,15 @@ END_TEST
 
 START_TEST(eio_test_monitor_file_file_attrib_modified_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_file_file_attrib_modified_notify", 
dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor file
    eio_monitor_add(filename);
    ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, 
(Ecore_Event_Handler_Cb)_file_modified_cb, filename);
@@ -392,12 +449,15 @@ END_TEST
 
 START_TEST(eio_test_monitor_file_file_closed_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_file_file_closed_notify", dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor file
    eio_monitor_add(dirname);
    ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, 
(Ecore_Event_Handler_Cb)_file_closed_cb, filename);
@@ -411,12 +471,15 @@ END_TEST
 
 START_TEST(eio_test_monitor_file_file_self_deleted_notify)
 {
-   Eina_Tmpstr* dirname = _common_init();
-   Eina_Stringshare* filename;
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
 
-   filename = eina_stringshare_printf("%s/filecreated", dirname);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_file_file_self_deleted_notify", 
dirname);
    _create_file((void*)filename);
 
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
    //monitor file
    eio_monitor_add(filename);
    ecore_event_handler_add(EIO_MONITOR_SELF_DELETED, 
(Ecore_Event_Handler_Cb)_directory_self_deleted_cb, filename);
@@ -429,24 +492,189 @@ 
START_TEST(eio_test_monitor_file_file_self_deleted_notify)
 }
 END_TEST
 
+START_TEST(eio_test_monitor_two_monitors_one_event)
+{
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Tmpstr *dirname2;
+
+   Eina_Stringshare *filename;
+
+   eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_event", dirname);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
+   //monitor directory
+   eio_monitor_add(dirname);
+   eio_monitor_add(dirname2);
+   ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, 
(Ecore_Event_Handler_Cb)_file_created_cb, filename);
+
+   ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
+
+   ecore_main_loop_begin();
+
+   _delete_directory((void*)dirname2);
+   _common_shutdown(dirname);
+}
+END_TEST
+
+
+START_TEST(eio_test_monitor_two_monitors_one_removed_one_event)
+{
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Tmpstr *dirname2;
+
+   Eina_Stringshare *filename;
+
+   Eio_Monitor *monitor;
+
+   eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_removed", 
dirname);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
+   //monitor directory
+   monitor = eio_monitor_add(dirname2);
+   eio_monitor_add(dirname);
+   eio_monitor_del(monitor);
+   ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, 
(Ecore_Event_Handler_Cb)_file_created_cb, filename);
+
+   ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
+
+   ecore_main_loop_begin();
+
+   _delete_directory((void*)dirname2);
+   _common_shutdown(dirname);
+}
+END_TEST
+
+static void _unexpected_event_cb(void *data, int type, void *event)
+{
+   ck_abort_msg("unexpected event");
+}
+
+START_TEST(eio_test_monitor_two_monitors_one_removed_no_event)
+{
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Tmpstr *dirname2;
+
+   Eina_Stringshare *filename;
+
+   Eio_Monitor *monitor;
+
+   eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_two_monitors_one_removed", 
dirname);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
+   //monitor directory
+   monitor = eio_monitor_add(dirname);
+   eio_monitor_add(dirname2);
+   eio_monitor_del(monitor);
+   ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, 
(Ecore_Event_Handler_Cb)_unexpected_event_cb, filename);
+
+   ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
+   ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
+
+   ecore_main_loop_begin();
+
+   _delete_directory((void*)dirname2);
+   _common_shutdown(dirname);
+}
+END_TEST
+
+START_TEST(eio_test_monitor_two_files_in_same_directory)
+{
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
+   Eina_Stringshare *filename2;
+
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_1", 
dirname);
+   filename2 = 
eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_2", 
dirname);
+   _create_file((void*)filename);
+   _create_file((void*)filename2);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
+   //monitor file
+   eio_monitor_add(filename);
+   eio_monitor_add(filename2);
+   ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, 
(Ecore_Event_Handler_Cb)_file_modified_cb, filename);
+
+   ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
+
+   ecore_main_loop_begin();
+
+   //cleanup
+   _common_shutdown(dirname);
+}
+END_TEST
+
+
+START_TEST(eio_test_monitor_two_files_in_same_directory_one_removed)
+{
+   Eina_Tmpstr *dirname = _common_init();
+   Eina_Stringshare *filename;
+   Eina_Stringshare *filename2;
+   Eio_Monitor *monitor;
+
+   filename = 
eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_one_removed_1",
 dirname);
+   filename2 = 
eina_stringshare_printf("%s/eio_test_monitor_two_files_in_same_directory_one_removed_2",
 dirname);
+   _create_file((void*)filename);
+   _create_file((void*)filename2);
+
+   //sleep to avoid catching event generated by above manipulations
+   usleep(500000);
+
+   //monitor file
+   monitor = eio_monitor_add(filename);
+   eio_monitor_add(filename2);
+   eio_monitor_del(monitor);
+
+   ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, 
(Ecore_Event_Handler_Cb)_unexpected_event_cb, filename);
+
+   ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
+   ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
+
+   ecore_main_loop_begin();
+
+   //cleanup
+   _common_shutdown(dirname);
+}
+END_TEST
+
+
 void eio_test_monitor(TCase *tc)
 {
    tcase_add_test(tc, eio_test_monitor_directory_file_created_notify);
    tcase_add_test(tc, eio_test_monitor_directory_file_deleted_notify);
    tcase_add_test(tc, eio_test_monitor_directory_file_modified_notify);
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__MACH__)
    tcase_add_test(tc, eio_test_monitor_directory_file_closed_notify);
 #endif
    tcase_add_test(tc, eio_test_monitor_directory_directory_created_notify);
    tcase_add_test(tc, eio_test_monitor_directory_directory_deleted_notify);
    tcase_add_test(tc, eio_test_monitor_directory_directory_modified_notify);
+#ifndef __MACH__
    tcase_add_test(tc, 
eio_test_monitor_directory_directory_self_deleted_notify);
+#endif
 
    tcase_add_test(tc, eio_test_monitor_file_file_modified_notify);
    tcase_add_test(tc, eio_test_monitor_file_file_attrib_modified_notify);
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__MACH__)
    tcase_add_test(tc, eio_test_monitor_file_file_closed_notify);
 #endif
+#ifndef __MACH__
    tcase_add_test(tc, eio_test_monitor_file_file_self_deleted_notify);
+#endif
 
+   tcase_add_test(tc, eio_test_monitor_two_monitors_one_event);
+   tcase_add_test(tc, eio_test_monitor_two_monitors_one_removed_one_event);
+   tcase_add_test(tc, eio_test_monitor_two_monitors_one_removed_no_event);
+   tcase_add_test(tc, eio_test_monitor_two_files_in_same_directory);
+   tcase_add_test(tc, 
eio_test_monitor_two_files_in_same_directory_one_removed);
 }

-- 


Reply via email to