1from __future__ import annotations
2
3from watchdog.events import (
4    EVENT_TYPE_CREATED,
5    EVENT_TYPE_DELETED,
6    EVENT_TYPE_MODIFIED,
7    EVENT_TYPE_MOVED,
8    DirCreatedEvent,
9    DirDeletedEvent,
10    DirModifiedEvent,
11    DirMovedEvent,
12    FileCreatedEvent,
13    FileDeletedEvent,
14    FileModifiedEvent,
15    FileMovedEvent,
16    LoggingEventHandler,
17    RegexMatchingEventHandler,
18)
19
20path_1 = "/path/xyz"
21path_2 = "/path/abc"
22g_allowed_regexes = [r".*\.py", r".*\.txt"]
23g_allowed_str_regexes = r".*\.py"
24g_ignore_regexes = [r".*\.pyc"]
25
26
27def test_dispatch():
28    # Utilities.
29    regexes = [r".*\.py", r".*\.txt"]
30    ignore_regexes = [r".*\.pyc"]
31
32    def assert_regexes(handler, event):
33        paths = [event.src_path, event.dest_path] if hasattr(event, "dest_path") else [event.src_path]
34        filtered_paths = set()
35        for p in paths:
36            if any(r.match(p) for r in handler.regexes):
37                filtered_paths.add(p)
38        assert filtered_paths
39
40    dir_del_event_match = DirDeletedEvent("/path/blah.py")
41    dir_del_event_not_match = DirDeletedEvent("/path/foobar")
42    dir_del_event_ignored = DirDeletedEvent("/path/foobar.pyc")
43    file_del_event_match = FileDeletedEvent("/path/blah.txt")
44    file_del_event_not_match = FileDeletedEvent("/path/foobar")
45    file_del_event_ignored = FileDeletedEvent("/path/blah.pyc")
46
47    dir_cre_event_match = DirCreatedEvent("/path/blah.py")
48    dir_cre_event_not_match = DirCreatedEvent("/path/foobar")
49    dir_cre_event_ignored = DirCreatedEvent("/path/foobar.pyc")
50    file_cre_event_match = FileCreatedEvent("/path/blah.txt")
51    file_cre_event_not_match = FileCreatedEvent("/path/foobar")
52    file_cre_event_ignored = FileCreatedEvent("/path/blah.pyc")
53
54    dir_mod_event_match = DirModifiedEvent("/path/blah.py")
55    dir_mod_event_not_match = DirModifiedEvent("/path/foobar")
56    dir_mod_event_ignored = DirModifiedEvent("/path/foobar.pyc")
57    file_mod_event_match = FileModifiedEvent("/path/blah.txt")
58    file_mod_event_not_match = FileModifiedEvent("/path/foobar")
59    file_mod_event_ignored = FileModifiedEvent("/path/blah.pyc")
60
61    dir_mov_event_match = DirMovedEvent("/path/blah.py", "/path/blah")
62    dir_mov_event_not_match = DirMovedEvent("/path/foobar", "/path/blah")
63    dir_mov_event_ignored = DirMovedEvent("/path/foobar.pyc", "/path/blah")
64    file_mov_event_match = FileMovedEvent("/path/blah.txt", "/path/blah")
65    file_mov_event_not_match = FileMovedEvent("/path/foobar", "/path/blah")
66    file_mov_event_ignored = FileMovedEvent("/path/blah.pyc", "/path/blah")
67
68    all_dir_events = [
69        dir_mod_event_match,
70        dir_mod_event_not_match,
71        dir_mod_event_ignored,
72        dir_del_event_match,
73        dir_del_event_not_match,
74        dir_del_event_ignored,
75        dir_cre_event_match,
76        dir_cre_event_not_match,
77        dir_cre_event_ignored,
78        dir_mov_event_match,
79        dir_mov_event_not_match,
80        dir_mov_event_ignored,
81    ]
82    all_file_events = [
83        file_mod_event_match,
84        file_mod_event_not_match,
85        file_mod_event_ignored,
86        file_del_event_match,
87        file_del_event_not_match,
88        file_del_event_ignored,
89        file_cre_event_match,
90        file_cre_event_not_match,
91        file_cre_event_ignored,
92        file_mov_event_match,
93        file_mov_event_not_match,
94        file_mov_event_ignored,
95    ]
96    all_events = all_file_events + all_dir_events
97
98    def assert_check_directory(handler, event):
99        assert not (handler.ignore_directories and event.is_directory)
100
101    class TestableEventHandler(RegexMatchingEventHandler):
102        def on_any_event(self, event):
103            assert_check_directory(self, event)
104
105        def on_modified(self, event):
106            assert_check_directory(self, event)
107            assert event.event_type == EVENT_TYPE_MODIFIED
108            assert_regexes(self, event)
109
110        def on_deleted(self, event):
111            assert_check_directory(self, event)
112            assert event.event_type == EVENT_TYPE_DELETED
113            assert_regexes(self, event)
114
115        def on_moved(self, event):
116            assert_check_directory(self, event)
117            assert event.event_type == EVENT_TYPE_MOVED
118            assert_regexes(self, event)
119
120        def on_created(self, event):
121            assert_check_directory(self, event)
122            assert event.event_type == EVENT_TYPE_CREATED
123            assert_regexes(self, event)
124
125    no_dirs_handler = TestableEventHandler(regexes=regexes, ignore_regexes=ignore_regexes, ignore_directories=True)
126    handler = TestableEventHandler(regexes=regexes, ignore_regexes=ignore_regexes)
127
128    for event in all_events:
129        no_dirs_handler.dispatch(event)
130    for event in all_events:
131        handler.dispatch(event)
132
133
134def test_handler():
135    handler1 = RegexMatchingEventHandler(
136        regexes=g_allowed_regexes,
137        ignore_regexes=g_ignore_regexes,
138        ignore_directories=True,
139    )
140    handler2 = RegexMatchingEventHandler(regexes=g_allowed_regexes, ignore_regexes=g_ignore_regexes)
141    assert [r.pattern for r in handler1.regexes] == g_allowed_regexes
142    assert [r.pattern for r in handler1.ignore_regexes] == g_ignore_regexes
143    assert handler1.ignore_directories
144    assert not handler2.ignore_directories
145
146
147def test_ignore_directories():
148    handler1 = RegexMatchingEventHandler(
149        regexes=g_allowed_regexes,
150        ignore_regexes=g_ignore_regexes,
151        ignore_directories=True,
152    )
153    handler2 = RegexMatchingEventHandler(regexes=g_allowed_regexes, ignore_regexes=g_ignore_regexes)
154    assert handler1.ignore_directories
155    assert not handler2.ignore_directories
156
157
158def test_ignore_regexes():
159    handler1 = RegexMatchingEventHandler(
160        regexes=g_allowed_regexes,
161        ignore_regexes=g_ignore_regexes,
162        ignore_directories=True,
163    )
164    assert [r.pattern for r in handler1.ignore_regexes] == g_ignore_regexes
165
166
167def test_regexes():
168    handler1 = RegexMatchingEventHandler(
169        regexes=g_allowed_regexes,
170        ignore_regexes=g_ignore_regexes,
171        ignore_directories=True,
172    )
173    assert [r.pattern for r in handler1.regexes] == g_allowed_regexes
174
175
176def test_str_regexes():
177    handler1 = RegexMatchingEventHandler(
178        regexes=g_allowed_str_regexes,
179        ignore_regexes=g_ignore_regexes,
180        case_sensitive=True,
181    )
182    assert [r.pattern for r in handler1.regexes] == [g_allowed_str_regexes]
183
184
185def test_logging_event_handler_dispatch():
186    class _TestableEventHandler(LoggingEventHandler):
187        def on_any_event(self, event):
188            pass
189
190        def on_modified(self, event):
191            super().on_modified(event)
192            assert event.event_type == EVENT_TYPE_MODIFIED
193
194        def on_deleted(self, event):
195            super().on_deleted(event)
196            assert event.event_type == EVENT_TYPE_DELETED
197
198        def on_moved(self, event):
199            super().on_moved(event)
200            assert event.event_type == EVENT_TYPE_MOVED
201
202        def on_created(self, event):
203            super().on_created(event)
204            assert event.event_type == EVENT_TYPE_CREATED
205
206    # Utilities.
207    dir_del_event = DirDeletedEvent("/path/blah.py")
208    file_del_event = FileDeletedEvent("/path/blah.txt")
209    dir_cre_event = DirCreatedEvent("/path/blah.py")
210    file_cre_event = FileCreatedEvent("/path/blah.txt")
211    dir_mod_event = DirModifiedEvent("/path/blah.py")
212    file_mod_event = FileModifiedEvent("/path/blah.txt")
213    dir_mov_event = DirMovedEvent("/path/blah.py", "/path/blah")
214    file_mov_event = FileMovedEvent("/path/blah.txt", "/path/blah")
215
216    all_events = [
217        dir_mod_event,
218        dir_del_event,
219        dir_cre_event,
220        dir_mov_event,
221        file_mod_event,
222        file_del_event,
223        file_cre_event,
224        file_mov_event,
225    ]
226
227    handler = _TestableEventHandler()
228    for event in all_events:
229        handler.dispatch(event)
230