Merge lp:~aaron-whitehouse/duplicity/Bug_1624725_files_within_folder_slash into lp:~duplicity-team/duplicity/0.7-series
- Bug_1624725_files_within_folder_slash
- Merge into 0.7-series
Status: | Merged |
---|---|
Merged at revision: | 1257 |
Proposed branch: | lp:~aaron-whitehouse/duplicity/Bug_1624725_files_within_folder_slash |
Merge into: | lp:~duplicity-team/duplicity/0.7-series |
Diff against target: |
481 lines (+365/-15) 5 files modified
duplicity/globmatch.py (+37/-8) duplicity/selection.py (+7/-2) testing/functional/test_selection.py (+76/-1) testing/unit/test_globmatch.py (+215/-2) testing/unit/test_selection.py (+30/-2) |
To merge this branch: | bzr merge lp:~aaron-whitehouse/duplicity/Bug_1624725_files_within_folder_slash |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
duplicity-team | Pending | ||
Review via email: mp+311357@code.launchpad.net |
Commit message
Fixed Bug #1624725, so that an include glob ending in "/" now includes folder contents (for globs with and without special characters). This preserves the behaviour that an expression ending in "/" only matches a folder, but now the contents of any matching folder is included.
Description of the change
Fixed Bug #1624725, so that an include glob ending in "/" now includes folder contents (for globs with and without special characters). This preserves the behaviour that an expression ending in "/" only matches a folder, but now the contents of any matching folder is included.
Note that this is to be merged into 0.7-series, as this fixes a regression in recent 0.7 releases. The change (likely along with all other changes that have been made in 0.7 recently) could then be merged into 0.8. Once merged into the 0.8 series, I plan to converge the functions dealing with expressions the do and don't have globbing characters so that we only have one code base to check/maintain.
Aaron Whitehouse (aaron-whitehouse) wrote : | # |
Kenneth Loafman (kenneth-loafman) wrote : | # |
Sorry, this got lost in my spam folder. Not good. Will get it done.
Kenneth Loafman (kenneth-loafman) wrote : | # |
BTW, the diff from the merge worked on series-8 as well.
Preview Diff
1 | === modified file 'duplicity/globmatch.py' |
2 | --- duplicity/globmatch.py 2016-08-12 20:50:29 +0000 |
3 | +++ duplicity/globmatch.py 2016-11-20 22:26:00 +0000 |
4 | @@ -60,11 +60,10 @@ |
5 | 2 - if the folder should be scanned for any included/excluded files |
6 | None - if the selection function has nothing to say about the file |
7 | """ |
8 | - match_only_dirs = False |
9 | + glob_ends_w_slash = False |
10 | |
11 | - # ToDo: Test behaviour of "/" on its own - should always match |
12 | if glob_str != "/" and glob_str[-1] == "/": |
13 | - match_only_dirs = True |
14 | + glob_ends_w_slash = True |
15 | # Remove trailing / from directory name (unless that is the entire |
16 | # string) |
17 | glob_str = glob_str[:-1] |
18 | @@ -76,21 +75,51 @@ |
19 | re_comp = lambda r: re.compile(r, re.S | flags) |
20 | |
21 | # matches what glob matches and any files in directory |
22 | + # Resulting regular expression is: |
23 | + # ^ string must be at the beginning of path |
24 | + # string translated into regex |
25 | + # ($|/) nothing must follow except for the end of the string, newline or / |
26 | + # Note that the "/" at the end of the regex means that it will match |
27 | + # if the glob matches a parent folders of path |
28 | glob_comp_re = re_comp("^%s($|/)" % glob_to_regex(glob_str)) |
29 | |
30 | + if glob_ends_w_slash: |
31 | + # Creates a version of glob_comp_re that does not match folder contents |
32 | + # This can be used later to check that an exact match is actually a |
33 | + # folder, rather than a file. |
34 | + glob_comp_re_exact = re_comp("^%s($)" % glob_to_regex(glob_str)) |
35 | + |
36 | if glob_str.find("**") != -1: |
37 | + # glob_str has a ** in it |
38 | glob_str = glob_str[:glob_str.find("**") + 2] # truncate after ** |
39 | |
40 | + # Below regex is translates to: |
41 | + # ^ string must be at the beginning of path |
42 | + # the regexs corresponding to the parent directories of glob_str |
43 | + # $ nothing must follow except for the end of the string or newline |
44 | scan_comp_re = re_comp("^(%s)$" % |
45 | "|".join(_glob_get_prefix_regexs(glob_str))) |
46 | |
47 | def test_fn(path): |
48 | + if glob_comp_re.match(path.name): |
49 | + # Path matches glob, or is contained within a matching folder |
50 | + if not glob_ends_w_slash: |
51 | + return include |
52 | + else: |
53 | + # Glob ended with a /, so we need to check any exact match was |
54 | + # a folder |
55 | + if glob_comp_re_exact.match(path.name): |
56 | + # Not an included file/folder, so must be a folder to match |
57 | + if path.isdir(): |
58 | + # Is a directory, so all is well |
59 | + return include |
60 | + else: |
61 | + # Exact match and not a folder |
62 | + return None |
63 | + else: |
64 | + # An included file/folder, so normal approach is fine |
65 | + return include |
66 | |
67 | - if match_only_dirs and not path.isdir(): |
68 | - # If the glob ended with a /, only match directories |
69 | - return None |
70 | - elif glob_comp_re.match(path.name): |
71 | - return include |
72 | elif include == 1 and scan_comp_re.match(path.name): |
73 | return 2 |
74 | else: |
75 | |
76 | === modified file 'duplicity/selection.py' |
77 | --- duplicity/selection.py 2016-09-04 22:25:37 +0000 |
78 | +++ duplicity/selection.py 2016-11-20 22:26:00 +0000 |
79 | @@ -487,6 +487,9 @@ |
80 | |
81 | """ |
82 | # Internal. Used by glob_get_sf and unit tests. |
83 | + # ToDo: Make all globbing/non-globbing use same code path |
84 | + # This distinction has bitten us too many times with bugs in one or |
85 | + # the other. |
86 | match_only_dirs = False |
87 | |
88 | if filename != "/" and filename[-1] == "/": |
89 | @@ -506,8 +509,10 @@ |
90 | # Internal. Used by glob_get_filename_sf. |
91 | |
92 | def include_sel_func(path): |
93 | - if match_only_dirs and not path.isdir(): |
94 | - # If the glob ended with a /, only match directories |
95 | + if len(tuple) == len(path.index) and match_only_dirs and not path.isdir(): |
96 | + # If we are assessing the actual directory (rather than the |
97 | + # contents of the directory) and the glob ended with a /, |
98 | + # only match directories |
99 | return None |
100 | elif (path.index == tuple[:len(path.index)] or |
101 | path.index[:len(tuple)] == tuple): |
102 | |
103 | === modified file 'testing/functional/test_selection.py' |
104 | --- testing/functional/test_selection.py 2016-09-04 22:25:37 +0000 |
105 | +++ testing/functional/test_selection.py 2016-11-20 22:26:00 +0000 |
106 | @@ -19,7 +19,6 @@ |
107 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
108 | |
109 | import os |
110 | -import os.path |
111 | import unittest |
112 | |
113 | from . import FunctionalTestCase |
114 | @@ -1006,5 +1005,81 @@ |
115 | ['1sub1sub1_file.txt']]) |
116 | |
117 | |
118 | +class TestFolderIncludesFiles(IncludeExcludeFunctionalTest): |
119 | + """ This tests that including a folder includes the files within it""" |
120 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
121 | + |
122 | + def test_includes_files(self): |
123 | + """This tests that including a folder includes the files within it""" |
124 | + self.backup("full", "testfiles/select2/1/1sub1", |
125 | + options=["--include", "testfiles/select2/1/1sub1/1sub1sub1", |
126 | + "--exclude", "**"]) |
127 | + self.restore() |
128 | + restore_dir = 'testfiles/restore_out' |
129 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
130 | + self.assertEqual(restored, [['1sub1sub1'], |
131 | + ['1sub1sub1_file.txt']]) |
132 | + |
133 | + def test_includes_files_trailing_slash(self): |
134 | + """This tests that including a folder includes the files within it""" |
135 | + self.backup("full", "testfiles/select2/1/1sub1", |
136 | + options=["--include", "testfiles/select2/1/1sub1/1sub1sub1/", |
137 | + "--exclude", "**"]) |
138 | + self.restore() |
139 | + restore_dir = 'testfiles/restore_out' |
140 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
141 | + self.assertEqual(restored, [['1sub1sub1'], |
142 | + ['1sub1sub1_file.txt']]) |
143 | + |
144 | + def test_includes_files_trailing_slash_globbing_chars(self): |
145 | + """Tests folder includes with globbing char and /""" |
146 | + self.backup("full", "testfiles/select2/1/1sub1", |
147 | + options=["--include", "testfiles/s?lect2/1/1sub1/1sub1sub1/", |
148 | + "--exclude", "**"]) |
149 | + self.restore() |
150 | + restore_dir = 'testfiles/restore_out' |
151 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
152 | + self.assertEqual(restored, [['1sub1sub1'], |
153 | + ['1sub1sub1_file.txt']]) |
154 | + |
155 | + def test_excludes_files_no_trailing_slash(self): |
156 | + """This tests that excluding a folder excludes the files within it""" |
157 | + self.backup("full", "testfiles/select2/1/1sub1", |
158 | + options=["--exclude", "testfiles/select2/1/1sub1/1sub1sub1", |
159 | + "--exclude", "testfiles/select2/1/1sub1/1sub1sub2", |
160 | + "--exclude", "testfiles/select2/1/1sub1/1sub1sub3", |
161 | + "--include", "testfiles/select2/1/1sub1/1sub1**", |
162 | + "--exclude", "testfiles/select2/1/1sub1/irrelevant.txt"]) |
163 | + self.restore() |
164 | + restore_dir = 'testfiles/restore_out' |
165 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
166 | + self.assertEqual(restored, []) |
167 | + |
168 | + def test_excludes_files_trailing_slash(self): |
169 | + """Excluding a folder excludes the files within it, if ends with /""" |
170 | + self.backup("full", "testfiles/select2/1/1sub1", |
171 | + options=["--exclude", "testfiles/select2/1/1sub1/1sub1sub1/", |
172 | + "--exclude", "testfiles/select2/1/1sub1/1sub1sub2/", |
173 | + "--exclude", "testfiles/select2/1/1sub1/1sub1sub3/", |
174 | + "--include", "testfiles/select2/1/1sub1/1sub1**", |
175 | + "--exclude", "testfiles/select2/1/1sub1/irrelevant.txt"]) |
176 | + self.restore() |
177 | + restore_dir = 'testfiles/restore_out' |
178 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
179 | + self.assertEqual(restored, []) |
180 | + |
181 | + def test_excludes_files_trailing_slash_globbing_chars(self): |
182 | + """Tests folder excludes with globbing char and /""" |
183 | + self.backup("full", "testfiles/select2/1/1sub1", |
184 | + options=["--exclude", "testfiles/sel?ct2/1/1sub1/1sub1sub1/", |
185 | + "--exclude", "testfiles/sel[e,f]ct2/1/1sub1/1sub1sub2/", |
186 | + "--exclude", "testfiles/sel*t2/1/1sub1/1sub1sub3/", |
187 | + "--include", "testfiles/select2/1/1sub1/1sub1**", |
188 | + "--exclude", "testfiles/select2/1/1sub1/irrelevant.txt"]) |
189 | + self.restore() |
190 | + restore_dir = 'testfiles/restore_out' |
191 | + restored = self.directory_tree_to_list_of_lists(restore_dir) |
192 | + self.assertEqual(restored, []) |
193 | + |
194 | if __name__ == "__main__": |
195 | unittest.main() |
196 | |
197 | === modified file 'testing/unit/test_globmatch.py' |
198 | --- testing/unit/test_globmatch.py 2016-03-05 10:47:02 +0000 |
199 | +++ testing/unit/test_globmatch.py 2016-11-20 22:26:00 +0000 |
200 | @@ -20,9 +20,12 @@ |
201 | # along with duplicity; if not, write to the Free Software Foundation, |
202 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
203 | |
204 | -import unittest |
205 | +import sys |
206 | from duplicity.globmatch import * |
207 | +from duplicity.path import * |
208 | from . import UnitTestCase |
209 | +from mock import patch |
210 | +import unittest |
211 | |
212 | |
213 | class MatchingTest(UnitTestCase): |
214 | @@ -38,4 +41,214 @@ |
215 | assert r == "\\/usr\\/[^/]*\\/bin\\/", r |
216 | assert glob_to_regex("[a.b/c]") == "[a.b/c]" |
217 | r = glob_to_regex("[a*b-c]e[!]]") |
218 | - assert r == "[a*b-c]e[^]]", r |
219 | \ No newline at end of file |
220 | + assert r == "[a*b-c]e[^]]", r |
221 | + |
222 | + |
223 | +class TestDoubleAsteriskOnIncludesExcludes(UnitTestCase): |
224 | + """Test ** on includes and exclude patterns""" |
225 | + |
226 | + def test_double_asterisk_include(self): |
227 | + """Test a few globbing patterns, including **""" |
228 | + self.assertEqual( |
229 | + path_matches_glob_fn("**", 1)(Path("foo.txt")), 1) |
230 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
231 | + mock_isdir.return_value = True |
232 | + self.assertEqual( |
233 | + path_matches_glob_fn("**", 1)(Path("folder")), 1) |
234 | + |
235 | + def test_double_asterisk_extension_include(self): |
236 | + """Test **.py""" |
237 | + self.assertEqual( |
238 | + path_matches_glob_fn("**.py", 1)(Path("what/ever.py")), 1) |
239 | + self.assertEqual( |
240 | + path_matches_glob_fn("**.py", 1)(Path("what/ever.py/foo")), 1) |
241 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
242 | + mock_isdir.return_value = True |
243 | + self.assertEqual( |
244 | + path_matches_glob_fn("**.py", 1)(Path("foo")), 2) |
245 | + self.assertEqual( |
246 | + path_matches_glob_fn("**.py", 1)(Path("usr/local/bin")), 2) |
247 | + self.assertEqual( |
248 | + path_matches_glob_fn("**.py", 1)(Path("/usr/local/bin")), 2) |
249 | + |
250 | + |
251 | +class TestTrailingSlash(UnitTestCase): |
252 | + """Test glob matching where the glob has a trailing slash""" |
253 | + |
254 | + def test_trailing_slash_matches_only_dirs(self): |
255 | + """Test matching where glob includes a trailing slash""" |
256 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
257 | + mock_isdir.return_value = True |
258 | + self.assertEqual( |
259 | + path_matches_glob_fn("fold*/", 1)(Path("folder")), 1) |
260 | + |
261 | + # Test the file named "folder" is not included if it is not a dir |
262 | + mock_isdir.return_value = False |
263 | + self.assertEqual( |
264 | + path_matches_glob_fn("fold*/", 1)(Path("folder")), None) |
265 | + |
266 | + # Test the file named "folder" is not included if it is not a dir |
267 | + mock_isdir.return_value = False |
268 | + self.assertEqual( |
269 | + path_matches_glob_fn("folder/", 1)(Path("folder")), None) |
270 | + |
271 | + mock_isdir.return_value = False |
272 | + self.assertEqual( |
273 | + path_matches_glob_fn("fo*/", 1)(Path("foo.txt")), None) |
274 | + |
275 | + def test_included_files_are_matched_no_slash(self): |
276 | + """Test that files within an included folder are matched""" |
277 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
278 | + mock_isdir.return_value = False |
279 | + self.assertEqual( |
280 | + path_matches_glob_fn("fold*", 1)(Path("folder/file.txt")), 1) |
281 | + |
282 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
283 | + mock_isdir.return_value = False |
284 | + self.assertEqual( |
285 | + path_matches_glob_fn("fold*", 1)(Path("folder/2/file.txt")), 1) |
286 | + |
287 | + def test_included_files_are_matched_no_slash_2(self): |
288 | + """Test that files within an included folder are matched""" |
289 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
290 | + mock_isdir.return_value = False |
291 | + self.assertEqual( |
292 | + path_matches_glob_fn("folder", 1)(Path("folder/file.txt")), 1) |
293 | + |
294 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
295 | + mock_isdir.return_value = False |
296 | + self.assertEqual( |
297 | + path_matches_glob_fn("folder/2", 1)(Path("folder/2/file.txt")), 1) |
298 | + |
299 | + def test_included_files_are_matched_slash(self): |
300 | + """Test that files within an included folder are matched with /""" |
301 | + # Bug #1624725 |
302 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
303 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
304 | + mock_isdir.return_value = False |
305 | + self.assertEqual( |
306 | + path_matches_glob_fn("folder/", 1)(Path("folder/file.txt")), 1) |
307 | + |
308 | + def test_included_files_are_matched_slash_2(self): |
309 | + """Test that files within an included folder are matched with /""" |
310 | + # Bug #1624725 |
311 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
312 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
313 | + mock_isdir.return_value = False |
314 | + self.assertEqual( |
315 | + path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1) |
316 | + (Path("testfiles/select2/1/1sub1/1sub1sub1/1sub1sub1_file.txt") |
317 | + ), 1) |
318 | + |
319 | + def test_included_files_are_matched_slash_2_parents(self): |
320 | + """Test that duplicity will scan parent of glob/""" |
321 | + # Bug #1624725 |
322 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
323 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
324 | + mock_isdir.return_value = True |
325 | + self.assertEqual( |
326 | + path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1) |
327 | + (Path("testfiles/select2/1/1sub1/1sub1sub1") |
328 | + ), 1) |
329 | + self.assertEqual( |
330 | + path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1) |
331 | + (Path("testfiles/select2/1/1sub1") |
332 | + ), 2) |
333 | + |
334 | + def test_included_files_are_matched_slash_wildcard(self): |
335 | + """Test that files within an included folder are matched with /""" |
336 | + # Bug #1624725 |
337 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
338 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
339 | + mock_isdir.return_value = False |
340 | + self.assertEqual( |
341 | + path_matches_glob_fn("fold*/", 1)(Path("folder/file.txt")), 1) |
342 | + # |
343 | + # def test_slash_matches_everything(self): |
344 | + # """Test / matches everything""" |
345 | + # # ToDo: Not relevant at this stage, as "/" would not go through |
346 | + # # globmatch because it has no special characters, but it should be |
347 | + # # made to work |
348 | + # with patch('duplicity.path.Path.isdir') as mock_isdir: |
349 | + # mock_isdir.return_value = True |
350 | + # self.assertEqual( |
351 | + # path_matches_glob_fn("/", |
352 | + # 1)(Path("/tmp/testfiles/select/1/2")), 1) |
353 | + # self.assertEqual( |
354 | + # path_matches_glob_fn("/", |
355 | + # 1)(Path("/test/random/path")), 1) |
356 | + # self.assertEqual( |
357 | + # path_matches_glob_fn("/", |
358 | + # 1)(Path("/")), 1) |
359 | + # self.assertEqual( |
360 | + # path_matches_glob_fn("/", |
361 | + # 1)(Path("/var/log")), 1) |
362 | + # self.assertEqual( |
363 | + # path_matches_glob_fn("/", |
364 | + # 1)(Path("/var/log/log.txt")), 1) |
365 | + |
366 | + def test_slash_star_scans_folder(self): |
367 | + """Test that folder/* scans folder/""" |
368 | + # This behaviour is a bit ambiguous - either include or scan could be |
369 | + # argued as most appropriate here, but only an empty folder is at stake |
370 | + # so long as test_slash_star_includes_folder_contents passes. |
371 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
372 | + mock_isdir.return_value = True |
373 | + self.assertEqual( |
374 | + path_matches_glob_fn("folder/*", 1)(Path("folder")), 2) |
375 | + |
376 | + def test_slash_star_includes_folder_contents(self): |
377 | + """Test that folder/* includes folder contents""" |
378 | + self.assertEqual(path_matches_glob_fn("folder/*", 1) |
379 | + (Path("folder/file.txt")), 1) |
380 | + self.assertEqual(path_matches_glob_fn("folder/*", 1) |
381 | + (Path("folder/other_file.log")), 1) |
382 | + |
383 | + def test_slash_star_star_includes_folder(self): |
384 | + """Test that folder/** includes folder/""" |
385 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
386 | + mock_isdir.return_value = True |
387 | + |
388 | + def test_simple_trailing_slash_match(self): |
389 | + """Test that a normal folder string ending in / matches that path""" |
390 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
391 | + mock_isdir.return_value = True |
392 | + test_path = "testfiles/select/1/2/1" |
393 | + self.assertEqual( |
394 | + path_matches_glob_fn(test_path, 1)(Path(test_path)), 1) |
395 | + |
396 | + def test_double_asterisk_string_slash(self): |
397 | + """Test string starting with ** and ending in /""" |
398 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
399 | + mock_isdir.return_value = True |
400 | + self.assertEqual( |
401 | + path_matches_glob_fn("**/1/2/", |
402 | + 1)(Path("testfiles/select/1/2")), 1) |
403 | + |
404 | + def test_string_double_asterisk_string_slash(self): |
405 | + """Test string ** string /""" |
406 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
407 | + mock_isdir.return_value = True |
408 | + self.assertEqual( |
409 | + path_matches_glob_fn("testfiles**/2/", |
410 | + 1)(Path("testfiles/select/1/2")), 1) |
411 | + |
412 | + |
413 | +class TestDoubleAsterisk(UnitTestCase): |
414 | + """Test glob matching where the glob finishes with a **""" |
415 | + |
416 | + def test_simple_trailing_slash_match(self): |
417 | + """Test that a folder string ending in /** matches that path""" |
418 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
419 | + mock_isdir.return_value = True |
420 | + self.assertEqual( |
421 | + path_matches_glob_fn("/test/folder/**", 1)( |
422 | + Path("/test/foo")), None) |
423 | + |
424 | + def test_simple_trailing_slash_match_2(self): |
425 | + """Test folder string ending in */**""" |
426 | + with patch('duplicity.path.Path.isdir') as mock_isdir: |
427 | + mock_isdir.return_value = True |
428 | + self.assertEqual( |
429 | + path_matches_glob_fn("fold*/**", 1)( |
430 | + Path("folder")), 2) |
431 | \ No newline at end of file |
432 | |
433 | === modified file 'testing/unit/test_selection.py' |
434 | --- testing/unit/test_selection.py 2016-03-05 10:14:57 +0000 |
435 | +++ testing/unit/test_selection.py 2016-11-20 22:26:00 +0000 |
436 | @@ -83,8 +83,6 @@ |
437 | |
438 | with patch('duplicity.path.ROPath.isdir') as mock_isdir: |
439 | mock_isdir.return_value = True |
440 | - # Can't pass the return_value as an argument to patch, as build |
441 | - # system's mock is too old to support it. |
442 | |
443 | assert sf2(self.makeext("usr")) is None |
444 | assert sf2(self.makeext("usr/local")) is None |
445 | @@ -666,6 +664,36 @@ |
446 | ("--exclude", "**t/1/3")], |
447 | [(), ('2',), ('2', '1')]) |
448 | |
449 | + def test_includes_files(self): |
450 | + """Unit test the functional test test_includes_files""" |
451 | + # Test for Bug 1624725 |
452 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
453 | + self.root = Path("testfiles/select2/1/1sub1") |
454 | + self.ParseTest([("--include", "testfiles/select2/1/1sub1/1sub1sub1"), |
455 | + ("--exclude", "**")], |
456 | + [(), ('1sub1sub1',), ('1sub1sub1', |
457 | + '1sub1sub1_file.txt')]) |
458 | + |
459 | + def test_includes_files_trailing_slash(self): |
460 | + """Unit test the functional test test_includes_files_trailing_slash""" |
461 | + # Test for Bug 1624725 |
462 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
463 | + self.root = Path("testfiles/select2/1/1sub1") |
464 | + self.ParseTest([("--include", "testfiles/select2/1/1sub1/1sub1sub1/"), |
465 | + ("--exclude", "**")], |
466 | + [(), ('1sub1sub1',), ('1sub1sub1', |
467 | + '1sub1sub1_file.txt')]) |
468 | + |
469 | + def test_includes_files_trailing_slash_globbing_chars(self): |
470 | + """Unit test functional test_includes_files_trailing_slash_globbing_chars""" |
471 | + # Test for Bug 1624725 |
472 | + # https://bugs.launchpad.net/duplicity/+bug/1624725 |
473 | + self.root = Path("testfiles/select2/1/1sub1") |
474 | + self.ParseTest([("--include", "testfiles/s?lect2/1/1sub1/1sub1sub1/"), |
475 | + ("--exclude", "**")], |
476 | + [(), ('1sub1sub1',), ('1sub1sub1', |
477 | + '1sub1sub1_file.txt')]) |
478 | + |
479 | def test_glob(self): |
480 | """Test globbing expression""" |
481 | self.ParseTest([("--exclude", "**[3-5]"), |
Kenneth, is there anything more I can do to get this merged? Would be good to get this fixed, so let me know if there is more I can do to help.