Disable the recently added wxFileSystemWatcher unit case under Windows.
[wxWidgets.git] / tests / fswatcher / fswatchertest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/fswatcher/fswatchertest.cpp
3 // Purpose: wxFileSystemWatcher unit test
4 // Author: Bartosz Bekier
5 // Created: 2009-06-11
6 // RCS-ID: $Id$
7 // Copyright: (c) 2009 Bartosz Bekier
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 #include "testprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #ifndef WX_PRECOMP
21 #include "wx/timer.h"
22 #endif
23
24 #include "wx/evtloop.h"
25 #include "wx/filename.h"
26 #include "wx/filefn.h"
27 #include "wx/stdpaths.h"
28 #include "wx/fswatcher.h"
29
30 #include "testfile.h"
31
32 // ----------------------------------------------------------------------------
33 // local functions
34 // ----------------------------------------------------------------------------
35
36 // class generating file system events
37 class EventGenerator
38 {
39 public:
40 static EventGenerator& Get()
41 {
42 if (!ms_instance)
43 ms_instance = new EventGenerator(GetWatchDir());
44
45 return *ms_instance;
46 }
47
48 EventGenerator(const wxFileName& path) : m_base(path)
49 {
50 m_old = wxFileName();
51 m_file = RandomName();
52 m_new = RandomName();
53 }
54
55 // operations
56 bool CreateFile()
57 {
58 wxFile file(m_file.GetFullPath(), wxFile::write);
59 return file.IsOpened() && m_file.FileExists();
60 }
61
62 bool RenameFile()
63 {
64 CPPUNIT_ASSERT(m_file.FileExists());
65
66 wxLogDebug("Renaming %s=>%s", m_file.GetFullPath(), m_new.GetFullPath());
67
68 bool ret = wxRenameFile(m_file.GetFullPath(), m_new.GetFullPath());
69 if (ret)
70 {
71 m_old = m_file;
72 m_file = m_new;
73 m_new = RandomName();
74 }
75
76 return ret;
77 }
78
79 bool DeleteFile()
80 {
81 CPPUNIT_ASSERT(m_file.FileExists());
82
83 bool ret = wxRemoveFile(m_file.GetFullPath());
84 if (ret)
85 {
86 m_old = m_file;
87 m_file = m_new;
88 m_new = RandomName();
89 }
90
91 return ret;
92 }
93
94 bool TouchFile()
95 {
96 return m_file.Touch();
97 }
98
99 bool ReadFile()
100 {
101 wxFile f(m_file.GetFullPath());
102 CPPUNIT_ASSERT(f.IsOpened());
103
104 char buf[1];
105 ssize_t count = f.Read(buf, sizeof(buf));
106 CPPUNIT_ASSERT(count > 0);
107
108 return true;
109 }
110
111 bool ModifyFile()
112 {
113 CPPUNIT_ASSERT(m_file.FileExists());
114
115 wxFile file(m_file.GetFullPath(), wxFile::write_append);
116 CPPUNIT_ASSERT(file.IsOpened());
117
118 CPPUNIT_ASSERT(file.Write("Words of Wisdom, Lloyd. Words of wisdom\n"));
119 return file.Close();
120 }
121
122 // helpers
123 wxFileName RandomName(int length = 10)
124 {
125 return RandomName(m_base, length);
126 }
127
128 // static helpers
129 static const wxFileName& GetWatchDir()
130 {
131 static wxFileName dir;
132
133 if (dir.DirExists())
134 return dir;
135
136 wxString tmp = wxStandardPaths::Get().GetTempDir();
137 dir.AssignDir(tmp);
138
139 // XXX look for more unique name? there is no function to generate
140 // unique filename, the file always get created...
141 dir.AppendDir("fswatcher_test");
142 CPPUNIT_ASSERT(!dir.DirExists());
143 CPPUNIT_ASSERT(dir.Mkdir());
144
145 return dir;
146 }
147
148 static void RemoveWatchDir()
149 {
150 wxFileName dir = GetWatchDir();
151 CPPUNIT_ASSERT(dir.DirExists());
152
153 // just to be really sure we know what we remove
154 CPPUNIT_ASSERT_EQUAL( "fswatcher_test", dir.GetDirs().Last() );
155
156 // FIXME-VC6: using non-static Rmdir() results in ICE
157 CPPUNIT_ASSERT( wxFileName::Rmdir(dir.GetFullPath(), wxPATH_RMDIR_RECURSIVE) );
158 }
159
160 static wxFileName RandomName(const wxFileName& base, int length = 10)
161 {
162 static int ALFA_CNT = 'z' - 'a';
163
164 wxString s;
165 for (int i = 0 ; i < length; ++i)
166 {
167 char c = 'a' + (rand() % ALFA_CNT);
168 s += c;
169 }
170
171 return wxFileName(base.GetFullPath(), s);
172 }
173
174 public:
175 wxFileName m_base; // base dir for doing operations
176 wxFileName m_file; // current file name
177 wxFileName m_old; // previous file name
178 wxFileName m_new; // name after renaming
179
180 protected:
181 static EventGenerator* ms_instance;
182 };
183
184 EventGenerator* EventGenerator::ms_instance = 0;
185
186
187 // custom event handler
188 class EventHandler : public wxEvtHandler
189 {
190 public:
191 enum { WAIT_DURATION = 3 };
192
193 EventHandler() :
194 eg(EventGenerator::Get()), m_loop(0), m_count(0), m_watcher(0)
195 {
196 m_loop = new wxEventLoop();
197 Connect(wxEVT_IDLE, wxIdleEventHandler(EventHandler::OnIdle));
198 Connect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(
199 EventHandler::OnFileSystemEvent));
200 }
201
202 virtual ~EventHandler()
203 {
204 delete m_watcher;
205 if (m_loop)
206 {
207 if (m_loop->IsRunning())
208 m_loop->Exit();
209 delete m_loop;
210 }
211 }
212
213 void Exit()
214 {
215 m_loop->Exit();
216 }
217
218 // sends idle event, so we get called in a moment
219 void SendIdle()
220 {
221 wxIdleEvent* e = new wxIdleEvent();
222 QueueEvent(e);
223 }
224
225 void Run()
226 {
227 SendIdle();
228 m_loop->Run();
229 }
230
231 void OnIdle(wxIdleEvent& /*evt*/)
232 {
233 bool more = Action();
234 m_count++;
235
236 if (more)
237 {
238 SendIdle();
239 }
240 }
241
242 // returns whether we should produce more idle events
243 virtual bool Action()
244 {
245 switch (m_count)
246 {
247 case 0:
248 CPPUNIT_ASSERT(Init());
249 break;
250 case 1:
251 GenerateEvent();
252 break;
253 case 2:
254 // actual test
255 CheckResult();
256 Exit();
257 break;
258
259 // TODO a mechanism that will break the loop in case we
260 // don't receive a file system event
261 // this below doesn't quite work, so all tests must pass :-)
262 #if 0
263 case 2:
264 m_loop.Yield();
265 m_loop.WakeUp();
266 CPPUNIT_ASSERT(KeepWaiting());
267 m_loop.Yield();
268 break;
269 case 3:
270 break;
271 case 4:
272 CPPUNIT_ASSERT(AfterWait());
273 break;
274 #endif
275 } // switch (m_count)
276
277 return m_count <= 0;
278 }
279
280 virtual bool Init()
281 {
282 // test we're good to go
283 CPPUNIT_ASSERT(wxEventLoopBase::GetActive());
284
285 // XXX only now can we construct Watcher, because we need
286 // active loop here
287 m_watcher = new wxFileSystemWatcher();
288 m_watcher->SetOwner(this);
289
290 // add dir to be watched
291 wxFileName dir = EventGenerator::GetWatchDir();
292 CPPUNIT_ASSERT(m_watcher->Add(dir, wxFSW_EVENT_ALL));
293
294 return true;
295 }
296
297 virtual bool KeepWaiting()
298 {
299 // did we receive event already?
300 if (!tested)
301 {
302 // well, let's wait a bit more
303 wxSleep(WAIT_DURATION);
304 }
305
306 return true;
307 }
308
309 virtual bool AfterWait()
310 {
311 // fail if still no events
312 WX_ASSERT_MESSAGE
313 (
314 ("No events during %d seconds!", static_cast<int>(WAIT_DURATION)),
315 tested
316 );
317
318 return true;
319 }
320
321 virtual void OnFileSystemEvent(wxFileSystemWatcherEvent& evt)
322 {
323 wxLogDebug("--- %s ---", evt.ToString());
324 m_lastEvent = wxDynamicCast(evt.Clone(), wxFileSystemWatcherEvent);
325 m_events.Add(m_lastEvent);
326
327 // test finished
328 SendIdle();
329 tested = true;
330 }
331
332 virtual void CheckResult()
333 {
334 CPPUNIT_ASSERT_MESSAGE( "No events received", !m_events.empty() );
335
336 const wxFileSystemWatcherEvent * const e = m_events.front();
337
338 // this is our "reference event"
339 const wxFileSystemWatcherEvent expected = ExpectedEvent();
340
341 CPPUNIT_ASSERT_EQUAL( expected.GetChangeType(), e->GetChangeType() );
342
343 CPPUNIT_ASSERT_EQUAL((int)wxEVT_FSWATCHER, e->GetEventType());
344
345 // XXX this needs change
346 CPPUNIT_ASSERT_EQUAL(wxEVT_CATEGORY_UNKNOWN, e->GetEventCategory());
347
348 CPPUNIT_ASSERT_EQUAL(expected.GetPath(), e->GetPath());
349 CPPUNIT_ASSERT_EQUAL(expected.GetNewPath(), e->GetNewPath());
350
351 // Under MSW extra modification events are sometimes reported after a
352 // rename and we just can't get rid of them, so ignore them in this
353 // test if they do happen.
354 if ( e->GetChangeType() == wxFSW_EVENT_RENAME &&
355 m_events.size() == 2 )
356 {
357 const wxFileSystemWatcherEvent* const e2 = m_events.back();
358 if ( e2->GetChangeType() == wxFSW_EVENT_MODIFY &&
359 e2->GetPath() == e->GetNewPath() )
360 {
361 // This is a modify event for the new file, ignore it.
362 return;
363 }
364 }
365
366 WX_ASSERT_EQUAL_MESSAGE
367 (
368 (
369 "Extra events received, last one is of type %x, path=\"%s\" "
370 "(the original event was for \"%s\" (\"%s\")",
371 m_events.back()->GetChangeType(),
372 m_events.back()->GetPath().GetFullPath(),
373 e->GetPath().GetFullPath(),
374 e->GetNewPath().GetFullPath()
375 ),
376 1, m_events.size()
377 );
378
379 }
380
381 virtual void GenerateEvent() = 0;
382
383 virtual wxFileSystemWatcherEvent ExpectedEvent() = 0;
384
385
386 protected:
387 EventGenerator& eg;
388 wxEventLoopBase* m_loop; // loop reference
389 int m_count; // idle events count
390
391 wxFileSystemWatcher* m_watcher;
392 bool tested; // indicates, whether we have already passed the test
393
394 #include "wx/arrimpl.cpp"
395 WX_DEFINE_ARRAY_PTR(wxFileSystemWatcherEvent*, wxArrayEvent);
396 wxArrayEvent m_events;
397 wxFileSystemWatcherEvent* m_lastEvent;
398 };
399
400
401 // ----------------------------------------------------------------------------
402 // test class
403 // ----------------------------------------------------------------------------
404
405 class FileSystemWatcherTestCase : public CppUnit::TestCase
406 {
407 public:
408 FileSystemWatcherTestCase() { }
409
410 virtual void setUp();
411 virtual void tearDown();
412
413 protected:
414 wxEventLoopBase* m_loop;
415
416 private:
417 CPPUNIT_TEST_SUITE( FileSystemWatcherTestCase );
418 CPPUNIT_TEST( TestEventCreate );
419 CPPUNIT_TEST( TestEventDelete );
420
421 // FIXME: Currently this test fails under Windows.
422 #ifndef __WINDOWS__
423 CPPUNIT_TEST( TestTrees );
424 #endif // __WINDOWS__
425
426 // kqueue-based implementation doesn't collapse create/delete pairs in
427 // renames and doesn't detect neither modifications nor access to the
428 // files reliably currently so disable these tests
429 //
430 // FIXME: fix the code and reenable them
431 #ifndef wxHAS_KQUEUE
432 CPPUNIT_TEST( TestEventRename );
433 CPPUNIT_TEST( TestEventModify );
434
435 // MSW implementation doesn't detect file access events currently
436 #ifndef __WINDOWS__
437 CPPUNIT_TEST( TestEventAccess );
438 #endif // __WINDOWS__
439 #endif // !wxHAS_KQUEUE
440
441 CPPUNIT_TEST( TestNoEventsAfterRemove );
442 CPPUNIT_TEST_SUITE_END();
443
444 void TestEventCreate();
445 void TestEventDelete();
446 void TestEventRename();
447 void TestEventModify();
448 void TestEventAccess();
449 #ifndef __WINDOWS__
450 void TestTrees();
451 #endif // __WINDOWS__
452
453 void TestNoEventsAfterRemove();
454
455 DECLARE_NO_COPY_CLASS(FileSystemWatcherTestCase)
456 };
457
458 // the test currently hangs under OS X for some reason and this prevents tests
459 // ran by buildbot from completing so disable it until someone has time to
460 // debug it
461 //
462 // FIXME: debug and fix this!
463 #ifndef __WXOSX__
464 // register in the unnamed registry so that these tests are run by default
465 CPPUNIT_TEST_SUITE_REGISTRATION( FileSystemWatcherTestCase );
466 #endif
467
468 // also include in its own registry so that these tests can be run alone
469 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FileSystemWatcherTestCase,
470 "FileSystemWatcherTestCase" );
471
472 void FileSystemWatcherTestCase::setUp()
473 {
474 wxLog::AddTraceMask(wxTRACE_FSWATCHER);
475 EventGenerator::Get().GetWatchDir();
476 }
477
478 void FileSystemWatcherTestCase::tearDown()
479 {
480 EventGenerator::Get().RemoveWatchDir();
481 }
482
483 // ----------------------------------------------------------------------------
484 // TestEventCreate
485 // ----------------------------------------------------------------------------
486 void FileSystemWatcherTestCase::TestEventCreate()
487 {
488 wxLogDebug("TestEventCreate()");
489
490 class EventTester : public EventHandler
491 {
492 public:
493 virtual void GenerateEvent()
494 {
495 CPPUNIT_ASSERT(eg.CreateFile());
496 }
497
498 virtual wxFileSystemWatcherEvent ExpectedEvent()
499 {
500 wxFileSystemWatcherEvent event(wxFSW_EVENT_CREATE);
501 event.SetPath(eg.m_file);
502 event.SetNewPath(eg.m_file);
503 return event;
504 }
505 };
506
507 EventTester tester;
508
509 wxLogTrace(wxTRACE_FSWATCHER, "TestEventCreate tester created()");
510
511 tester.Run();
512 }
513
514 // ----------------------------------------------------------------------------
515 // TestEventDelete
516 // ----------------------------------------------------------------------------
517 void FileSystemWatcherTestCase::TestEventDelete()
518 {
519 wxLogDebug("TestEventDelete()");
520
521 class EventTester : public EventHandler
522 {
523 public:
524 virtual void GenerateEvent()
525 {
526 CPPUNIT_ASSERT(eg.DeleteFile());
527 }
528
529 virtual wxFileSystemWatcherEvent ExpectedEvent()
530 {
531 wxFileSystemWatcherEvent event(wxFSW_EVENT_DELETE);
532 event.SetPath(eg.m_old);
533
534 // CHECK maybe new path here could be NULL or sth?
535 event.SetNewPath(eg.m_old);
536 return event;
537 }
538 };
539
540 // we need to create a file now, so we can delete it
541 EventGenerator::Get().CreateFile();
542
543 EventTester tester;
544 tester.Run();
545 }
546
547 // ----------------------------------------------------------------------------
548 // TestEventRename
549 // ----------------------------------------------------------------------------
550 void FileSystemWatcherTestCase::TestEventRename()
551 {
552 wxLogDebug("TestEventRename()");
553
554 class EventTester : public EventHandler
555 {
556 public:
557 virtual void GenerateEvent()
558 {
559 CPPUNIT_ASSERT(eg.RenameFile());
560 }
561
562 virtual wxFileSystemWatcherEvent ExpectedEvent()
563 {
564 wxFileSystemWatcherEvent event(wxFSW_EVENT_RENAME);
565 event.SetPath(eg.m_old);
566 event.SetNewPath(eg.m_file);
567 return event;
568 }
569 };
570
571 // need a file to rename later
572 EventGenerator::Get().CreateFile();
573
574 EventTester tester;
575 tester.Run();
576 }
577
578 // ----------------------------------------------------------------------------
579 // TestEventModify
580 // ----------------------------------------------------------------------------
581 void FileSystemWatcherTestCase::TestEventModify()
582 {
583 wxLogDebug("TestEventModify()");
584
585 class EventTester : public EventHandler
586 {
587 public:
588 virtual void GenerateEvent()
589 {
590 CPPUNIT_ASSERT(eg.ModifyFile());
591 }
592
593 virtual wxFileSystemWatcherEvent ExpectedEvent()
594 {
595 wxFileSystemWatcherEvent event(wxFSW_EVENT_MODIFY);
596 event.SetPath(eg.m_file);
597 event.SetNewPath(eg.m_file);
598 return event;
599 }
600 };
601
602 // we need to create a file to modify
603 EventGenerator::Get().CreateFile();
604
605 EventTester tester;
606 tester.Run();
607 }
608
609 // ----------------------------------------------------------------------------
610 // TestEventAccess
611 // ----------------------------------------------------------------------------
612 void FileSystemWatcherTestCase::TestEventAccess()
613 {
614 wxLogDebug("TestEventAccess()");
615
616 class EventTester : public EventHandler
617 {
618 public:
619 virtual void GenerateEvent()
620 {
621 CPPUNIT_ASSERT(eg.ReadFile());
622 }
623
624 virtual wxFileSystemWatcherEvent ExpectedEvent()
625 {
626 wxFileSystemWatcherEvent event(wxFSW_EVENT_ACCESS);
627 event.SetPath(eg.m_file);
628 event.SetNewPath(eg.m_file);
629 return event;
630 }
631 };
632
633 // we need to create a file to read from it and write sth to it
634 EventGenerator::Get().CreateFile();
635 EventGenerator::Get().ModifyFile();
636
637 EventTester tester;
638 tester.Run();
639 }
640
641 // ----------------------------------------------------------------------------
642 // TestTrees
643 // ----------------------------------------------------------------------------
644 #ifndef __WINDOWS__
645 void FileSystemWatcherTestCase::TestTrees()
646 {
647 class TreeTester : public EventHandler
648 {
649 const size_t subdirs;
650 const size_t files;
651
652 public:
653 TreeTester() : subdirs(5), files(3) {}
654
655 void GrowTree(wxFileName dir)
656 {
657 CPPUNIT_ASSERT(dir.Mkdir());
658
659 // Create a branch of 5 numbered subdirs, each containing 3
660 // numbered files
661 for ( unsigned d = 0; d < subdirs; ++d )
662 {
663 dir.AppendDir(wxString::Format("subdir%u", d+1));
664 CPPUNIT_ASSERT(dir.Mkdir());
665
666 const wxString prefix = dir.GetPathWithSep();
667 for ( unsigned f = 0; f < files; ++f )
668 {
669 // Just create the files.
670 wxFile(prefix + wxString::Format("file%u", f+1),
671 wxFile::write);
672 }
673 }
674 }
675
676 void RmDir(wxFileName dir)
677 {
678 CPPUNIT_ASSERT(dir.DirExists());
679
680 CPPUNIT_ASSERT(dir.Rmdir(wxPATH_RMDIR_RECURSIVE));
681 }
682
683 void WatchDir(wxFileName dir)
684 {
685 CPPUNIT_ASSERT(m_watcher);
686
687 // Store the initial count; there may already be some watches
688 const int initial = m_watcher->GetWatchedPathsCount();
689
690 m_watcher->Add(dir);
691 CPPUNIT_ASSERT_EQUAL(initial + 1,
692 m_watcher->GetWatchedPathsCount());
693 }
694
695 void RemoveSingleWatch(wxFileName dir)
696 {
697 CPPUNIT_ASSERT(m_watcher);
698
699 const int initial = m_watcher->GetWatchedPathsCount();
700
701 m_watcher->Remove(dir);
702 CPPUNIT_ASSERT_EQUAL(initial - 1,
703 m_watcher->GetWatchedPathsCount());
704 }
705
706 void WatchTree(const wxFileName& dir)
707 {
708 CPPUNIT_ASSERT(m_watcher);
709
710 const size_t
711 treeitems = (subdirs*files) + subdirs + 1; // +1 for the trunk
712
713 // Store the initial count; there may already be some watches
714 const int initial = m_watcher->GetWatchedPathsCount();
715
716 GrowTree(dir);
717
718 m_watcher->AddTree(dir);
719 const int plustree = m_watcher->GetWatchedPathsCount();
720
721 CPPUNIT_ASSERT_EQUAL(initial + treeitems, plustree);
722
723 m_watcher->RemoveTree(dir);
724 CPPUNIT_ASSERT_EQUAL(initial, m_watcher->GetWatchedPathsCount());
725 }
726
727 void RemoveAllWatches()
728 {
729 CPPUNIT_ASSERT(m_watcher);
730
731 m_watcher->RemoveAll();
732 CPPUNIT_ASSERT_EQUAL(0, m_watcher->GetWatchedPathsCount());
733 }
734
735 virtual void GenerateEvent()
736 {
737 // We don't use this function for events. Just run the tests
738
739 wxFileName watchdir = EventGenerator::GetWatchDir();
740 CPPUNIT_ASSERT(watchdir.DirExists());
741
742 wxFileName treedir(watchdir);
743 treedir.AppendDir("treetrunk");
744 CPPUNIT_ASSERT(!treedir.DirExists());
745
746 wxFileName singledir(watchdir);
747 singledir.AppendDir("single");
748 CPPUNIT_ASSERT(!singledir.DirExists());
749 CPPUNIT_ASSERT(singledir.Mkdir());
750
751 WatchDir(singledir);
752 WatchTree(treedir);
753
754 RemoveSingleWatch(singledir);
755 // Add it back again, ready to test RemoveAll()
756 WatchDir(singledir);
757
758 RemoveAllWatches();
759
760 // Clean up
761 RmDir(singledir);
762 RmDir(treedir);
763
764 Exit();
765 }
766
767 virtual wxFileSystemWatcherEvent ExpectedEvent()
768 {
769 CPPUNIT_FAIL("Shouldn't be called");
770
771 return wxFileSystemWatcherEvent(wxFSW_EVENT_ERROR);
772 }
773
774 virtual void CheckResult()
775 {
776 // Do nothing. We override this to prevent receiving events in
777 // ExpectedEvent()
778 }
779 };
780
781 TreeTester tester;
782 tester.Run();
783 }
784 #endif // __WINDOWS__
785
786 namespace
787 {
788
789 // We can't define this class locally inside TestNoEventsAfterRemove() for some
790 // reason with g++ 4.0 under OS X 10.5, it results in the following mysterious
791 // error:
792 //
793 // /var/tmp//ccTkNCkc.s:unknown:Non-global symbol:
794 // __ZThn80_ZN25FileSystemWatcherTestCase23TestNoEventsAfterRemoveEvEN11EventTester6NotifyEv.eh
795 // can't be a weak_definition
796 //
797 // So define this class outside the function instead.
798 class NoEventsAfterRemoveEventTester : public EventHandler,
799 public wxTimer
800 {
801 public:
802 NoEventsAfterRemoveEventTester()
803 {
804 // We need to use an inactivity timer as we never get any file
805 // system events in this test, so we consider that the test is
806 // finished when this 1s timeout expires instead of, as usual,
807 // stopping after getting the file system events.
808 Start(1000, true);
809 }
810
811 virtual void GenerateEvent()
812 {
813 m_watcher->Remove(EventGenerator::GetWatchDir());
814 CPPUNIT_ASSERT(eg.CreateFile());
815 }
816
817 virtual void CheckResult()
818 {
819 CPPUNIT_ASSERT( m_events.empty() );
820 }
821
822 virtual wxFileSystemWatcherEvent ExpectedEvent()
823 {
824 CPPUNIT_FAIL( "Shouldn't be called" );
825
826 return wxFileSystemWatcherEvent(wxFSW_EVENT_ERROR);
827 }
828
829 virtual void Notify()
830 {
831 SendIdle();
832 }
833 };
834
835 } // anonymous namespace
836
837 void FileSystemWatcherTestCase::TestNoEventsAfterRemove()
838 {
839 NoEventsAfterRemoveEventTester tester;
840 tester.Run();
841 }