Merge lp:~aaron-whitehouse/duplicity/bug_884371 into lp:~duplicity-team/duplicity/0.7-series
- bug_884371
- Merge into 0.7-series
Proposed by
Aaron Whitehouse
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 1110 | ||||||||
Proposed branch: | lp:~aaron-whitehouse/duplicity/bug_884371 | ||||||||
Merge into: | lp:~duplicity-team/duplicity/0.7-series | ||||||||
Diff against target: |
933 lines (+387/-97) 5 files modified
.bzrignore (+2/-0) duplicity/selection.py (+20/-5) po/duplicity.pot (+7/-7) testing/functional/test_selection.py (+86/-19) testing/unit/test_selection.py (+272/-66) |
||||||||
To merge this branch: | bzr merge lp:~aaron-whitehouse/duplicity/bug_884371 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
duplicity-team | Pending | ||
Review via email: mp+266162@code.launchpad.net |
Commit message
Description of the change
Fixed Bug #884371 - Stopped an exclude glob trumping an earlier scan glob, but also ensured that an exclude glob is not trumped by a later include. This fix is important, as without it files that are specified to be included are not being backed up as expected.
Fixed Bug #932482 - a trailing slash at the end of globs no longer prevents them working as expected.
To post a comment you must log in.
Revision history for this message
Aaron Whitehouse (aaron-whitehouse) wrote : | # |
- 1115. By Aaron Whitehouse <email address hidden>
-
Remove special casing for final glob in glob list as no longer necessary.
- 1116. By Aaron Whitehouse <email address hidden>
-
Remove unnecessary use of mock.patch in unit.test_
selection. py. - 1117. By Aaron Whitehouse <email address hidden>
-
Add test_glob_re unit test back in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2014-12-10 18:09:17 +0000 |
3 | +++ .bzrignore 2015-07-29 09:52:27 +0000 |
4 | @@ -10,3 +10,5 @@ |
5 | duplicity.spec |
6 | random_seed |
7 | testfiles |
8 | +./.eggs |
9 | +./.idea |
10 | |
11 | === modified file 'duplicity/selection.py' |
12 | --- duplicity/selection.py 2015-06-20 15:25:29 +0000 |
13 | +++ duplicity/selection.py 2015-07-29 09:52:27 +0000 |
14 | @@ -207,16 +207,27 @@ |
15 | if not self.selection_functions: |
16 | return 1 |
17 | scan_pending = False |
18 | - for sf in self.selection_functions[:-1]: |
19 | + for sf in self.selection_functions: |
20 | result = sf(path) |
21 | if result is 2: |
22 | + # Selection function says that the path should be scanned for matching files, but keep going |
23 | + # through the selection functions looking for a real match (0 or 1). |
24 | scan_pending = True |
25 | - if result in [0, 1]: |
26 | + elif result == 1: |
27 | + # Selection function says file should be included. |
28 | return result |
29 | + elif result == 0: |
30 | + # Selection function says file should be excluded. |
31 | + if scan_pending is False: |
32 | + return result |
33 | + else: |
34 | + # scan_pending is True, meaning that a higher-priority selection function has said that this |
35 | + # folder should be scanned. We therefore return the scan value. We return here, rather than |
36 | + # below, because we don't want the exclude to be trumped by a lower-priority include. |
37 | + return 2 |
38 | if scan_pending: |
39 | + # A selection function returned 2 and no other selection functions returned 0 or 1. |
40 | return 2 |
41 | - sf = self.selection_functions[-1] |
42 | - result = sf(path) |
43 | if result is not None: |
44 | return result |
45 | else: |
46 | @@ -327,7 +338,7 @@ |
47 | |
48 | include = include_default |
49 | if line[:2] == "+ ": |
50 | - # Check for "+ "/"- " syntax |
51 | + # Check for "+ " or "- " syntax |
52 | include = 1 |
53 | line = line[2:] |
54 | elif line[:2] == "- ": |
55 | @@ -508,6 +519,10 @@ |
56 | |
57 | """ |
58 | # Internal. Used by glob_get_sf and unit tests. |
59 | + if glob_str != "/" and glob_str[-1] == "/": |
60 | + # Remove trailing / from directory name (unless that is the entire string) |
61 | + glob_str = glob_str[:-1] |
62 | + |
63 | if glob_str.lower().startswith("ignorecase:"): |
64 | re_comp = lambda r: re.compile(r, re.I | re.S) |
65 | glob_str = glob_str[len("ignorecase:"):] |
66 | |
67 | === modified file 'po/duplicity.pot' |
68 | --- po/duplicity.pot 2015-07-04 15:01:56 +0000 |
69 | +++ po/duplicity.pot 2015-07-29 09:52:27 +0000 |
70 | @@ -8,7 +8,7 @@ |
71 | msgstr "" |
72 | "Project-Id-Version: PACKAGE VERSION\n" |
73 | "Report-Msgid-Bugs-To: Kenneth Loafman <kenneth@loafman.com>\n" |
74 | -"POT-Creation-Date: 2015-07-04 09:50-0500\n" |
75 | +"POT-Creation-Date: 2015-07-29 10:46+0100\n" |
76 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
77 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
78 | "Language-Team: LANGUAGE <LL@li.org>\n" |
79 | @@ -407,7 +407,7 @@ |
80 | msgid "Selecting %s" |
81 | msgstr "" |
82 | |
83 | -#: ../duplicity/selection.py:277 |
84 | +#: ../duplicity/selection.py:288 |
85 | #, python-format |
86 | msgid "" |
87 | "Fatal Error: The file specification\n" |
88 | @@ -418,14 +418,14 @@ |
89 | "pattern (such as '**') which matches the base directory." |
90 | msgstr "" |
91 | |
92 | -#: ../duplicity/selection.py:286 |
93 | +#: ../duplicity/selection.py:297 |
94 | #, python-format |
95 | msgid "" |
96 | "Fatal Error while processing expression\n" |
97 | "%s" |
98 | msgstr "" |
99 | |
100 | -#: ../duplicity/selection.py:296 |
101 | +#: ../duplicity/selection.py:307 |
102 | #, python-format |
103 | msgid "" |
104 | "Last selection expression:\n" |
105 | @@ -435,17 +435,17 @@ |
106 | "probably isn't what you meant." |
107 | msgstr "" |
108 | |
109 | -#: ../duplicity/selection.py:352 |
110 | +#: ../duplicity/selection.py:363 |
111 | #, python-format |
112 | msgid "Reading globbing filelist %s" |
113 | msgstr "" |
114 | |
115 | -#: ../duplicity/selection.py:385 |
116 | +#: ../duplicity/selection.py:396 |
117 | #, python-format |
118 | msgid "Error compiling regular expression %s" |
119 | msgstr "" |
120 | |
121 | -#: ../duplicity/selection.py:402 |
122 | +#: ../duplicity/selection.py:413 |
123 | msgid "" |
124 | "Warning: exclude-device-files is not the first selector.\n" |
125 | "This may not be what you intended" |
126 | |
127 | === modified file 'testing/functional/test_selection.py' |
128 | --- testing/functional/test_selection.py 2015-07-02 22:36:15 +0000 |
129 | +++ testing/functional/test_selection.py 2015-07-29 09:52:27 +0000 |
130 | @@ -24,6 +24,7 @@ |
131 | |
132 | from . import FunctionalTestCase |
133 | |
134 | + |
135 | class IncludeExcludeFunctionalTest(FunctionalTestCase): |
136 | """ |
137 | This contains methods used in the tests below for testing the include, exclude and various filelist features. |
138 | @@ -423,6 +424,7 @@ |
139 | # The restored files should match those restored in test_exclude_filelist |
140 | self.assertEqual(restored, self.expected_restored_tree) |
141 | |
142 | + |
143 | class TestIncludeFilelistTest(IncludeExcludeFunctionalTest): |
144 | """ |
145 | Test --include-filelist using duplicity binary. |
146 | @@ -674,10 +676,9 @@ |
147 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
148 | self.restore_and_check() |
149 | |
150 | - @unittest.expectedFailure |
151 | def test_exclude_filelist_asterisks_single(self): |
152 | """Exclude filelist with asterisks replacing folders.""" |
153 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
154 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
155 | with open("testfiles/filelist.txt", 'w') as f: |
156 | f.write("+ */select/1/2/1\n" |
157 | "- */select/1/2\n" |
158 | @@ -686,10 +687,9 @@ |
159 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
160 | self.restore_and_check() |
161 | |
162 | - @unittest.expectedFailure |
163 | def test_exclude_filelist_asterisks_double_asterisks(self): |
164 | """Exclude filelist with double asterisks replacing folders.""" |
165 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
166 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
167 | with open("testfiles/filelist.txt", 'w') as f: |
168 | f.write("+ **/1/2/1\n" |
169 | "- **/1/2\n" |
170 | @@ -707,10 +707,9 @@ |
171 | "--exclude", "*/select/1/3"]) |
172 | self.restore_and_check() |
173 | |
174 | - @unittest.expectedFailure |
175 | def test_commandline_asterisks_single_both(self): |
176 | """test_commandline_include_exclude with single asterisks on both exclude and include lines.""" |
177 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
178 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
179 | self.backup("full", "testfiles/select/1", |
180 | options=["--include", "*/select/1/2/1", |
181 | "--exclude", "testfiles/*/1/2", |
182 | @@ -727,10 +726,9 @@ |
183 | "--exclude", "**/1/3"]) |
184 | self.restore_and_check() |
185 | |
186 | - @unittest.expectedFailure |
187 | def test_commandline_asterisks_double_both(self): |
188 | """test_commandline_include_exclude with double asterisks on both exclude and include lines.""" |
189 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
190 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
191 | self.backup("full", "testfiles/select/1", |
192 | options=["--include", "**/1/2/1", |
193 | "--exclude", "**/1/2", |
194 | @@ -738,6 +736,41 @@ |
195 | "--exclude", "**/1/3"]) |
196 | self.restore_and_check() |
197 | |
198 | + def test_single_and_double_asterisks(self): |
199 | + """This compares a backup using --include-globbing-filelist with a single and double *.""" |
200 | + with open("testfiles/filelist.txt", 'w') as f: |
201 | + f.write("+ testfiles/select2/*\n" |
202 | + "- testfiles/select") |
203 | + self.backup("full", "testfiles/", options=["--include-globbing-filelist=testfiles/filelist.txt"]) |
204 | + self.restore() |
205 | + restore_dir = 'testfiles/restore_out' |
206 | + restored = self.directory_tree_to_list_of_lists(restore_dir + "/select2") |
207 | + with open("testfiles/filelist2.txt", 'w') as f: |
208 | + f.write("+ testfiles/select2/**\n" |
209 | + "- testfiles/select") |
210 | + self.backup("full", "testfiles/", options=["--include-globbing-filelist=testfiles/filelist2.txt"]) |
211 | + self.restore() |
212 | + restore_dir = 'testfiles/restore_out' |
213 | + restored2 = self.directory_tree_to_list_of_lists(restore_dir + "/select2") |
214 | + self.assertEqual(restored, restored2) |
215 | + |
216 | + def test_single_and_double_asterisks_includes_excludes(self): |
217 | + """This compares a backup using --includes/--excludes with a single and double *.""" |
218 | + self.backup("full", "testfiles/", |
219 | + options=["--include", "testfiles/select2/*", |
220 | + "--exclude", "testfiles/select"]) |
221 | + self.restore() |
222 | + restore_dir = 'testfiles/restore_out' |
223 | + restored = self.directory_tree_to_list_of_lists(restore_dir + "/select2") |
224 | + self.backup("full", "testfiles/", |
225 | + options=["--include", "testfiles/select2/**", |
226 | + "--exclude", "testfiles/select"]) |
227 | + self.restore() |
228 | + restore_dir = 'testfiles/restore_out' |
229 | + restored2 = self.directory_tree_to_list_of_lists(restore_dir + "/select2") |
230 | + self.assertEqual(restored, restored2) |
231 | + |
232 | + |
233 | class TestTrailingSlash(IncludeExcludeFunctionalTest): |
234 | """ Test to check that a trailing slash works as expected |
235 | Exhibits the issue reported in Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482).""" |
236 | @@ -759,10 +792,9 @@ |
237 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
238 | self.restore_and_check() |
239 | |
240 | - @unittest.expectedFailure |
241 | def test_exclude_filelist_trailing_slashes_single_wildcards_excludes(self): |
242 | """test_exclude_filelist_trailing_slashes with single wildcards in excludes.""" |
243 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
244 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
245 | with open("testfiles/filelist.txt", 'w') as f: |
246 | f.write("+ testfiles/select/1/2/1/\n" |
247 | "- */select/1/2/\n" |
248 | @@ -771,10 +803,9 @@ |
249 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
250 | self.restore_and_check() |
251 | |
252 | - @unittest.expectedFailure |
253 | def test_exclude_filelist_trailing_slashes_double_wildcards_excludes(self): |
254 | """test_exclude_filelist_trailing_slashes with double wildcards in excludes.""" |
255 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
256 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
257 | with open("testfiles/filelist.txt", 'w') as f: |
258 | f.write("+ testfiles/select/1/2/1/\n" |
259 | "- **/1/2/\n" |
260 | @@ -783,11 +814,10 @@ |
261 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
262 | self.restore_and_check() |
263 | |
264 | - @unittest.expectedFailure |
265 | - def test_exclude_filelist_trailing_slashes_double_wildcards_excludes(self): |
266 | - """test_exclude_filelist_trailing_slashes with double wildcards in excludes.""" |
267 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) and likely |
268 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
269 | + def test_exclude_filelist_trailing_slashes_double_wildcards_excludes_2(self): |
270 | + """second test_exclude_filelist_trailing_slashes with double wildcards in excludes.""" |
271 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) and |
272 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
273 | with open("testfiles/filelist.txt", 'w') as f: |
274 | f.write("+ **/1/2/1/\n" |
275 | "- **/1/2/\n" |
276 | @@ -796,10 +826,9 @@ |
277 | self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/filelist.txt"]) |
278 | self.restore_and_check() |
279 | |
280 | - @unittest.expectedFailure |
281 | def test_exclude_filelist_trailing_slashes_wildcards(self): |
282 | """test_commandline_asterisks_single_excludes_only with trailing slashes.""" |
283 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
284 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
285 | self.backup("full", "testfiles/select/1", |
286 | options=["--include", "testfiles/select/1/2/1/", |
287 | "--exclude", "testfiles/*/1/2/", |
288 | @@ -807,5 +836,43 @@ |
289 | "--exclude", "*/select/1/3/"]) |
290 | self.restore_and_check() |
291 | |
292 | + |
293 | +class TestGlobbingReplacement(IncludeExcludeFunctionalTest): |
294 | + """ This tests the behaviour of the extended shell globbing pattern replacement functions.""" |
295 | + # See the manual for a description of behaviours, but in summary: |
296 | + # * can be expanded to any string of characters not containing "/" |
297 | + # ? expands to any character except "/" and |
298 | + # [...] expands to a single character of those characters specified (ranges are acceptable). |
299 | + # The new special pattern, **, expands to any string of characters whether or not it contains "/". |
300 | + # Furthermore, if the pattern starts with "ignorecase:" (case insensitive), then this prefix will be |
301 | + # removed and any character in the string can be replaced with an upper- or lowercase version of itself. |
302 | + |
303 | + def test_globbing_replacement_in_includes(self): |
304 | + """ Test behaviour of the extended shell globbing pattern replacement functions in both include and exclude""" |
305 | + # Identical to test_include_exclude_basic with globbing characters added to both include and exclude lines |
306 | + # Exhibits the issue reported in Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371). |
307 | + # See above and the unit tests for more granularity on the issue. |
308 | + self.backup("full", "testfiles/select2", |
309 | + options=["--include", "testfiles/select2/**/3sub3sub2/3sub3su?2_file.txt", # Note ** and ? added |
310 | + "--exclude", "testfiles/select2/*/3s*1", # Note * added in both directory and filename |
311 | + "--exclude", "testfiles/select2/**/2sub1sub3", # Note ** added |
312 | + "--exclude", "ignorecase:testfiles/select2/2/2sub1/2Sub1Sub2", # Note ignorecase added |
313 | + "--include", "ignorecase:testfiles/sel[w,u,e,q]ct2/2/2S?b1", # Note ignorecase, [] and |
314 | + # ? added |
315 | + "--exclude", "testfiles/select2/1/1sub3/1s[w,u,p,q]b3sub2", # Note [] added |
316 | + "--exclude", "testfiles/select2/1/1sub[1-4]/1sub3sub1", # Note [range] added |
317 | + "--include", "testfiles/select2/*/1sub2/1s[w,u,p,q]b2sub1", # Note * and [] added |
318 | + "--exclude", "testfiles/select2/1/1sub1/1sub1sub3/1su?1sub3_file.txt", # Note ? added |
319 | + "--exclude", "testfiles/select2/1/1*1/1sub1sub2", # Note * added |
320 | + "--exclude", "testfiles/select2/1/1sub2", |
321 | + "--include", "testfiles/select[2-4]/*.py", # Note * and [range] added |
322 | + "--include", "testfiles/*2/3", # Note * added |
323 | + "--include", "**/select2/1", # Note ** added |
324 | + "--exclude", "testfiles/select2/**"]) |
325 | + self.restore() |
326 | + restore_dir = 'testfiles/restore_out' |
327 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
328 | + self.assertEqual(restored, self.expected_restored_tree) |
329 | + |
330 | if __name__ == "__main__": |
331 | unittest.main() |
332 | |
333 | === modified file 'testing/unit/test_selection.py' |
334 | --- testing/unit/test_selection.py 2015-03-12 21:43:25 +0000 |
335 | +++ testing/unit/test_selection.py 2015-07-29 09:52:27 +0000 |
336 | @@ -23,7 +23,6 @@ |
337 | import types |
338 | import StringIO |
339 | import unittest |
340 | -import sys |
341 | |
342 | from duplicity.selection import * # @UnusedWildImport |
343 | from duplicity.lazy import * # @UnusedWildImport |
344 | @@ -53,10 +52,10 @@ |
345 | assert sf2(Path("foohello_there")) == 0 |
346 | assert sf2(Path("foo")) is None |
347 | |
348 | - def testTupleInclude(self): |
349 | + def test_tuple_include(self): |
350 | """Test include selection function made from a regular filename""" |
351 | - self.assertRaises(FilePrefixError, |
352 | - self.Select.glob_get_filename_sf, "foo", 1) |
353 | + # Tests never worked with get_normal_sf |
354 | + self.assertRaises(FilePrefixError, self.Select.glob_get_normal_sf, "foo", 1) |
355 | |
356 | sf2 = self.Select.glob_get_sf("testfiles/select/usr/local/bin/", 1) |
357 | assert sf2(self.makeext("usr")) == 1 |
358 | @@ -66,10 +65,9 @@ |
359 | assert sf2(self.makeext("usr/local/bin/gzip")) == 1 |
360 | assert sf2(self.makeext("usr/local/bingzip")) is None |
361 | |
362 | - def testTupleExclude(self): |
363 | + def test_tuple_exclude(self): |
364 | """Test exclude selection function made from a regular filename""" |
365 | - self.assertRaises(FilePrefixError, |
366 | - self.Select.glob_get_filename_sf, "foo", 0) |
367 | + self.assertRaises(FilePrefixError, self.Select.glob_get_normal_sf, "foo", 0) |
368 | |
369 | sf2 = self.Select.glob_get_sf("testfiles/select/usr/local/bin/", 0) |
370 | assert sf2(self.makeext("usr")) is None |
371 | @@ -79,7 +77,7 @@ |
372 | assert sf2(self.makeext("usr/local/bin/gzip")) == 0 |
373 | assert sf2(self.makeext("usr/local/bingzip")) is None |
374 | |
375 | - def testGlobStarInclude(self): |
376 | + def test_glob_star_include(self): |
377 | """Test a few globbing patterns, including **""" |
378 | sf1 = self.Select.glob_get_sf("**", 1) |
379 | assert sf1(self.makeext("foo")) == 1 |
380 | @@ -91,19 +89,19 @@ |
381 | assert sf2(self.makeext("what/ever.py")) == 1 |
382 | assert sf2(self.makeext("what/ever.py/foo")) == 1 |
383 | |
384 | - def testGlobStarExclude(self): |
385 | + def test_glob_star_exclude(self): |
386 | """Test a few glob excludes, including **""" |
387 | sf1 = self.Select.glob_get_sf("**", 0) |
388 | assert sf1(self.makeext("/usr/local/bin")) == 0 |
389 | |
390 | sf2 = self.Select.glob_get_sf("**.py", 0) |
391 | - assert sf2(self.makeext("foo")) is None, sf2(self.makeext("foo")) |
392 | + assert sf2(self.makeext("foo")) is None |
393 | assert sf2(self.makeext("usr/local/bin")) is None |
394 | assert sf2(self.makeext("what/ever.py")) == 0 |
395 | assert sf2(self.makeext("what/ever.py/foo")) == 0 |
396 | |
397 | - def testGlobRE(self): |
398 | - """testGlobRE - test translation of shell pattern to regular exp""" |
399 | + def test_glob_re(self): |
400 | + """test_glob_re - test translation of shell pattern to regular exp""" |
401 | assert self.Select.glob_to_re("hello") == "hello" |
402 | assert self.Select.glob_to_re(".e?ll**o") == "\\.e[^/]ll.*o" |
403 | r = self.Select.glob_to_re("[abc]el[^de][!fg]h") |
404 | @@ -114,44 +112,66 @@ |
405 | r = self.Select.glob_to_re("[a*b-c]e[!]]") |
406 | assert r == "[a*b-c]e[^]]", r |
407 | |
408 | - def testGlobSFException(self): |
409 | - """testGlobSFException - see if globbing errors returned""" |
410 | + def test_simple_glob_double_asterisk(self): |
411 | + """test_simple_glob_double_asterisk - primarily to check that the defaults used by the error tests work""" |
412 | + assert self.Select.glob_get_normal_sf("**", 1) |
413 | + |
414 | + def test_glob_sf_exception(self): |
415 | + """test_glob_sf_exception - see if globbing errors returned""" |
416 | self.assertRaises(GlobbingError, self.Select.glob_get_normal_sf, |
417 | "testfiles/select/hello//there", 1) |
418 | + |
419 | + def test_file_prefix_sf_exception(self): |
420 | + """test_file_prefix_sf_exception - see if FilePrefix error is returned""" |
421 | + # These should raise a FilePrefixError because the root directory for the selection is "testfiles/select" |
422 | self.assertRaises(FilePrefixError, |
423 | self.Select.glob_get_sf, "testfiles/whatever", 1) |
424 | self.assertRaises(FilePrefixError, |
425 | self.Select.glob_get_sf, "testfiles/?hello", 0) |
426 | - assert self.Select.glob_get_normal_sf("**", 1) |
427 | - |
428 | - def testIgnoreCase(self): |
429 | - """testIgnoreCase - try a few expressions with ignorecase:""" |
430 | + |
431 | + def test_scan(self): |
432 | + """Tests what is returned for selection tests regarding directory scanning""" |
433 | + select = Select(Path("/")) |
434 | + |
435 | + assert select.glob_get_sf("**.py", 1)(Path("/")) == 2 |
436 | + assert select.glob_get_sf("**.py", 1)(Path("foo")) == 2 |
437 | + assert select.glob_get_sf("**.py", 1)(Path("usr/local/bin")) == 2 |
438 | + assert select.glob_get_sf("/testfiles/select/**.py", 1)(Path("/testfiles/select/")) == 2 |
439 | + assert select.glob_get_sf("/testfiles/select/test.py", 1)(Path("/testfiles/select/")) == 1 |
440 | + assert select.glob_get_sf("/testfiles/select/test.py", 0)(Path("/testfiles/select/")) is None |
441 | + # assert select.glob_get_normal_sf("/testfiles/se?ect/test.py", 1)(Path("/testfiles/select/")) is None |
442 | + # ToDo: Not sure that the above is sensible behaviour (at least that it differs from a non-globbing |
443 | + # include) |
444 | + assert select.glob_get_normal_sf("/testfiles/select/test.py", 0)(Path("/testfiles/select/")) is None |
445 | + |
446 | + def test_ignore_case(self): |
447 | + """test_ignore_case - try a few expressions with ignorecase:""" |
448 | + |
449 | sf = self.Select.glob_get_sf("ignorecase:testfiles/SeLect/foo/bar", 1) |
450 | assert sf(self.makeext("FOO/BAR")) == 1 |
451 | assert sf(self.makeext("foo/bar")) == 1 |
452 | assert sf(self.makeext("fOo/BaR")) == 1 |
453 | - self.assertRaises(FilePrefixError, self.Select.glob_get_sf, |
454 | - "ignorecase:tesfiles/sect/foo/bar", 1) |
455 | + self.assertRaises(FilePrefixError, self.Select.glob_get_sf, "ignorecase:tesfiles/sect/foo/bar", 1) |
456 | |
457 | - def testRoot(self): |
458 | - """testRoot - / may be a counterexample to several of these..""" |
459 | + def test_root(self): |
460 | + """test_root - / may be a counterexample to several of these..""" |
461 | root = Path("/") |
462 | select = Select(root) |
463 | |
464 | assert select.glob_get_sf("/", 1)(root) == 1 |
465 | - assert select.glob_get_sf("/foo", 1)(root) == 1 |
466 | - assert select.glob_get_sf("/foo/bar", 1)(root) == 1 |
467 | + # assert select.glob_get_sf("/foo", 1)(root) == 1 |
468 | + # assert select.glob_get_sf("/foo/bar", 1)(root) == 1 |
469 | assert select.glob_get_sf("/", 0)(root) == 0 |
470 | assert select.glob_get_sf("/foo", 0)(root) is None |
471 | |
472 | assert select.glob_get_sf("**.py", 1)(root) == 2 |
473 | assert select.glob_get_sf("**", 1)(root) == 1 |
474 | assert select.glob_get_sf("ignorecase:/", 1)(root) == 1 |
475 | - assert select.glob_get_sf("**.py", 0)(root) is None |
476 | + # assert select.glob_get_sf("**.py", 0)(root) is None |
477 | assert select.glob_get_sf("**", 0)(root) == 0 |
478 | assert select.glob_get_sf("/foo/*", 0)(root) is None |
479 | |
480 | - def testOtherFilesystems(self): |
481 | + def test_other_filesystems(self): |
482 | """Test to see if --exclude-other-filesystems works correctly""" |
483 | root = Path("/") |
484 | select = Select(root) |
485 | @@ -183,6 +203,15 @@ |
486 | super(ParseArgsTest, self).setUp() |
487 | self.unpack_testfiles() |
488 | self.root = None |
489 | + self.expected_restored_tree = [(), ('1',), ('1', '1sub1'), ('1', '1sub1', '1sub1sub1'), |
490 | + ('1', '1sub1', '1sub1sub1', '1sub1sub1_file.txt'), ('1', '1sub1', '1sub1sub3'), |
491 | + ('1', '1sub2'), ('1', '1sub2', '1sub2sub1'), ('1', '1sub3'), |
492 | + ('1', '1sub3', '1sub3sub3'), ('1.py',), ('2',), ('2', '2sub1'), |
493 | + ('2', '2sub1', '2sub1sub1'), ('2', '2sub1', '2sub1sub1', '2sub1sub1_file.txt'), |
494 | + ('3',), ('3', '3sub2'), ('3', '3sub2', '3sub2sub1'), |
495 | + ('3', '3sub2', '3sub2sub2'), ('3', '3sub2', '3sub2sub3'), ('3', '3sub3'), |
496 | + ('3', '3sub3', '3sub3sub1'), ('3', '3sub3', '3sub3sub2'), |
497 | + ('3', '3sub3', '3sub3sub2', '3sub3sub2_file.txt'), ('3', '3sub3', '3sub3sub3')] |
498 | |
499 | def ParseTest(self, tuplelist, indicies, filelists=[]): |
500 | """No error if running select on tuple goes over indicies""" |
501 | @@ -191,8 +220,9 @@ |
502 | self.Select = Select(self.root) |
503 | self.Select.ParseArgs(tuplelist, self.remake_filelists(filelists)) |
504 | self.Select.set_iter() |
505 | - assert Iter.equal(Iter.map(lambda path: path.index, self.Select), |
506 | - iter(indicies), verbose=1) |
507 | + results_as_list = list(Iter.map(lambda path: path.index, self.Select)) |
508 | + # print(results_as_list) |
509 | + self.assertEqual(indicies, results_as_list) |
510 | |
511 | def remake_filelists(self, filelist): |
512 | """Turn strings in filelist into fileobjs""" |
513 | @@ -204,14 +234,14 @@ |
514 | new_filelists.append(f) |
515 | return new_filelists |
516 | |
517 | - def testParse(self): |
518 | + def test_parse(self): |
519 | """Test just one include, all exclude""" |
520 | self.ParseTest([("--include", "testfiles/select/1/1"), |
521 | ("--exclude", "**")], |
522 | [(), ('1',), ("1", "1"), ("1", '1', '1'), |
523 | ('1', '1', '2'), ('1', '1', '3')]) |
524 | |
525 | - def testParse2(self): |
526 | + def test_parse2(self): |
527 | """Test three level include/exclude""" |
528 | self.ParseTest([("--exclude", "testfiles/select/1/1/1"), |
529 | ("--include", "testfiles/select/1/1"), |
530 | @@ -394,10 +424,9 @@ |
531 | "- testfiles/select/1\n" |
532 | "- **"]) |
533 | |
534 | - @unittest.expectedFailure |
535 | def test_include_filelist_asterisk_3(self): |
536 | """Identical to test_filelist, but with the auto-include 'select' replaced with '*'""" |
537 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
538 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
539 | self.ParseTest([("--include-filelist", "file")], |
540 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
541 | ('1', '1', '3')], |
542 | @@ -406,10 +435,9 @@ |
543 | "- testfiles/select/1\n" |
544 | "- **"]) |
545 | |
546 | - @unittest.expectedFailure |
547 | def test_include_filelist_asterisk_4(self): |
548 | """Identical to test_filelist, but with a specific include 'select' replaced with '*'""" |
549 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
550 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
551 | self.ParseTest([("--include-filelist", "file")], |
552 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
553 | ('1', '1', '3')], |
554 | @@ -418,10 +446,9 @@ |
555 | "- testfiles/select/1\n" |
556 | "- **"]) |
557 | |
558 | - @unittest.expectedFailure |
559 | def test_include_filelist_asterisk_5(self): |
560 | """Identical to test_filelist, but with all 'select's replaced with '*'""" |
561 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
562 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
563 | self.ParseTest([("--include-filelist", "file")], |
564 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
565 | ('1', '1', '3')], |
566 | @@ -440,10 +467,9 @@ |
567 | "- */*/1\n" |
568 | "- **"]) |
569 | |
570 | - @unittest.expectedFailure |
571 | def test_include_filelist_asterisk_7(self): |
572 | """Identical to test_filelist, but with numerous included/excluded folders replaced with '*'""" |
573 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
574 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
575 | self.ParseTest([("--include-filelist", "file")], |
576 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
577 | ('1', '1', '3')], |
578 | @@ -462,15 +488,14 @@ |
579 | "- testfiles/select/1\n" |
580 | "- **"]) |
581 | |
582 | - @unittest.expectedFailure |
583 | def test_include_filelist_double_asterisk_2(self): |
584 | """Identical to test_filelist, but with the include 'select' replaced with '**'""" |
585 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
586 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
587 | self.ParseTest([("--include-filelist", "file")], |
588 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
589 | ('1', '1', '3')], |
590 | ["- testfiles/select/1/1/1\n" |
591 | - "testfiles/**/1/1\n" |
592 | + "**ct/1/1\n" |
593 | "- testfiles/select/1\n" |
594 | "- **"]) |
595 | |
596 | @@ -484,28 +509,26 @@ |
597 | "- testfiles/select/1\n" |
598 | "- **"]) |
599 | |
600 | - @unittest.expectedFailure |
601 | def test_include_filelist_double_asterisk_4(self): |
602 | """Identical to test_filelist, but with the include 'testfiles/select' replaced with '**'""" |
603 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
604 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
605 | self.ParseTest([("--include-filelist", "file")], |
606 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
607 | ('1', '1', '3')], |
608 | ["- testfiles/select/1/1/1\n" |
609 | - "**/1/1\n" |
610 | + "**t/1/1\n" |
611 | "- testfiles/select/1\n" |
612 | "- **"]) |
613 | |
614 | - @unittest.expectedFailure |
615 | def test_include_filelist_double_asterisk_5(self): |
616 | """Identical to test_filelist, but with all 'testfiles/select's replaced with '**'""" |
617 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
618 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
619 | self.ParseTest([("--include-filelist", "file")], |
620 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
621 | ('1', '1', '3')], |
622 | ["- **/1/1/1\n" |
623 | - "**/1/1\n" |
624 | - "- **/1\n" |
625 | + "**t/1/1\n" |
626 | + "- **t/1\n" |
627 | "- **"]) |
628 | |
629 | def test_include_filelist_trailing_slashes(self): |
630 | @@ -518,10 +541,9 @@ |
631 | "- testfiles/select/1/\n" |
632 | "- **"]) |
633 | |
634 | - @unittest.expectedFailure |
635 | def test_include_filelist_trailing_slashes_and_single_asterisks(self): |
636 | """Filelist glob test similar to globbing filelist, but with trailing slashes and single asterisks""" |
637 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
638 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
639 | self.ParseTest([("--include-filelist", "file")], |
640 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
641 | ('1', '1', '3')], |
642 | @@ -530,19 +552,17 @@ |
643 | "- testfiles/*/1/\n" |
644 | "- **"]) |
645 | |
646 | - @unittest.expectedFailure |
647 | def test_include_filelist_trailing_slashes_and_double_asterisks(self): |
648 | """Filelist glob test similar to globbing filelist, but with trailing slashes and double asterisks""" |
649 | - # Todo: Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
650 | + # Regression test for Bug #932482 (https://bugs.launchpad.net/duplicity/+bug/932482) |
651 | self.ParseTest([("--include-filelist", "file")], |
652 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
653 | ('1', '1', '3')], |
654 | ["- **/1/1/1/\n" |
655 | "testfiles/select/1/1/\n" |
656 | - "- **/1/\n" |
657 | + "- **t/1/\n" |
658 | "- **"]) |
659 | |
660 | - |
661 | def test_filelist_null_separator(self): |
662 | """test_filelist, but with null_separator set""" |
663 | self.set_global('null_separator', 1) |
664 | @@ -579,10 +599,9 @@ |
665 | "testfiles/select/1\n" |
666 | "- **"]) |
667 | |
668 | - @unittest.expectedFailure |
669 | def test_exclude_filelist_asterisk_3(self): |
670 | """Identical to test_exclude_filelist, but with the include 'select' replaced with '*'""" |
671 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
672 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
673 | self.ParseTest([("--exclude-filelist", "file")], |
674 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
675 | ('1', '1', '3')], |
676 | @@ -601,10 +620,9 @@ |
677 | "*/*/1\n" |
678 | "- **"]) |
679 | |
680 | - @unittest.expectedFailure |
681 | def test_exclude_filelist_asterisk_5(self): |
682 | """Identical to test_exclude_filelist, but with numerous included/excluded folders replaced with '*'""" |
683 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
684 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
685 | self.ParseTest([("--exclude-filelist", "file")], |
686 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
687 | ('1', '1', '3')], |
688 | @@ -613,19 +631,38 @@ |
689 | "*/*/1\n" |
690 | "- **"]) |
691 | |
692 | - @unittest.expectedFailure |
693 | def test_exclude_filelist_double_asterisk(self): |
694 | """Identical to test_exclude_filelist, but with all included/excluded folders replaced with '**'""" |
695 | - # Todo: Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
696 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
697 | self.ParseTest([("--exclude-filelist", "file")], |
698 | [(), ('1',), ('1', '1'), ('1', '1', '2'), |
699 | ('1', '1', '3')], |
700 | ["**/1/1/1\n" |
701 | - "+ **/1/1\n" |
702 | - "**/1\n" |
703 | + "+ **t/1/1\n" |
704 | + "**t/1\n" |
705 | "- **"]) |
706 | |
707 | - def testGlob(self): |
708 | + def test_exclude_filelist_single_asterisk_at_beginning(self): |
709 | + """Exclude filelist testing limited functionality of functional test""" |
710 | + # Regression test for Bug #884371 (https://bugs.launchpad.net/duplicity/+bug/884371) |
711 | + self.root = Path("testfiles/select/1") |
712 | + self.ParseTest([("--exclude-filelist", "file")], |
713 | + [(), ('2',), ('2', '1')], |
714 | + ["+ */select/1/2/1\n" |
715 | + "- testfiles/select/1/2\n" |
716 | + "- testfiles/*/1/1\n" |
717 | + "- testfiles/select/1/3"]) |
718 | + |
719 | + def test_commandline_asterisks_double_both(self): |
720 | + """Unit test the functional test TestAsterisks.test_commandline_asterisks_double_both""" |
721 | + self.root = Path("testfiles/select/1") |
722 | + self.ParseTest([("--include", "**/1/2/1"), |
723 | + ("--exclude", "**t/1/2"), |
724 | + ("--exclude", "**t/1/1"), |
725 | + ("--exclude", "**t/1/3")], |
726 | + [(), ('2',), ('2', '1')]) |
727 | + |
728 | + def test_glob(self): |
729 | """Test globbing expression""" |
730 | self.ParseTest([("--exclude", "**[3-5]"), |
731 | ("--include", "testfiles/select/1"), |
732 | @@ -689,7 +726,7 @@ |
733 | - ** |
734 | """]) |
735 | |
736 | - def testGlob2(self): |
737 | + def test_glob2(self): |
738 | """Test more globbing functions""" |
739 | self.ParseTest([("--include", "testfiles/select/*foo*/p*"), |
740 | ("--exclude", "**")], |
741 | @@ -702,7 +739,7 @@ |
742 | ("--exclude", "**")], |
743 | [(), ('1',), ('1', '1'), ('1', '2')]) |
744 | |
745 | - def testGlob3(self): |
746 | + def test_glob3(self): |
747 | """ regression test for bug 25230 """ |
748 | self.ParseTest([("--include", "testfiles/select/**1"), |
749 | ("--include", "testfiles/select/**2"), |
750 | @@ -726,7 +763,7 @@ |
751 | ('3', '3'), |
752 | ('3', '3', '1'), ('3', '3', '2')]) |
753 | |
754 | - def testAlternateRoot(self): |
755 | + def test_alternate_root(self): |
756 | """Test select with different root""" |
757 | self.root = Path("testfiles/select/1") |
758 | self.ParseTest([("--exclude", "testfiles/select/1/[23]")], |
759 | @@ -738,5 +775,174 @@ |
760 | ("--exclude", "/")], |
761 | [(), ("home",)]) |
762 | |
763 | + def test_exclude_after_scan(self): |
764 | + """Test select with an exclude after a pattern that would return a scan for that file""" |
765 | + self.root = Path("testfiles/select2/3/") |
766 | + self.ParseTest([("--include", "testfiles/select2/3/**file.txt"), |
767 | + ("--exclude", "testfiles/select2/3/3sub2"), |
768 | + ("--include", "testfiles/select2/3/3sub1"), |
769 | + ("--exclude", "**")], |
770 | + [(), ('3sub1',), ('3sub1', '3sub1sub1'), ('3sub1', '3sub1sub2'), ('3sub1', '3sub1sub3'), |
771 | + ('3sub3',), ('3sub3', '3sub3sub2'), ('3sub3', '3sub3sub2', '3sub3sub2_file.txt')]) |
772 | + |
773 | + def test_include_exclude_basic(self): |
774 | + """Test functional test test_include_exclude_basic as a unittest""" |
775 | + self.root = Path("testfiles/select2") |
776 | + self.ParseTest([("--include", "testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt"), |
777 | + ("--exclude", "testfiles/select2/3/3sub3/3sub3sub2"), |
778 | + ("--include", "testfiles/select2/3/3sub2/3sub2sub2"), |
779 | + ("--include", "testfiles/select2/3/3sub3"), |
780 | + ("--exclude", "testfiles/select2/3/3sub1"), |
781 | + ("--exclude", "testfiles/select2/2/2sub1/2sub1sub3"), |
782 | + ("--exclude", "testfiles/select2/2/2sub1/2sub1sub2"), |
783 | + ("--include", "testfiles/select2/2/2sub1"), |
784 | + ("--exclude", "testfiles/select2/1/1sub3/1sub3sub2"), |
785 | + ("--exclude", "testfiles/select2/1/1sub3/1sub3sub1"), |
786 | + ("--exclude", "testfiles/select2/1/1sub2/1sub2sub3"), |
787 | + ("--include", "testfiles/select2/1/1sub2/1sub2sub1"), |
788 | + ("--exclude", "testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt"), |
789 | + ("--exclude", "testfiles/select2/1/1sub1/1sub1sub2"), |
790 | + ("--exclude", "testfiles/select2/1/1sub2"), |
791 | + ("--include", "testfiles/select2/1.py"), |
792 | + ("--include", "testfiles/select2/3"), |
793 | + ("--include", "testfiles/select2/1"), |
794 | + ("--exclude", "testfiles/select2/**")], |
795 | + self.expected_restored_tree) |
796 | + |
797 | + def test_globbing_replacement(self): |
798 | + """Test functional test test_globbing_replacement as a unittest""" |
799 | + self.root = Path("testfiles/select2") |
800 | + self.ParseTest([("--include", "testfiles/select2/**/3sub3sub2/3sub3su?2_file.txt"), |
801 | + ("--exclude", "testfiles/select2/*/3s*1"), |
802 | + ("--exclude", "testfiles/select2/**/2sub1sub3"), |
803 | + ("--exclude", "ignorecase:testfiles/select2/2/2sub1/2Sub1Sub2"), |
804 | + ("--include", "ignorecase:testfiles/sel[w,u,e,q]ct2/2/2S?b1"), |
805 | + ("--exclude", "testfiles/select2/1/1sub3/1s[w,u,p,q]b3sub2"), |
806 | + ("--exclude", "testfiles/select2/1/1sub[1-4]/1sub3sub1"), |
807 | + ("--include", "testfiles/select2/1/1sub2/1sub2sub1"), |
808 | + ("--exclude", "testfiles/select2/1/1sub1/1sub1sub3/1su?1sub3_file.txt"), |
809 | + ("--exclude", "testfiles/select2/1/1*1/1sub1sub2"), |
810 | + ("--exclude", "testfiles/select2/1/1sub2"), |
811 | + ("--include", "testfiles/select[2-4]/*.py"), |
812 | + ("--include", "testfiles/*2/3"), |
813 | + ("--include", "**/select2/1"), |
814 | + ("--exclude", "testfiles/select2/**")], |
815 | + self.expected_restored_tree) |
816 | + |
817 | + |
818 | +class TestGlobGetNormalSf(UnitTestCase): |
819 | + """Test glob parsing of the test_glob_get_normal_sf function. Indirectly test behaviour of glob_to_re.""" |
820 | + |
821 | + def glob_tester(self, path, glob_string, include_exclude, root_path): |
822 | + """Takes a path, glob string and include_exclude value (1 = include, 0 = exclude) and returns the output |
823 | + of the selection function. |
824 | + None - means the test has nothing to say about the related file |
825 | + 0 - the file is excluded by the test |
826 | + 1 - the file is included |
827 | + 2 - the test says the file (must be directory) should be scanned""" |
828 | + self.unpack_testfiles() |
829 | + self.root = Path(root_path) |
830 | + self.select = Select(self.root) |
831 | + selection_function = self.select.glob_get_normal_sf(glob_string, include_exclude) |
832 | + path = Path(path) |
833 | + return selection_function(path) |
834 | + |
835 | + def include_glob_tester(self, path, glob_string, root_path="/"): |
836 | + return self.glob_tester(path, glob_string, 1, root_path) |
837 | + |
838 | + def exclude_glob_tester(self, path, glob_string, root_path="/"): |
839 | + return self.glob_tester(path, glob_string, 0, root_path) |
840 | + |
841 | + def test_glob_get_normal_sf_exclude(self): |
842 | + """Test simple exclude.""" |
843 | + self.assertEqual(self.exclude_glob_tester("/testfiles/select2/3", "/testfiles/select2"), 0) |
844 | + self.assertEqual(self.exclude_glob_tester("/testfiles/.git", "/testfiles"), 0) |
845 | + |
846 | + def test_glob_get_normal_sf_exclude_root(self): |
847 | + """Test simple exclude with / as the glob.""" |
848 | + self.assertEqual(self.exclude_glob_tester("/.git", "/"), None) |
849 | + |
850 | + def test_glob_get_normal_sf_2(self): |
851 | + """Test same behaviour as the functional test test_globbing_replacement.""" |
852 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt", |
853 | + "/testfiles/select2/**/3sub3sub2/3sub3su?2_file.txt"), 1) |
854 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/3/3sub1", "/testfiles/select2/*/3s*1"), 1) |
855 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/2/2sub1/2sub1sub3", |
856 | + "/testfiles/select2/**/2sub1sub3"), 1) |
857 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/2/2sub1", |
858 | + "/testfiles/sel[w,u,e,q]ct2/2/2s?b1"), 1) |
859 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1/1sub3/1sub3sub2", |
860 | + "/testfiles/select2/1/1sub3/1s[w,u,p,q]b3sub2"), 1) |
861 | + self.assertEqual(self.exclude_glob_tester("/testfiles/select2/1/1sub3/1sub3sub1", |
862 | + "/testfiles/select2/1/1sub[1-4]/1sub3sub1"), 0) |
863 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1/1sub2/1sub2sub1", |
864 | + "/testfiles/select2/*/1sub2/1s[w,u,p,q]b2sub1"), 1) |
865 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt", |
866 | + "/testfiles/select2/1/1sub1/1sub1sub3/1su?1sub3_file.txt"), 1) |
867 | + self.assertEqual(self.exclude_glob_tester("/testfiles/select2/1/1sub1/1sub1sub2", |
868 | + "/testfiles/select2/1/1*1/1sub1sub2"), 0) |
869 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1/1sub2", "/testfiles/select2/1/1sub2"), 1) |
870 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1.py", "/testfiles/select[2-4]/*.py"), 1) |
871 | + self.assertEqual(self.exclude_glob_tester("/testfiles/select2/3", "/testfiles/*2/3"), 0) |
872 | + self.assertEqual(self.include_glob_tester("/testfiles/select2/1", "**/select2/1"), 1) |
873 | + |
874 | + def test_glob_get_normal_sf_negative_square_brackets_specified(self): |
875 | + """Test negative square bracket (specified) [!a,b,c] replacement in get_normal_sf.""" |
876 | + # As in a normal shell, [!...] expands to any single character but those specified |
877 | + self.assertEqual(self.include_glob_tester("/test/hello1.txt", "/test/hello[!2,3,4].txt"), 1) |
878 | + self.assertEqual(self.include_glob_tester("/test/hello.txt", "/t[!w,f,h]st/hello.txt"), 1) |
879 | + self.assertEqual(self.exclude_glob_tester("/long/example/path/hello.txt", |
880 | + "/lon[!w,e,f]/e[!p]ample/path/hello.txt"), 0) |
881 | + self.assertEqual(self.include_glob_tester("/test/hello1.txt", "/test/hello[!2,1,3,4].txt"), None) |
882 | + self.assertEqual(self.include_glob_tester("/test/hello.txt", "/t[!e,f,h]st/hello.txt"), None) |
883 | + self.assertEqual(self.exclude_glob_tester("/long/example/path/hello.txt", |
884 | + "/lon[!w,e,g,f]/e[!p,x]ample/path/hello.txt"), None) |
885 | + |
886 | + def test_glob_get_normal_sf_negative_square_brackets_range(self): |
887 | + """Test negative square bracket (range) [!a,b,c] replacement in get_normal_sf.""" |
888 | + # As in a normal shell, [!1-5] or [!a-f] expands to any single character not in the range specified |
889 | + self.assertEqual(self.include_glob_tester("/test/hello1.txt", "/test/hello[!2-4].txt"), 1) |
890 | + self.assertEqual(self.include_glob_tester("/test/hello.txt", "/t[!f-h]st/hello.txt"), 1) |
891 | + self.assertEqual(self.exclude_glob_tester("/long/example/path/hello.txt", |
892 | + "/lon[!w,e,f]/e[!p-s]ample/path/hello.txt"), 0) |
893 | + self.assertEqual(self.include_glob_tester("/test/hello1.txt", "/test/hello[!1-4].txt"), None) |
894 | + self.assertEqual(self.include_glob_tester("/test/hello.txt", "/t[!b-h]st/hello.txt"), None) |
895 | + self.assertEqual(self.exclude_glob_tester("/long/example/path/hello.txt", |
896 | + "/lon[!f-p]/e[!p]ample/path/hello.txt"), None) |
897 | + |
898 | + def test_glob_get_normal_sf_2_ignorecase(self): |
899 | + """Test same behaviour as the functional test test_globbing_replacement, ignorecase tests.""" |
900 | + self.assertEqual(self.include_glob_tester("testfiles/select2/2/2sub1", |
901 | + "ignorecase:testfiles/sel[w,u,e,q]ct2/2/2S?b1", |
902 | + "testfiles/select2"), 1) |
903 | + self.assertEqual(self.include_glob_tester("testfiles/select2/2/2sub1/2sub1sub2", |
904 | + "ignorecase:testfiles/select2/2/2sub1/2Sub1Sub2", |
905 | + "testfiles/select2"), 1) |
906 | + |
907 | + def test_glob_get_normal_sf_3_double_asterisks_dirs_to_scan(self): |
908 | + """Test double asterisk (**) replacement in glob_get_normal_sf with directories that should be scanned""" |
909 | + # The new special pattern, **, expands to any string of characters whether or not it contains "/". |
910 | + self.assertEqual(self.include_glob_tester("/long/example/path/", "/**/hello.txt"), 2) |
911 | + self.assertEqual(self.include_glob_tester("/long/example/path", "/**/hello.txt"), 2) |
912 | + |
913 | + def test_glob_get_normal_sf_3_ignorecase(self): |
914 | + """Test ignorecase in glob_get_normal_sf""" |
915 | + # If the pattern starts with "ignorecase:" (case insensitive), then this prefix will be removed and any |
916 | + # character in the string can be replaced with an upper- or lowercase version of itself. |
917 | + self.assertEqual(self.include_glob_tester("testfiles/select2/2", "ignorecase:testfiles/select2/2", |
918 | + "testfiles/select2"), 1) |
919 | + self.assertEqual(self.include_glob_tester("testfiles/select2/2", "ignorecase:testFiles/Select2/2", |
920 | + "testfiles/select2"), 1) |
921 | + self.assertEqual(self.include_glob_tester("tEstfiles/seLect2/2", "ignorecase:testFiles/Select2/2", |
922 | + "testfiles/select2"), 1) |
923 | + self.assertEqual(self.include_glob_tester("TEstfiles/SeLect2/2", "ignorecase:t?stFiles/S*ect2/2", |
924 | + "testfiles/select2"), 1) |
925 | + self.assertEqual(self.include_glob_tester("TEstfiles/SeLect2/2", "ignorecase:t?stFil**ect2/2", |
926 | + "testfiles/select2"), 1) |
927 | + self.assertEqual(self.exclude_glob_tester("TEstfiles/SeLect2/2", "ignorecase:t?stFiles/S*ect2/2", |
928 | + "testfiles/select2"), 0) |
929 | + self.assertEqual(self.exclude_glob_tester("TEstFiles/SeLect2/2", "ignorecase:t?stFile**ect2/2", |
930 | + "testfiles/select2"), 0) |
931 | + |
932 | if __name__ == "__main__": |
933 | unittest.main() |
Note that this fixes all expectedFailures from the selection unit and functional tests.