From: Michael Albinus <michael.albinus@gmx.de>
Date: Wed, 25 Nov 2015 14:00:06 +0000 (+0100)
Subject: Some final fixes in file notification before merging with master
X-Git-Tag: emacs-26.0.90~2931^2
X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=bec57a4;p=emacs.git

Some final fixes in file notification before merging with master

* lisp/filenotify.el (file-notify--rm-descriptor): Remove WHAT arg.
(file-notify-callback): Improve check for `stopped' event.  Call
`file-notify-rm-watch' rather than `file-notify--rm-descriptor'.
(file-notify-add-watch): In case FILE is not a directory, call the
file monitor for the kqueue backend.  Otherwise, call the
directory monitor for the upper directory.

* src/inotify.c (inotifyevent_to_event): Extract file name from
watch_object if the event doesn't provide it.
(Finotify_add_watch): Add file name to watch_object.

* test/automated/file-notify-tests.el (file-notify--test-timeout):
Use different timeouts for different libraries.
(file-notify--test-with-events): Suppress lock files.  Flush
outstanding events before running the body.
(file-notify-test02-events, file-notify-test04-file-validity): Do
not skip cygwin tests.  Add additional test for file creation.
Adapt expected result for different backends.
(file-notify-test03-autorevert): Some of the tests don't work for
w32notify.
(file-notify-test06-many-events): Rename into both directions.
---

diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index 0d7a2b914c6..b6c1f686fe1 100644
--- a/lisp/filenotify.el
+++ b/lisp/filenotify.el
@@ -49,17 +49,16 @@ handler.  The value in the hash table is a list
 Several values for a given DIR happen only for `inotify', when
 different files from the same directory are watched.")
 
-(defun file-notify--rm-descriptor (descriptor &optional what)
+(defun file-notify--rm-descriptor (descriptor)
   "Remove DESCRIPTOR from `file-notify-descriptors'.
 DESCRIPTOR should be an object returned by `file-notify-add-watch'.
-If it is registered in `file-notify-descriptors', a stopped event is sent.
-WHAT is a file or directory name to be removed, needed just for `inotify'."
+If it is registered in `file-notify-descriptors', a stopped event is sent."
   (let* ((desc (if (consp descriptor) (car descriptor) descriptor))
 	 (file (if (consp descriptor) (cdr descriptor)))
          (registered (gethash desc file-notify-descriptors))
 	 (dir (car registered)))
 
-    (when (and (consp registered) (or (null what) (string-equal dir what)))
+    (when (consp registered)
       ;; Send `stopped' event.
       (dolist (entry (cdr registered))
 	(funcall (cdr entry)
@@ -236,7 +235,6 @@ EVENT is the cadr of the event in `file-notify-handle-event'
           (setq pending-event nil))
 
         ;; Check for stopped.
-	;;(message "file-notify-callback %S %S %S" file file1 registered)
         (setq
          stopped
          (or
@@ -244,10 +242,13 @@ EVENT is the cadr of the event in `file-notify-handle-event'
           (and
            (memq action '(deleted renamed))
            (= (length (cdr registered)) 1)
-           (string-equal
-            (file-name-nondirectory file)
-	    (or (file-name-nondirectory (car registered))
-		(car (cadr registered)))))))
+           (or
+            (string-equal
+             (file-name-nondirectory file)
+	     (file-name-nondirectory (car registered)))
+            (string-equal
+             (file-name-nondirectory file)
+             (car (cadr registered)))))))
 
 	;; Apply callback.
 	(when (and action
@@ -266,6 +267,9 @@ EVENT is the cadr of the event in `file-notify-handle-event'
 		    (and (stringp file1)
 			 (string-equal
 			  (nth 0 entry) (file-name-nondirectory file1)))))
+          ;;(message
+           ;;"file-notify-callback %S %S %S %S %S"
+           ;;(file-notify--descriptor desc file) action file file1 registered)
 	  (if file1
 	      (funcall
 	       callback
@@ -276,8 +280,7 @@ EVENT is the cadr of the event in `file-notify-handle-event'
 
       ;; Modify `file-notify-descriptors'.
       (when stopped
-        (file-notify--rm-descriptor
-         (file-notify--descriptor desc file) file)))))
+        (file-notify-rm-watch (file-notify--descriptor desc file))))))
 
 ;; `kqueue', `gfilenotify' and `w32notify' return a unique descriptor
 ;; for every `file-notify-add-watch', while `inotify' returns a unique
@@ -342,7 +345,12 @@ FILE is the name of the file whose event is being reported."
 	;; A file name handler could exist even if there is no local
 	;; file notification support.
 	(setq desc (funcall
-		    handler 'file-notify-add-watch file flags callback))
+		    handler 'file-notify-add-watch
+                    ;; kqueue does not report file changes in
+                    ;; directory monitor.  So we must watch the file
+                    ;; itself.
+                    (if (eq file-notify--library 'kqueue) file dir)
+                    flags callback))
 
       ;; Check, whether Emacs has been compiled with file notification
       ;; support.
@@ -379,7 +387,9 @@ FILE is the name of the file whose event is being reported."
                 l-flags)))
 
       ;; Call low-level function.
-      (setq desc (funcall func file l-flags 'file-notify-callback)))
+      (setq desc (funcall
+                  func (if (eq file-notify--library 'kqueue) file dir)
+                  l-flags 'file-notify-callback)))
 
     ;; Modify `file-notify-descriptors'.
     (setq file (unless (file-directory-p file) (file-name-nondirectory file))
diff --git a/src/inotify.c b/src/inotify.c
index d1a80bbad1b..6577ee28cd1 100644
--- a/src/inotify.c
+++ b/src/inotify.c
@@ -46,8 +46,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 static int inotifyfd = -1;
 
 /* Assoc list of files being watched.
-   Format:
-   (watch-descriptor . callback)
+   Format: (watch-descriptor name callback)
  */
 static Lisp_Object watch_list;
 
@@ -106,12 +105,14 @@ inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev)
       name = make_unibyte_string (ev->name, min (len, ev->len));
       name = DECODE_FILE (name);
     }
+  else
+    name = XCAR (XCDR (watch_object));
 
   return list2 (list4 (make_watch_descriptor (ev->wd),
                        mask_to_aspects (ev->mask),
                        name,
                        make_number (ev->cookie)),
-                XCDR (watch_object));
+		Fnth (make_number (2), watch_object));
 }
 
 /* This callback is called when the FD is available for read.  The inotify
@@ -325,7 +326,7 @@ is managed internally and there is no corresponding inotify_init.  Use
       watch_list = Fdelete (watch_object, watch_list);
 
   /* Store watch object in watch list.  */
-  watch_object = Fcons (watch_descriptor, callback);
+  watch_object = list3 (watch_descriptor, encoded_file_name, callback);
   watch_list = Fcons (watch_object, watch_list);
 
   return watch_descriptor;
diff --git a/test/automated/file-notify-tests.el b/test/automated/file-notify-tests.el
index 7bacddd8855..b665dddb631 100644
--- a/test/automated/file-notify-tests.el
+++ b/test/automated/file-notify-tests.el
@@ -65,7 +65,11 @@
 
 (defun file-notify--test-timeout ()
   "Timeout to wait for arriving events, in seconds."
-  (if (file-remote-p temporary-file-directory) 6 3))
+  (cond
+   ((file-remote-p temporary-file-directory) 6)
+   ((string-equal (file-notify--test-library) "w32notify") 20)
+   ((eq system-type 'cygwin) 10)
+   (t 3)))
 
 (defun file-notify--test-cleanup ()
   "Cleanup after a test."
@@ -262,7 +266,7 @@ and the event to `file-notify--test-events'."
   (let* ((file-notify--test-event event)
          (result
           (ert-run-test (make-ert-test :body 'file-notify--test-event-test))))
-    ;; Do not add temporary files, this would confuse the checks.
+    ;; Do not add lock files, this would confuse the checks.
     (unless (string-match
 	     (regexp-quote ".#")
 	     (file-notify--event-file-name file-notify--test-event))
@@ -289,9 +293,14 @@ TIMEOUT is the maximum time to wait for, in seconds."
 Don't wait longer than timeout seconds for the events to be delivered."
   (declare (indent 1))
   (let ((outer (make-symbol "outer")))
-    `(let ((,outer file-notify--test-events))
+    `(let ((,outer file-notify--test-events)
+           create-lockfiles)
        (setq file-notify--test-expected-events
 	     (append file-notify--test-expected-events ,events))
+       ;; Flush pending events.
+       (file-notify--wait-for-events
+        (file-notify--test-timeout)
+        (input-pending-p))
        (let (file-notify--test-events)
          ,@body
          (file-notify--wait-for-events
@@ -305,11 +314,34 @@ Don't wait longer than timeout seconds for the events to be delivered."
 (ert-deftest file-notify-test02-events ()
   "Check file creation/change/removal notifications."
   (skip-unless (file-notify--test-local-enabled))
-  ;; Under cygwin there are so bad timings that it doesn't make sense to test.
-  (skip-unless (not (eq system-type 'cygwin)))
 
   (unwind-protect
       (progn
+        ;; Check file creation, change and deletion.  It doesn't work
+        ;; for cygwin and kqueue, because we don't use an implicit
+        ;; directory monitor (kqueue), or the timings are too bad (cygwin).
+        (unless (or (eq system-type 'cygwin)
+		    (string-equal (file-notify--test-library) "kqueue"))
+          (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
+          (should
+           (setq file-notify--test-desc
+                 (file-notify-add-watch
+                  file-notify--test-tmpfile
+                  '(change) 'file-notify--test-event-handler)))
+          (file-notify--test-with-events
+              (cond
+               ;; cygwin recognizes only `deleted' and `stopped' events.
+               ((eq system-type 'cygwin)
+                '(deleted stopped))
+               (t '(created changed deleted stopped)))
+            (write-region
+             "another text" nil file-notify--test-tmpfile nil 'no-message)
+            (read-event nil nil 0.1)
+            (delete-file file-notify--test-tmpfile))
+          ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
+          (let (file-notify--test-events)
+            (file-notify-rm-watch file-notify--test-desc)))
+
         ;; Check file change and deletion.
 	(setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
         (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
@@ -318,9 +350,23 @@ Don't wait longer than timeout seconds for the events to be delivered."
 	       (file-notify-add-watch
 		file-notify--test-tmpfile
 		'(change) 'file-notify--test-event-handler)))
-        (file-notify--test-with-events '(changed deleted)
+        (file-notify--test-with-events
+	    (cond
+	     ;; cygwin recognizes only `deleted' and `stopped' events.
+	     ((eq system-type 'cygwin)
+	      '(deleted stopped))
+             ;; inotify, kqueueg and gfilenotify raise just one
+             ;; `changed' event, the other backends show us two of
+             ;; them.
+             ((or (string-equal "inotify" (file-notify--test-library))
+                  (string-equal "kqueue" (file-notify--test-library))
+                  (string-equal "gfilenotify" (file-notify--test-library)))
+	      '(changed deleted stopped))
+	     (t '(changed changed deleted stopped)))
+          (read-event nil nil 0.1)
           (write-region
            "another text" nil file-notify--test-tmpfile nil 'no-message)
+          (read-event nil nil 0.1)
           (delete-file file-notify--test-tmpfile))
 	;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
 	(let (file-notify--test-events)
@@ -328,29 +374,37 @@ Don't wait longer than timeout seconds for the events to be delivered."
 
         ;; Check file creation, change and deletion when watching a
         ;; directory.  There must be a `stopped' event when deleting
-        ;; the directory.  It doesn't work for w32notify.
-	(unless (string-equal (file-notify--test-library) "w32notify")
-	  (let ((temporary-file-directory
-		 (make-temp-file "file-notify-test-parent" t)))
-	    (should
-	     (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
-		   file-notify--test-desc
-		   (file-notify-add-watch
-		    temporary-file-directory
-		    '(change) 'file-notify--test-event-handler)))
-	    (file-notify--test-with-events
-		;; There are two `deleted' events, for the file and
-		;; for the directory.  Except for kqueue.
-		(if (string-equal (file-notify--test-library) "kqueue")
-		    '(created changed deleted stopped)
-		  '(created changed deleted deleted stopped))
-	      (write-region
-	       "any text" nil file-notify--test-tmpfile nil 'no-message)
-	      (read-event nil nil 0.1)
-	      (delete-directory temporary-file-directory 'recursive))
-	    ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
-	    (let (file-notify--test-events)
-	      (file-notify-rm-watch file-notify--test-desc))))
+        ;; the directory.
+	(let ((temporary-file-directory
+	       (make-temp-file "file-notify-test-parent" t)))
+	  (should
+	   (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
+		 file-notify--test-desc
+		 (file-notify-add-watch
+		  temporary-file-directory
+		  '(change) 'file-notify--test-event-handler)))
+	  (file-notify--test-with-events
+	      (cond
+	       ;; w32notify does raise a `stopped' event when a
+	       ;; watched directory is deleted.
+	       ((string-equal (file-notify--test-library) "w32notify")
+		'(created changed deleted))
+	       ;; cygwin recognizes only `deleted' and `stopped' events.
+	       ((eq system-type 'cygwin)
+		'(deleted stopped))
+	       ;; There are two `deleted' events, for the file and for
+	       ;; the directory.  Except for kqueue.
+	       ((string-equal (file-notify--test-library) "kqueue")
+		'(created changed deleted stopped))
+	       (t '(created changed deleted deleted stopped)))
+	    (read-event nil nil 0.1)
+	    (write-region
+	     "any text" nil file-notify--test-tmpfile nil 'no-message)
+	    (read-event nil nil 0.1)
+	    (delete-directory temporary-file-directory 'recursive))
+	  ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
+	  (let (file-notify--test-events)
+	    (file-notify-rm-watch file-notify--test-desc)))
 
         ;; Check copy of files inside a directory.
 	(let ((temporary-file-directory
@@ -363,11 +417,22 @@ Don't wait longer than timeout seconds for the events to be delivered."
 		  temporary-file-directory
 		  '(change) 'file-notify--test-event-handler)))
 	  (file-notify--test-with-events
-	      ;; w32notify does not distinguish between `changed' and
-	      ;; `attribute-changed'.
-	      (if (string-equal (file-notify--test-library) "w32notify")
-		  '(created changed changed deleted)
+	      (cond
+	       ;; w32notify does not distinguish between `changed' and
+	       ;; `attribute-changed'.
+	       ((string-equal (file-notify--test-library) "w32notify")
+		'(created changed created changed changed changed changed
+		  deleted deleted))
+	       ;; cygwin recognizes only `deleted' and `stopped' events.
+	       ((eq system-type 'cygwin)
+		'(deleted stopped))
+	       ;; There are three `deleted' events, for two files and
+	       ;; for the directory.  Except for kqueue.
+	       ((string-equal (file-notify--test-library) "kqueue")
 		'(created changed created changed deleted stopped))
+	       (t '(created changed created changed
+		    deleted deleted deleted stopped)))
+	    (read-event nil nil 0.1)
 	    (write-region
 	     "any text" nil file-notify--test-tmpfile nil 'no-message)
 	    (read-event nil nil 0.1)
@@ -393,7 +458,21 @@ Don't wait longer than timeout seconds for the events to be delivered."
 		 (file-notify-add-watch
 		  temporary-file-directory
 		  '(change) 'file-notify--test-event-handler)))
-	  (file-notify--test-with-events '(created changed renamed)
+	  (file-notify--test-with-events
+	      (cond
+	       ;; w32notify does not distinguish between `changed' and
+	       ;; `attribute-changed'.
+	       ((string-equal (file-notify--test-library) "w32notify")
+		'(created changed renamed deleted))
+	       ;; cygwin recognizes only `deleted' and `stopped' events.
+	       ((eq system-type 'cygwin)
+		'(deleted stopped))
+	       ;; There are two `deleted' events, for the file and for
+	       ;; the directory.  Except for kqueue.
+	       ((string-equal (file-notify--test-library) "kqueue")
+		'(created changed renamed deleted stopped))
+	       (t '(created changed renamed deleted deleted stopped)))
+	    (read-event nil nil 0.1)
 	    (write-region
 	     "any text" nil file-notify--test-tmpfile nil 'no-message)
 	    (read-event nil nil 0.1)
@@ -405,30 +484,37 @@ Don't wait longer than timeout seconds for the events to be delivered."
 	  (let (file-notify--test-events)
 	    (file-notify-rm-watch file-notify--test-desc)))
 
-        ;; Check attribute change.  It doesn't work for kqueue and w32notify.
-	(unless (or (string-equal (file-notify--test-library) "kqueue")
-		    (string-equal (file-notify--test-library) "w32notify"))
+        ;; Check attribute change.  Does not work for cygwin.
+	(unless (eq system-type 'cygwin)
+	  (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
+	  (write-region
+	   "any text" nil file-notify--test-tmpfile nil 'no-message)
 	  (should
 	   (setq file-notify--test-desc
 		 (file-notify-add-watch
 		  file-notify--test-tmpfile
 		  '(attribute-change) 'file-notify--test-event-handler)))
-          (file-notify--test-with-events
-              (if (file-remote-p temporary-file-directory)
-                  ;; In the remote case, `write-region' raises also an
-                  ;; `attribute-changed' event.
-                  '(attribute-changed attribute-changed attribute-changed)
-                '(attribute-changed attribute-changed))
-            ;; We must use short delays between the operations.
-            ;; Otherwise, not all events arrive us in the remote case.
-            (write-region
-             "any text" nil file-notify--test-tmpfile nil 'no-message)
-            (read-event nil nil 0.1)
-            (set-file-modes file-notify--test-tmpfile 000)
-            (read-event nil nil 0.1)
-            (set-file-times file-notify--test-tmpfile '(0 0))
-            (read-event nil nil 0.1)
-            (delete-file file-notify--test-tmpfile))
+	  (file-notify--test-with-events
+	      (cond
+	       ;; w32notify does not distinguish between `changed' and
+	       ;; `attribute-changed'.
+	       ((string-equal (file-notify--test-library) "w32notify")
+		'(changed changed changed changed))
+	       ;; For kqueue and in the remote case, `write-region'
+	       ;; raises also an `attribute-changed' event.
+	       ((or (string-equal (file-notify--test-library) "kqueue")
+		    (file-remote-p temporary-file-directory))
+		'(attribute-changed attribute-changed attribute-changed))
+	       (t '(attribute-changed attribute-changed)))
+	    (read-event nil nil 0.1)
+	    (write-region
+	     "any text" nil file-notify--test-tmpfile nil 'no-message)
+	    (read-event nil nil 0.1)
+	    (set-file-modes file-notify--test-tmpfile 000)
+	    (read-event nil nil 0.1)
+	    (set-file-times file-notify--test-tmpfile '(0 0))
+	    (read-event nil nil 0.1)
+	    (delete-file file-notify--test-tmpfile))
 	  ;; `file-notify-rm-watch' fires the `stopped' event.  Suppress it.
 	  (let (file-notify--test-events)
 	    (file-notify-rm-watch file-notify--test-desc)))
@@ -504,28 +590,31 @@ Don't wait longer than timeout seconds for the events to be delivered."
 	    (should (string-match "another text" (buffer-string)))
 
             ;; Stop file notification.  Autorevert shall still work via polling.
-	    (file-notify-rm-watch auto-revert-notify-watch-descriptor)
-            (file-notify--wait-for-events
-             timeout (null auto-revert-use-notify))
-	    (should-not auto-revert-use-notify)
-	    (should-not auto-revert-notify-watch-descriptor)
-
-	    ;; Modify file.  We wait for two seconds, in order to have
-	    ;; another timestamp.  One second seems to be too short.
-            (with-current-buffer (get-buffer-create "*Messages*")
-              (narrow-to-region (point-max) (point-max)))
-	    (sleep-for 2)
-            (write-region
-             "foo bla" nil file-notify--test-tmpfile nil 'no-message)
-
-	    ;; Check, that the buffer has been reverted.
-	    (with-current-buffer (get-buffer-create "*Messages*")
+	    ;; It doesn't work for `w32notify'.
+	    (unless (string-equal (file-notify--test-library) "w32notify")
+	      (file-notify-rm-watch auto-revert-notify-watch-descriptor)
 	      (file-notify--wait-for-events
-	       timeout
-	       (string-match
-                (format-message "Reverting buffer `%s'." (buffer-name buf))
-                (buffer-string))))
-	    (should (string-match "foo bla" (buffer-string)))))
+	       timeout (null auto-revert-use-notify))
+	      (should-not auto-revert-use-notify)
+	      (should-not auto-revert-notify-watch-descriptor)
+
+	      ;; Modify file.  We wait for two seconds, in order to
+	      ;; have another timestamp.  One second seems to be too
+	      ;; short.
+	      (with-current-buffer (get-buffer-create "*Messages*")
+		(narrow-to-region (point-max) (point-max)))
+	      (sleep-for 2)
+	      (write-region
+	       "foo bla" nil file-notify--test-tmpfile nil 'no-message)
+
+	      ;; Check, that the buffer has been reverted.
+	      (with-current-buffer (get-buffer-create "*Messages*")
+		(file-notify--wait-for-events
+		 timeout
+		 (string-match
+		  (format-message "Reverting buffer `%s'." (buffer-name buf))
+		  (buffer-string))))
+	      (should (string-match "foo bla" (buffer-string))))))
 
       ;; Cleanup.
       (with-current-buffer "*Messages*" (widen))
@@ -538,8 +627,6 @@ Don't wait longer than timeout seconds for the events to be delivered."
 (ert-deftest file-notify-test04-file-validity ()
   "Check `file-notify-valid-p' for files."
   (skip-unless (file-notify--test-local-enabled))
-  ;; Under cygwin there are so bad timings that it doesn't make sense to test.
-  (skip-unless (not (eq system-type 'cygwin)))
 
   (unwind-protect
       (progn
@@ -569,7 +656,20 @@ Don't wait longer than timeout seconds for the events to be delivered."
 	       (file-notify-add-watch
 		file-notify--test-tmpfile
 		'(change) #'file-notify--test-event-handler)))
-        (file-notify--test-with-events '(changed deleted)
+        (file-notify--test-with-events
+            (cond
+             ;; cygwin recognizes only `deleted' and `stopped' events.
+	     ((eq system-type 'cygwin)
+	      '(deleted stopped))
+             ;; inotify, kqueueg and gfilenotify raise just one
+             ;; `changed' event, the other backends show us two of
+             ;; them.
+             ((or (string-equal "inotify" (file-notify--test-library))
+                  (string-equal "kqueue" (file-notify--test-library))
+                  (string-equal "gfilenotify" (file-notify--test-library)))
+	      '(changed deleted stopped))
+	     (t '(changed changed deleted stopped)))
+	  (read-event nil nil 0.1)
           (should (file-notify-valid-p file-notify--test-desc))
           (write-region
            "another text" nil file-notify--test-tmpfile nil 'no-message)
@@ -583,10 +683,10 @@ Don't wait longer than timeout seconds for the events to be delivered."
     (file-notify--test-cleanup))
 
   (unwind-protect
-      ;; The batch-mode operation of w32notify is fragile (there's no
-      ;; input threads to send the message to).
+      ;; w32notify does not send a `stopped' event when deleting a
+      ;; directory.  The test does not work, therefore.
       (unless (string-equal (file-notify--test-library) "w32notify")
-        (let ((temporary-file-directory
+	(let ((temporary-file-directory
 	       (make-temp-file "file-notify-test-parent" t)))
 	  (should
 	   (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
@@ -594,20 +694,25 @@ Don't wait longer than timeout seconds for the events to be delivered."
 		 (file-notify-add-watch
 		  temporary-file-directory
 		  '(change) #'file-notify--test-event-handler)))
-          (file-notify--test-with-events
-	      ;; There are two `deleted' events, for the file and for
-	      ;; the directory.  Except for kqueue.
-	      (if (string-equal (file-notify--test-library) "kqueue")
-		  '(created changed deleted stopped)
-		'(created changed deleted deleted stopped))
-            (should (file-notify-valid-p file-notify--test-desc))
-            (write-region
-             "any text" nil file-notify--test-tmpfile nil 'no-message)
-            (read-event nil nil 0.1)
+	  (file-notify--test-with-events
+	      (cond
+	       ;; cygwin recognizes only `deleted' and `stopped' events.
+	       ((eq system-type 'cygwin)
+		'(deleted stopped))
+	       ;; There are two `deleted' events, for the file and for
+	       ;; the directory.  Except for kqueue.
+	       ((string-equal (file-notify--test-library) "kqueue")
+		'(created changed deleted stopped))
+	       (t '(created changed deleted deleted stopped)))
+	    (should (file-notify-valid-p file-notify--test-desc))
+	    (read-event nil nil 0.1)
+	    (write-region
+	     "any text" nil file-notify--test-tmpfile nil 'no-message)
+	    (read-event nil nil 0.1)
 	    (delete-directory temporary-file-directory t))
-          ;; After deleting the parent directory, the descriptor must
-          ;; not be valid anymore.
-          (should-not (file-notify-valid-p file-notify--test-desc))))
+	  ;; After deleting the parent directory, the descriptor must
+	  ;; not be valid anymore.
+	  (should-not (file-notify-valid-p file-notify--test-desc))))
 
     ;; Cleanup.
     (file-notify--test-cleanup)))
@@ -659,7 +764,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
         ;; valid anymore.
         (delete-directory file-notify--test-tmpfile t)
         (file-notify--wait-for-events
-         (file-notify--test-timeout)
+	 (file-notify--test-timeout)
 	 (not (file-notify-valid-p file-notify--test-desc)))
         (should-not (file-notify-valid-p file-notify--test-desc)))
 
@@ -672,8 +777,9 @@ Don't wait longer than timeout seconds for the events to be delivered."
 (ert-deftest file-notify-test06-many-events ()
   "Check that events are not dropped."
   (skip-unless (file-notify--test-local-enabled))
-  ;; Under cygwin there are so bad timings that it doesn't make sense to test.
+  ;; Under cygwin events arrive in random order.  Impossible to define a test.
   (skip-unless (not (eq system-type 'cygwin)))
+
   (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
   (make-directory file-notify--test-tmpfile)
   (should
@@ -699,10 +805,18 @@ Don't wait longer than timeout seconds for the events to be delivered."
           (let ((source-file-list source-file-list)
                 (target-file-list target-file-list))
             (while (and source-file-list target-file-list)
+              (read-event nil nil 0.1)
               (write-region "" nil (pop source-file-list) nil 'no-message)
               (read-event nil nil 0.1)
               (write-region "" nil (pop target-file-list) nil 'no-message))))
-        (file-notify--test-with-events (make-list n 'renamed)
+        (file-notify--test-with-events
+	    (cond
+	     ;; w32notify fires both `deleted' and `renamed' events.
+	     ((string-equal (file-notify--test-library) "w32notify")
+	      (let (r)
+		(dotimes (i n r)
+		  (setq r (append '(deleted renamed) r)))))
+	     (t (make-list n 'renamed)))
           (let ((source-file-list source-file-list)
                 (target-file-list target-file-list))
             (while (and source-file-list target-file-list)
@@ -725,7 +839,7 @@ Don't wait longer than timeout seconds for the events to be delivered."
 ;; TODO:
 
 ;; * For w32notify, no stopped events arrive when a directory is removed.
-;; * Try to handle arriving events under cygwin reliably.
+;; * Check, why cygwin recognizes only `deleted' and `stopped' events.
 
 (provide 'file-notify-tests)
 ;;; file-notify-tests.el ends here