Merge lp:~aaron-whitehouse/duplicity/process_filelists_for_spaces_etc into lp:~duplicity-team/duplicity/0.7-series

Proposed by Aaron Whitehouse
Status: Merged
Merged at revision: 1046
Proposed branch: lp:~aaron-whitehouse/duplicity/process_filelists_for_spaces_etc
Merge into: lp:~duplicity-team/duplicity/0.7-series
Diff against target: 1143 lines (+1018/-29)
3 files modified
duplicity/selection.py (+46/-22)
testing/functional/test_selection.py (+606/-0)
testing/unit/test_selection.py (+366/-7)
To merge this branch: bzr merge lp:~aaron-whitehouse/duplicity/process_filelists_for_spaces_etc
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+245797@code.launchpad.net

Description of the change

Process filelists to remove imperfections such as blank lines, comments and leading/trailing whitespace. Also correctly processes quoted folders containing spaces in their names. Extensive unit and functional tests to test these changes (and selection more generally).

The branch does add an additional folder to testfiles.tar.gz called select2. This included a folder with a trailing space, to test the quote test. The subfolders also have clearer names than in the "select" folder (eg "1sub2sub3") which makes it easier to keep track of issues in tests.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'duplicity/selection.py'
2--- duplicity/selection.py 2014-12-12 14:39:54 +0000
3+++ duplicity/selection.py 2015-01-07 22:00:24 +0000
4@@ -2,6 +2,7 @@
5 #
6 # Copyright 2002 Ben Escoto <ben@emerose.org>
7 # Copyright 2007 Kenneth Loafman <kenneth@loafman.com>
8+# Copyright 2014 Aaron Whitehouse <aaron@whitehouse.kiwi.nz>
9 #
10 # This file is part of duplicity.
11 #
12@@ -349,30 +350,37 @@
13 something_excluded, tuple_list = None, []
14 separator = globals.null_separator and "\0" or "\n"
15 for line in filelist_fp.read().split(separator):
16- if not line:
17- continue # skip blanks
18 try:
19 tuple = self.filelist_parse_line(line, include)
20 except FilePrefixError as exc:
21 incr_warnings(exc)
22 continue
23- tuple_list.append(tuple)
24+ if not tuple:
25+ # Skip blanks/full-line comments
26+ continue
27+ else:
28+ tuple_list.append(tuple)
29 if not tuple[1]:
30 something_excluded = 1
31 if filelist_fp not in (sys.stdin,) and filelist_fp.close():
32 log.Warn(_("Error closing filelist %s") % filelist_name)
33 return (tuple_list, something_excluded)
34
35- def filelist_parse_line(self, line, include):
36- """Parse a single line of a filelist, returning a pair
37-
38- pair will be of form (index, include), where index is another
39- tuple, and include is 1 if the line specifies that we are
40- including a file. The default is given as an argument.
41- prefix is the string that the index is relative to.
42-
43- """
44+ def filelist_sanitise_line(self, line, include_default):
45+ """
46+ Sanitises lines of both normal and globbing filelists, returning (line, include) and line=None if blank/comment
47+
48+ The aim is to parse filelists in a consistent way, prior to the interpretation of globbing statements.
49+ The function removes whitespace, comment lines and processes modifiers (leading +/-) and quotes.
50+ """
51+
52 line = line.strip()
53+ if not line: # skip blanks
54+ return None, include_default
55+ if line[0] == "#": # skip full-line comments
56+ return None, include_default
57+
58+ include = include_default
59 if line[:2] == "+ ":
60 # Check for "+ "/"- " syntax
61 include = 1
62@@ -381,6 +389,27 @@
63 include = 0
64 line = line[2:]
65
66+ if (line[:1] == "'" and line[-1:] == "'") or (line[:1] == '"' and line[-1:] == '"'):
67+ line = line[1:-1]
68+
69+ return line, include
70+
71+ def filelist_parse_line(self, line, include):
72+ """Parse a single line of a filelist, returning a pair or None if the line is blank/a comment
73+
74+ Pair will be of form (index, include), where index is another
75+ tuple, and include is 1 if the line specifies that we are
76+ including a file. The default is given as an argument.
77+ prefix is the string that the index is relative to.
78+
79+ """
80+
81+ line, include = self.filelist_sanitise_line(line, include)
82+
83+ if not line:
84+ # Skip blanks and comments
85+ return None
86+
87 if not line.startswith(self.prefix):
88 raise FilePrefixError(line)
89 line = line[len(self.prefix):] # Discard prefix
90@@ -430,16 +459,11 @@
91 log.Notice(_("Reading globbing filelist %s") % list_name)
92 separator = globals.null_separator and "\0" or "\n"
93 for line in filelist_fp.read().split(separator):
94- if not line: # skip blanks
95- continue
96- if line[0] == "#": # skip comments
97- continue
98- if line[:2] == "+ ":
99- yield self.glob_get_sf(line[2:], 1)
100- elif line[:2] == "- ":
101- yield self.glob_get_sf(line[2:], 0)
102- else:
103- yield self.glob_get_sf(line, inc_default)
104+ line, include = self.filelist_sanitise_line(line, inc_default)
105+ if not line:
106+ # Skip blanks and comment lines
107+ continue
108+ yield self.glob_get_sf(line, include)
109
110 def other_filesystems_get_sf(self, include):
111 """Return selection function matching files on other filesystems"""
112
113=== added file 'testing/functional/test_selection.py'
114--- testing/functional/test_selection.py 1970-01-01 00:00:00 +0000
115+++ testing/functional/test_selection.py 2015-01-07 22:00:24 +0000
116@@ -0,0 +1,606 @@
117+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
118+#
119+# Copyright 2014 Aaron Whitehouse <aaron@whitehouse.kiwi.nz>
120+#
121+# This file is part of duplicity.
122+#
123+# Duplicity is free software; you can redistribute it and/or modify it
124+# under the terms of the GNU General Public License as published by the
125+# Free Software Foundation; either version 2 of the License, or (at your
126+# option) any later version.
127+#
128+# Duplicity is distributed in the hope that it will be useful, but
129+# WITHOUT ANY WARRANTY; without even the implied warranty of
130+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
131+# General Public License for more details.
132+#
133+# You should have received a copy of the GNU General Public License
134+# along with duplicity; if not, write to the Free Software Foundation,
135+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
136+
137+import os
138+import os.path
139+import unittest
140+
141+from . import FunctionalTestCase
142+
143+
144+class IncludeExcludeFunctionalTest(FunctionalTestCase):
145+ """
146+ This contains methods used in the tests below for testing the include, exclude and various filelist features.
147+ """
148+
149+ # These tests assume the following files and logic, with:
150+ # "is" meaning that the file is included specifically
151+ # "ia" meaning that the file should be included automatically because its parent is included
152+ # "ic" meaning that the folder is included because its contents are included
153+ # "es" meaning that the file is excluded specifically
154+ # "ea" meaning that the file should be excluded automatically because its parent is included
155+ # select2 (es)
156+ # --- 1.doc (ea)
157+ # --- 1.py (is)
158+ # --- 1 (is)
159+ # ------ 1sub1 (ia)
160+ # --------- 1sub1sub1 (ia)
161+ # ------------ 1sub1sub1_file.txt (ia)
162+ # --------- 1sub1sub2 (es)
163+ # ------------ 1sub1sub2_file.txt (ea)
164+ # --------- 1sub1sub3 (ia)
165+ # ------------ 1sub1sub3_file.txt (es)
166+ # ------ 1sub2 (ic)
167+ # --------- 1sub2sub1 (is)
168+ # --------- 1sub2sub2 (ea)
169+ # --------- 1sub2sub3 (es) # Not necessary as also ea, but to ensure there are no issues doing so
170+ # ------ 1sub3 (ia)
171+ # --------- 1sub3sub1 (es)
172+ # --------- 1sub3sub2 (es)
173+ # --------- 1sub3sub3 (ia)
174+ # --- 2 (ic)
175+ # ------ 2sub1 (is)
176+ # --------- 2sub1sub1 (ia)
177+ # ------------ 2sub1sub1_file.txt (ia)
178+ # --------- 2sub1sub2 (es)
179+ # --------- 2sub1sub3 (es)
180+ # ------ 2sub2 (ea)
181+ # --------- 2sub2sub1 (ea)
182+ # --------- 2sub2sub2 (ea)
183+ # --------- 2sub2sub3 (ea)
184+ # ------ 2sub3 (ea)
185+ # --------- 2sub3sub1 (ea)
186+ # --------- 2sub3sub3 (ea)
187+ # --------- 2sub3sub2 (ea)
188+ # --- 3 (is)
189+ # ------ 3sub1 (es)
190+ # --------- 3sub1sub1 (ea)
191+ # --------- 3sub1sub2 (ea)
192+ # --------- 3sub1sub3 (ea)
193+ # ------ 3sub2 (ia)
194+ # --------- 3sub2sub1 (ia)
195+ # --------- 3sub2sub2 (ia)
196+ # --------- 3sub2sub3 (ia)
197+ # ------ 3sub3 (is) # Not necessary as also ia, but to ensure there are no issues doing so
198+ # --------- 3sub3sub1 (ia)
199+ # --------- 3sub3sub2 (es, ic)
200+ # ------------ 3sub3sub2_file.txt (is)
201+ # --------- 3sub3sub3 (ia)
202+ # --- trailing_space (ea) # Note this is "trailing_space ". Excluded until trailing_space test, when (is)
203+ # ------ trailing_space sub1 (ea) # Excluded until trailing_space test, when (ia)
204+ # ------ trailing_space sub2 (ea) # Excluded until trailing_space test, when (es, ic)
205+ # --------- trailing_space sub2_file.txt (ea) # Excluded until trailing_space test, when (is)
206+
207+ complete_directory_tree = [['1', '2', '3', 'trailing_space ', '1.doc', '1.py'],
208+ ['1sub1', '1sub2', '1sub3'],
209+ ['1sub1sub1', '1sub1sub2', '1sub1sub3'],
210+ ['1sub1sub1_file.txt'],
211+ ['1sub1sub2_file.txt'],
212+ ['1sub1sub3_file.txt'],
213+ ['1sub2sub1', '1sub2sub2', '1sub2sub3'],
214+ ['1sub3sub1', '1sub3sub2', '1sub3sub3'],
215+ ['2sub1', '2sub2', '2sub3'],
216+ ['2sub1sub1', '2sub1sub2', '2sub1sub3'],
217+ ['2sub1sub1_file.txt'],
218+ ['2sub2sub1', '2sub2sub2', '2sub2sub3'],
219+ ['2sub3sub1', '2sub3sub2', '2sub3sub3'],
220+ ['3sub1', '3sub2', '3sub3'],
221+ ['3sub1sub1', '3sub1sub2', '3sub1sub3'],
222+ ['3sub2sub1', '3sub2sub2', '3sub2sub3'],
223+ ['3sub3sub1', '3sub3sub2', '3sub3sub3'],
224+ ['3sub3sub2_file.txt'],
225+ ['trailing_space sub1', 'trailing_space sub2'],
226+ ['trailing_space sub2_file.txt']]
227+
228+ expected_restored_tree = [['1', '2', '3', '1.py'],
229+ ['1sub1', '1sub2', '1sub3'],
230+ ['1sub1sub1', '1sub1sub3'],
231+ ['1sub1sub1_file.txt'],
232+ ['1sub2sub1'],
233+ ['1sub3sub3'],
234+ ['2sub1'],
235+ ['2sub1sub1'],
236+ ['2sub1sub1_file.txt'],
237+ ['3sub2', '3sub3'],
238+ ['3sub2sub1', '3sub2sub2', '3sub2sub3'],
239+ ['3sub3sub1', '3sub3sub2', '3sub3sub3'],
240+ ['3sub3sub2_file.txt']]
241+
242+ expected_restored_tree_with_trailing_space = [['1', '2', '3', 'trailing_space ', '1.py'],
243+ ['1sub1', '1sub2', '1sub3'],
244+ ['1sub1sub1', '1sub1sub3'],
245+ ['1sub1sub1_file.txt'],
246+ ['1sub2sub1'],
247+ ['1sub3sub3'],
248+ ['2sub1'],
249+ ['2sub1sub1'],
250+ ['2sub1sub1_file.txt'],
251+ ['3sub2', '3sub3'],
252+ ['3sub2sub1', '3sub2sub2', '3sub2sub3'],
253+ ['3sub3sub1', '3sub3sub2', '3sub3sub3'],
254+ ['3sub3sub2_file.txt'],
255+ ['trailing_space sub1', 'trailing_space sub2'],
256+ ['trailing_space sub2_file.txt']]
257+
258+ def directory_tree_to_list_of_lists(self, parent_directory):
259+ """
260+ This takes a folder as an input and returns a list with its contents. If the directory has subdirectories, it
261+ returns a list of lists with the contents of those subdirectories.
262+ """
263+ directory_list = []
264+ for root, dirs, files in os.walk(parent_directory):
265+ to_add = []
266+ if dirs:
267+ dirs.sort() # So that we can easily compare to what we expect
268+ to_add = dirs
269+ if files:
270+ files.sort() # So that we can easily compare to what we expect
271+ to_add += files
272+ if to_add:
273+ directory_list.append(to_add)
274+ return directory_list
275+
276+
277+class TestCheckTestFiles(IncludeExcludeFunctionalTest):
278+ """ Tests the testfiles required by the exclude/include tests are as expected. """
279+
280+ def test_files_are_as_expected(self):
281+ """Test that the contents of testfiles/select are as expected."""
282+ testfiles = self.directory_tree_to_list_of_lists('testfiles/select2')
283+ #print(testfiles)
284+ self.assertEqual(testfiles, self.complete_directory_tree)
285+
286+
287+class TestIncludeExcludeOptions(IncludeExcludeFunctionalTest):
288+ """ This tests the behaviour of the duplicity binary when the include/exclude options are passed directly """
289+
290+ def test_include_exclude_basic(self):
291+ """ Test --include and --exclude work in the basic case """
292+ self.backup("full", "testfiles/select2",
293+ options=["--include", "testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt",
294+ "--exclude", "testfiles/select2/3/3sub3/3sub3sub2",
295+ "--include", "testfiles/select2/3/3sub2/3sub2sub2",
296+ "--include", "testfiles/select2/3/3sub3",
297+ "--exclude", "testfiles/select2/3/3sub1",
298+ "--exclude", "testfiles/select2/2/2sub1/2sub1sub3",
299+ "--exclude", "testfiles/select2/2/2sub1/2sub1sub2",
300+ "--include", "testfiles/select2/2/2sub1",
301+ "--exclude", "testfiles/select2/1/1sub3/1sub3sub2",
302+ "--exclude", "testfiles/select2/1/1sub3/1sub3sub1",
303+ "--exclude", "testfiles/select2/1/1sub2/1sub2sub3",
304+ "--include", "testfiles/select2/1/1sub2/1sub2sub1",
305+ "--exclude", "testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt",
306+ "--exclude", "testfiles/select2/1/1sub1/1sub1sub2",
307+ "--exclude", "testfiles/select2/1/1sub2",
308+ "--include", "testfiles/select2/1.py",
309+ "--include", "testfiles/select2/3",
310+ "--include", "testfiles/select2/1",
311+ "--exclude", "testfiles/select2/**"])
312+ self.restore()
313+ restore_dir = 'testfiles/restore_out'
314+ restored = self.directory_tree_to_list_of_lists(restore_dir)
315+ self.assertEqual(restored, self.expected_restored_tree)
316+
317+ def test_include_exclude_trailing_whitespace(self):
318+ """Test that folders with trailing whitespace in the names work correctly when passing as include/exclude"""
319+ # Note that, because this only passes items in as a list of options, this test does not test whether duplicity
320+ # would correctly interpret commandline options with spaces. However, bin/duplicity uses sys.argv[1:], which
321+ # should return a list of strings after having correctly processed quotes etc.
322+ self.backup("full", "testfiles/select2",
323+ options=["--include",
324+ "testfiles/select2/trailing_space /trailing_space sub2/trailing_space sub2_file.txt",
325+ "--exclude", "testfiles/select2/trailing_space /trailing_space sub2",
326+ "--include", "testfiles/select2/trailing_space ",
327+ "--include", "testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt",
328+ "--exclude", "testfiles/select2/3/3sub3/3sub3sub2",
329+ "--include", "testfiles/select2/3/3sub2/3sub2sub2",
330+ "--include", "testfiles/select2/3/3sub3",
331+ "--exclude", "testfiles/select2/3/3sub1",
332+ "--exclude", "testfiles/select2/2/2sub1/2sub1sub3",
333+ "--exclude", "testfiles/select2/2/2sub1/2sub1sub2",
334+ "--include", "testfiles/select2/2/2sub1",
335+ "--exclude", "testfiles/select2/1/1sub3/1sub3sub2",
336+ "--exclude", "testfiles/select2/1/1sub3/1sub3sub1",
337+ "--exclude", "testfiles/select2/1/1sub2/1sub2sub3",
338+ "--include", "testfiles/select2/1/1sub2/1sub2sub1",
339+ "--exclude", "testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt",
340+ "--exclude", "testfiles/select2/1/1sub1/1sub1sub2",
341+ "--exclude", "testfiles/select2/1/1sub2",
342+ "--include", "testfiles/select2/1.py",
343+ "--include", "testfiles/select2/3",
344+ "--include", "testfiles/select2/1",
345+ "--exclude", "testfiles/select2/**"])
346+ self.restore()
347+ restore_dir = 'testfiles/restore_out'
348+ restored = self.directory_tree_to_list_of_lists(restore_dir)
349+ self.assertEqual(restored, self.expected_restored_tree_with_trailing_space)
350+
351+
352+class TestExcludeGlobbingFilelistTest(IncludeExcludeFunctionalTest):
353+ """
354+ Test --exclude-globbing-filelist using duplicity binary.
355+ """
356+
357+ def test_exclude_globbing_filelist(self):
358+ """Test that exclude globbing filelist works in the basic case """
359+ # As this is an exclude filelist any lines with no +/- modifier should be treated as if they have a -.
360+ # Create a filelist
361+ with open('testfiles/exclude.txt', 'w') as f:
362+ f.write('+ testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
363+ 'testfiles/select2/3/3sub3/3sub3sub2\n'
364+ '+ testfiles/select2/3/3sub2/3sub2sub2\n'
365+ '+ testfiles/select2/3/3sub3\n'
366+ '- testfiles/select2/3/3sub1\n' # - added to ensure it makes no difference
367+ 'testfiles/select2/2/2sub1/2sub1sub3\n'
368+ 'testfiles/select2/2/2sub1/2sub1sub2\n'
369+ '+ testfiles/select2/2/2sub1\n'
370+ 'testfiles/select2/1/1sub3/1sub3sub2\n'
371+ 'testfiles/select2/1/1sub3/1sub3sub1\n'
372+ 'testfiles/select2/1/1sub2/1sub2sub3\n'
373+ '+ testfiles/select2/1/1sub2/1sub2sub1\n'
374+ 'testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
375+ 'testfiles/select2/1/1sub1/1sub1sub2\n'
376+ '- testfiles/select2/1/1sub2\n' # - added to ensure it makes no difference
377+ '+ testfiles/select2/1.py\n'
378+ '+ testfiles/select2/3\n'
379+ '+ testfiles/select2/1\n'
380+ 'testfiles/select2/**')
381+ self.backup("full", "testfiles/select2", options=["--exclude-globbing-filelist=testfiles/exclude.txt"])
382+ self.restore()
383+ restore_dir = 'testfiles/restore_out'
384+ restored = self.directory_tree_to_list_of_lists(restore_dir)
385+ self.assertEqual(restored, self.expected_restored_tree)
386+
387+ def test_exclude_globbing_filelist_combined_imperfections(self):
388+ """Test that exclude globbing filelist works with imperfections in the input file"""
389+ # This is a combined test for speed reasons. The individual imperfections are tested as unittests in
390+ # unit/test_selection.
391+ # Imperfections tested are;
392+ # * Leading space/spaces before the modifier
393+ # * Trailing space/spaces after the filename (but before the newline)
394+ # * Blank lines (newline character only)
395+ # * Line only containing spaces
396+ # * Full-line comments with # as the first character and with leading/trailing spaces
397+ # * Unnecessarily quoted filenames with/without modifier (both " and ')
398+
399+ # Create a filelist
400+ with open('testfiles/exclude.txt', 'w') as f:
401+ f.write('+ testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
402+ 'testfiles/select2/3/3sub3/3sub3sub2\n'
403+ '+ testfiles/select2/3/3sub2/3sub2sub2\n'
404+ ' + testfiles/select2/3/3sub3\n' # Note leading space added here
405+ '- testfiles/select2/3/3sub1\n'
406+ ' testfiles/select2/2/2sub1/2sub1sub3\n' # Note leading spaces added here
407+ '\n'
408+ 'testfiles/select2/2/2sub1/2sub1sub2\n'
409+ ' + testfiles/select2/2/2sub1 \n' # Note added trailing/leading space here
410+ '- "testfiles/select2/1/1sub3/1sub3sub2"\n' # Unnecessary quotes
411+ '# Testing a full-line comment\n'
412+ "'testfiles/select2/1/1sub3/1sub3sub1' \n" # Note added spaces and quotes here
413+ 'testfiles/select2/1/1sub2/1sub2sub3\n'
414+ ' \n'
415+ '+ testfiles/select2/1/1sub2/1sub2sub1\n'
416+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
417+ 'testfiles/select2/1/1sub1/1sub1sub2\n'
418+ ' # Testing a full-line comment with leading and trailing spaces \n'
419+ 'testfiles/select2/1/1sub2 \n' # Note added spaces here
420+ '+ testfiles/select2/1.py\n'
421+ '+ testfiles/select2/3 \n' # Note added space here
422+ '+ testfiles/select2/1\n'
423+ '- testfiles/select2/**')
424+ self.backup("full", "testfiles/select2", options=["--exclude-globbing-filelist=testfiles/exclude.txt"])
425+ self.restore()
426+ restore_dir = 'testfiles/restore_out'
427+ restored = self.directory_tree_to_list_of_lists(restore_dir)
428+ self.assertEqual(restored, self.expected_restored_tree)
429+
430+ def test_exclude_globbing_filelist_trailing_whitespace_folders_work_with_quotes(self):
431+ """Test that folders with trailing whitespace in the names work correctly if they are enclosed in quotes"""
432+ # Create a filelist
433+ with open('testfiles/exclude.txt', 'w') as f:
434+ f.write('+ "testfiles/select2/trailing_space /trailing_space sub2/trailing_space sub2_file.txt"\n' # New
435+ '- "testfiles/select2/trailing_space /trailing_space sub2"\n' # New
436+ '+ "testfiles/select2/trailing_space "\n' # New
437+ '+ testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
438+ 'testfiles/select2/3/3sub3/3sub3sub2\n'
439+ '+ testfiles/select2/3/3sub2/3sub2sub2\n'
440+ '+ testfiles/select2/3/3sub3\n'
441+ '- testfiles/select2/3/3sub1\n'
442+ 'testfiles/select2/2/2sub1/2sub1sub3\n'
443+ 'testfiles/select2/2/2sub1/2sub1sub2\n'
444+ '+ testfiles/select2/2/2sub1\n'
445+ 'testfiles/select2/1/1sub3/1sub3sub2\n'
446+ 'testfiles/select2/1/1sub3/1sub3sub1\n'
447+ 'testfiles/select2/1/1sub2/1sub2sub3\n'
448+ '+ testfiles/select2/1/1sub2/1sub2sub1\n'
449+ 'testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
450+ 'testfiles/select2/1/1sub1/1sub1sub2\n'
451+ '- testfiles/select2/1/1sub2\n'
452+ '+ testfiles/select2/1.py\n'
453+ '+ testfiles/select2/3\n'
454+ '+ testfiles/select2/1\n'
455+ 'testfiles/select2/**')
456+ self.backup("full", "testfiles/select2", options=["--exclude-globbing-filelist=testfiles/exclude.txt"])
457+ self.restore()
458+ restore_dir = 'testfiles/restore_out'
459+ restored = self.directory_tree_to_list_of_lists(restore_dir)
460+ self.assertEqual(restored, self.expected_restored_tree_with_trailing_space)
461+
462+class TestIncludeGlobbingFilelistTest(IncludeExcludeFunctionalTest):
463+ """
464+ Test --include-globbing-filelist using duplicity binary.
465+ """
466+
467+ def test_include_globbing_filelist(self):
468+ """Test that include globbing filelist works in the basic case"""
469+ # See test_exclude_globbing_filelist above for explanation of what is expected. As this is an include filelist
470+ # any lines with no +/- modifier should be treated as if they have a +.
471+ # Create a filelist
472+ with open('testfiles/include.txt', 'w') as f:
473+ f.write('testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
474+ '- testfiles/select2/3/3sub3/3sub3sub2\n'
475+ 'testfiles/select2/3/3sub2/3sub2sub2\n'
476+ '+ testfiles/select2/3/3sub3\n' # + added to ensure it makes no difference
477+ '- testfiles/select2/3/3sub1\n'
478+ '- testfiles/select2/2/2sub1/2sub1sub3\n'
479+ '- testfiles/select2/2/2sub1/2sub1sub2\n'
480+ 'testfiles/select2/2/2sub1\n'
481+ '- testfiles/select2/1/1sub3/1sub3sub2\n'
482+ '- testfiles/select2/1/1sub3/1sub3sub1\n'
483+ '- testfiles/select2/1/1sub2/1sub2sub3\n'
484+ '+ testfiles/select2/1/1sub2/1sub2sub1\n' # + added to ensure it makes no difference
485+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
486+ '- testfiles/select2/1/1sub1/1sub1sub2\n'
487+ '- testfiles/select2/1/1sub2\n'
488+ 'testfiles/select2/1.py\n'
489+ 'testfiles/select2/3\n'
490+ 'testfiles/select2/1\n'
491+ '- testfiles/select2/**')
492+ self.backup("full", "testfiles/select2", options=["--include-globbing-filelist=testfiles/include.txt"])
493+ self.restore()
494+ restore_dir = 'testfiles/restore_out'
495+ restored = self.directory_tree_to_list_of_lists(restore_dir)
496+ self.assertEqual(restored, self.expected_restored_tree)
497+
498+ def test_include_globbing_filelist_combined_imperfections(self):
499+ """Test that include globbing filelist works with imperfections in the input file"""
500+ # This is a combined test for speed reasons. The individual imperfections are tested as unittests in
501+ # unit/test_selection.
502+ # Imperfections tested are;
503+ # * Leading space/spaces before the modifier
504+ # * Trailing space/spaces after the filename (but before the newline)
505+ # * Blank lines (newline character only)
506+ # * Line only containing spaces
507+ # * Full-line comments with # as the first character and with leading/trailing spaces
508+ # * Unnecessarily quoted filenames with/without modifier (both " and ')
509+ # Create a filelist
510+ with open('testfiles/include.txt', 'w') as f:
511+ f.write('testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
512+ '- testfiles/select2/3/3sub3/3sub3sub2\n'
513+ '"testfiles/select2/3/3sub2/3sub2sub2"\n'
514+ ' + testfiles/select2/3/3sub3\n' # + added to ensure it makes no difference
515+ '- testfiles/select2/3/3sub1\n'
516+ '- testfiles/select2/2/2sub1/2sub1sub3\n'
517+ ' - "testfiles/select2/2/2sub1/2sub1sub2"\n'
518+ 'testfiles/select2/2/2sub1 \n'
519+ '\n'
520+ '- testfiles/select2/1/1sub3/1sub3sub2\n'
521+ '- testfiles/select2/1/1sub3/1sub3sub1 \n'
522+ "- 'testfiles/select2/1/1sub2/1sub2sub3'\n"
523+ ' \n'
524+ ' + testfiles/select2/1/1sub2/1sub2sub1 \n' # + added to ensure it makes no difference
525+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
526+ ' - testfiles/select2/1/1sub1/1sub1sub2 \n'
527+ '# Testing full-line comment\n'
528+ '- testfiles/select2/1/1sub2\n'
529+ "'testfiles/select2/1.py'\n"
530+ 'testfiles/select2/3\n'
531+ ' # Testing another full-line comment \n'
532+ 'testfiles/select2/1\n'
533+ '- testfiles/select2/**')
534+ self.backup("full", "testfiles/select2", options=["--include-globbing-filelist=testfiles/include.txt"])
535+ self.restore()
536+ restore_dir = 'testfiles/restore_out'
537+ restored = self.directory_tree_to_list_of_lists(restore_dir)
538+ self.assertEqual(restored, self.expected_restored_tree)
539+
540+
541+class TestIncludeFilelistTest(IncludeExcludeFunctionalTest):
542+ """
543+ Test --include-filelist using duplicity binary.
544+ """
545+ @unittest.expectedFailure
546+ def test_include_filelist(self):
547+ """Test that include filelist works in the basic case"""
548+ # See test_exclude_globbing_filelist above for explanation of what is expected. As this is an include filelist
549+ # any lines with no +/- modifier should be treated as if they have a +.
550+ # ToDo Currently fails - Bug #1408411 (https://bugs.launchpad.net/duplicity/+bug/1408411)
551+ # Create a filelist
552+ with open('testfiles/include.txt', 'w') as f:
553+ f.write('testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
554+ '- testfiles/select2/3/3sub3/3sub3sub2\n'
555+ 'testfiles/select2/3/3sub2/3sub2sub2\n'
556+ '+ testfiles/select2/3/3sub3\n' # + added to ensure it makes no difference
557+ '- testfiles/select2/3/3sub1\n'
558+ '- testfiles/select2/2/2sub1/2sub1sub3\n'
559+ '- testfiles/select2/2/2sub1/2sub1sub2\n'
560+ 'testfiles/select2/2/2sub1\n'
561+ '- testfiles/select2/1/1sub3/1sub3sub2\n'
562+ '- testfiles/select2/1/1sub3/1sub3sub1\n'
563+ '- testfiles/select2/1/1sub2/1sub2sub3\n'
564+ '+ testfiles/select2/1/1sub2/1sub2sub1\n' # + added to ensure it makes no difference
565+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
566+ '- testfiles/select2/1/1sub1/1sub1sub2\n'
567+ '- testfiles/select2/1/1sub2\n'
568+ 'testfiles/select2/1.py\n'
569+ 'testfiles/select2/3\n'
570+ '- testfiles/select2/2\n' # es instead of ea as no globbing - **
571+ 'testfiles/select2/1\n'
572+ '- "testfiles/select2/trailing_space "\n' # es instead of ea as no globbing - **
573+ '- testfiles/select2/1.doc') # es instead of ea as no globbing - **
574+ self.backup("full", "testfiles/select2", options=["--include-filelist=testfiles/include.txt"])
575+ self.restore()
576+ restore_dir = 'testfiles/restore_out'
577+ restored = self.directory_tree_to_list_of_lists(restore_dir)
578+ self.assertEqual(restored, self.expected_restored_tree)
579+
580+ def test_include_filelist_workaround(self):
581+ """Test that include filelist works in the basic case"""
582+ # This is a modified version of test_include_filelist that passes, despite Bug #1408411
583+ # It is still a valid test, it just does not test as many selection features as the above.
584+ # Create a filelist
585+ with open('testfiles/include.txt', 'w') as f:
586+ f.write('testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
587+ # '- testfiles/select2/3/3sub3/3sub3sub2\n' # Commented out because of Bug #1408411
588+ 'testfiles/select2/3/3sub2/3sub2sub2\n'
589+ '+ testfiles/select2/3/3sub3\n' # + added to ensure it makes no difference
590+ '- testfiles/select2/3/3sub1\n'
591+ '- testfiles/select2/2/2sub1/2sub1sub3\n'
592+ '- testfiles/select2/2/2sub1/2sub1sub2\n'
593+ 'testfiles/select2/2/2sub1\n'
594+ '- testfiles/select2/2/2sub3\n' # Added because of Bug #1408411
595+ '- testfiles/select2/2/2sub2\n' # Added because of Bug #1408411
596+ '- testfiles/select2/1/1sub3/1sub3sub2\n'
597+ '- testfiles/select2/1/1sub3/1sub3sub1\n'
598+ '- testfiles/select2/1/1sub2/1sub2sub3\n'
599+ '- testfiles/select2/1/1sub2/1sub2sub2\n' # Added because of Bug #1408411
600+ '+ testfiles/select2/1/1sub2/1sub2sub1\n' # + added to ensure it makes no difference
601+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
602+ '- testfiles/select2/1/1sub1/1sub1sub2\n'
603+ # '- testfiles/select2/1/1sub2\n' # Commented out because of Bug #1408411
604+ 'testfiles/select2/1.py\n'
605+ 'testfiles/select2/3\n'
606+ # '- testfiles/select2/2\n' # Commented out because of Bug #1408411
607+ 'testfiles/select2/1\n'
608+ '- "testfiles/select2/trailing_space "\n' # es instead of ea as no globbing - **
609+ '- testfiles/select2/1.doc') # es instead of ea as no globbing - **
610+ self.backup("full", "testfiles/select2", options=["--include-filelist=testfiles/include.txt"])
611+ self.restore()
612+ restore_dir = 'testfiles/restore_out'
613+ restored = self.directory_tree_to_list_of_lists(restore_dir)
614+ self.assertEqual(restored, self.expected_restored_tree)
615+
616+ def test_include_filelist_workaround_combined_imperfections(self):
617+ """Test that include filelist works with imperfections in the input file"""
618+ # This is a modified version of test_include_filelist that passes, despite Bug #1408411
619+ # It is still a valid test, it just does not test as many selection features as the above.
620+ # This is a combined test for speed reasons. The individual imperfections are tested as unittests in
621+ # unit/test_selection.
622+ # Imperfections tested are;
623+ # * Leading space/spaces before the modifier
624+ # * Trailing space/spaces after the filename (but before the newline)
625+ # * Blank lines (newline character only)
626+ # * Line only containing spaces
627+ # * Full-line comments with # as the first character and with leading/trailing spaces
628+ # * Unnecessarily quoted filenames with/without modifier (both " and ')
629+ # Create a filelist
630+ with open('testfiles/include.txt', 'w') as f:
631+ f.write('testfiles/select2/3/3sub3/3sub3sub2/3sub3sub2_file.txt\n'
632+ 'testfiles/select2/3/3sub2/3sub2sub2 \n'
633+ ' + testfiles/select2/3/3sub3\n' # + added to ensure it makes no difference
634+ ' - testfiles/select2/3/3sub1 \n'
635+ '- testfiles/select2/2/2sub1/2sub1sub3\n'
636+ '- testfiles/select2/2/2sub1/2sub1sub2\n'
637+ '"testfiles/select2/2/2sub1"\n'
638+ ' - testfiles/select2/2/2sub3 \n' # Added because of Bug #1408411
639+ '- testfiles/select2/2/2sub2\n' # Added because of Bug #1408411
640+ "- 'testfiles/select2/1/1sub3/1sub3sub2'\n"
641+ '\n'
642+ '- testfiles/select2/1/1sub3/1sub3sub1\n'
643+ '- testfiles/select2/1/1sub2/1sub2sub3\n'
644+ '- "testfiles/select2/1/1sub2/1sub2sub2"\n' # Added because of Bug #1408411
645+ '# This is a full-line comment\n'
646+ '+ testfiles/select2/1/1sub2/1sub2sub1 \n' # + added to ensure it makes no difference
647+ '- testfiles/select2/1/1sub1/1sub1sub3/1sub1sub3_file.txt\n'
648+ ' \n'
649+ '- testfiles/select2/1/1sub1/1sub1sub2\n'
650+ # '- testfiles/select2/1/1sub2\n' # Commented out because of Bug #1408411
651+ "'testfiles/select2/1.py'\n"
652+ ' # This is another full-line comment, with spaces \n'
653+ 'testfiles/select2/3\n'
654+ # '- testfiles/select2/2\n' # Commented out because of Bug #1408411
655+ 'testfiles/select2/1\n'
656+ '- "testfiles/select2/trailing_space "\n' # es instead of ea as no globbing - **
657+ '- testfiles/select2/1.doc') # es instead of ea as no globbing - **
658+ self.backup("full", "testfiles/select2", options=["--include-filelist=testfiles/include.txt"])
659+ self.restore()
660+ restore_dir = 'testfiles/restore_out'
661+ restored = self.directory_tree_to_list_of_lists(restore_dir)
662+ self.assertEqual(restored, self.expected_restored_tree)
663+
664+class TestIncludeExcludedForContents(IncludeExcludeFunctionalTest):
665+ """ Test to check that folders that are excluded are included if they contain includes of higher priority.
666+ Exhibits the issue reported in Bug #1408411 (https://bugs.launchpad.net/duplicity/+bug/1408411). """
667+
668+ def write_filelist(self, filelist_name):
669+ """Used by the below tests to write the filelist"""
670+ assert filelist_name is not None
671+ with open(filelist_name, 'w') as f:
672+ f.write("+ testfiles/select/1/2/1\n"
673+ "- testfiles/select/1/2\n"
674+ "- testfiles/select/1/1\n"
675+ "- testfiles/select/1/3")
676+
677+ def restore_and_check(self):
678+ """Restores the backup and compares to what was expected (based on the filelist in write_filelist)"""
679+ self.restore()
680+ restore_dir = 'testfiles/restore_out'
681+ restored = self.directory_tree_to_list_of_lists(restore_dir)
682+ self.assertEqual(restored, [['2'], ['1']])
683+
684+ def test_commandline_include_exclude(self):
685+ """test an excluded folder is included for included contents when using commandline includes and excludes"""
686+ self.backup("full", "testfiles/select/1",
687+ options=["--include", "testfiles/select/1/2/1",
688+ "--exclude", "testfiles/select/1/2",
689+ "--exclude", "testfiles/select/1/1",
690+ "--exclude", "testfiles/select/1/3"])
691+ self.restore_and_check()
692+
693+ def test_include_globbing_filelist(self):
694+ """test an excluded folder is included for included contents with an include-globbing-filelist """
695+ self.write_filelist("testfiles/include.txt")
696+ self.backup("full", "testfiles/select/1", options=["--include-globbing-filelist=testfiles/include.txt"])
697+ self.restore_and_check()
698+
699+ def test_exclude_globbing_filelist(self):
700+ """test an excluded folder is included for included contents with an exclude-globbing-filelist """
701+ self.write_filelist("testfiles/exclude.txt")
702+ self.backup("full", "testfiles/select/1", options=["--exclude-globbing-filelist=testfiles/exclude.txt"])
703+ self.restore_and_check()
704+
705+ @unittest.expectedFailure
706+ def test_include_filelist(self):
707+ """test an excluded folder is included for included contents with an include-filelist (non-globbing) """
708+ # ToDo - currently fails - Bug #1408411 (https://bugs.launchpad.net/duplicity/+bug/1408411)
709+ self.write_filelist("testfiles/include.txt")
710+ self.backup("full", "testfiles/select/1", options=["--include-filelist=testfiles/include.txt"])
711+ self.restore_and_check()
712+
713+ @unittest.expectedFailure
714+ def test_exclude_filelist(self):
715+ """test an excluded folder is included for included contents with an exclude-filelist (non-globbing) """
716+ # ToDo - currently fails - Bug #1408411 (https://bugs.launchpad.net/duplicity/+bug/1408411)
717+ self.write_filelist("testfiles/exclude.txt")
718+ self.backup("full", "testfiles/select/1", options=["--exclude-filelist=testfiles/exclude.txt"])
719+ self.restore_and_check()
720+
721+if __name__ == "__main__":
722+ unittest.main()
723
724=== modified file 'testing/testfiles.tar.gz'
725Binary files testing/testfiles.tar.gz 2011-11-04 04:07:59 +0000 and testing/testfiles.tar.gz 2015-01-07 22:00:24 +0000 differ
726=== modified file 'testing/unit/test_selection.py'
727--- testing/unit/test_selection.py 2014-12-12 14:39:54 +0000
728+++ testing/unit/test_selection.py 2015-01-07 22:00:24 +0000
729@@ -2,6 +2,7 @@
730 #
731 # Copyright 2002 Ben Escoto <ben@emerose.org>
732 # Copyright 2007 Kenneth Loafman <kenneth@loafman.com>
733+# Copyright 2014 Aaron Whitehouse <aaron@whitehouse.kiwi.nz>
734 #
735 # This file is part of duplicity.
736 #
737@@ -27,7 +28,6 @@
738 from . import UnitTestCase
739
740
741-
742 class MatchingTest(UnitTestCase):
743 """Test matching of file names against various selection functions"""
744 def setUp(self):
745@@ -117,6 +117,70 @@
746 assert sf(self.makeext("3/3")) == 1
747 assert sf(self.makeext("3/3/3")) == None
748
749+ def test_filelist_include_1_trailing_white_space(self):
750+ """Test trailing whitespace is ignored in included filelist (1 space)"""
751+ fp = StringIO.StringIO("testfiles/select/1/2\n"
752+ "testfiles/select/1 \n"
753+ "testfiles/select/1/2/3\n"
754+ "testfiles/select/3/3/2")
755+ sf = self.Select.filelist_get_sf(fp, 1, "test")
756+ assert sf(self.root) == 1
757+ assert sf(self.makeext("1")) == 1
758+ assert sf(self.makeext("1/1")) == None
759+ assert sf(self.makeext("1/2/3")) == 1
760+ assert sf(self.makeext("2/2")) == None
761+ assert sf(self.makeext("3")) == 1
762+ assert sf(self.makeext("3/3")) == 1
763+ assert sf(self.makeext("3/3/3")) == None
764+
765+ def test_filelist_include_2_trailing_white_spaces(self):
766+ """Test trailing whitespace is ignored in included filelist (2 space)"""
767+ fp = StringIO.StringIO("testfiles/select/1/2\n"
768+ "testfiles/select/1\n"
769+ "testfiles/select/1/2/3 \n"
770+ "testfiles/select/3/3/2")
771+ sf = self.Select.filelist_get_sf(fp, 1, "test")
772+ assert sf(self.root) == 1
773+ assert sf(self.makeext("1")) == 1
774+ assert sf(self.makeext("1/1")) == None
775+ assert sf(self.makeext("1/2/3")) == 1
776+ assert sf(self.makeext("2/2")) == None
777+ assert sf(self.makeext("3")) == 1
778+ assert sf(self.makeext("3/3")) == 1
779+ assert sf(self.makeext("3/3/3")) == None
780+
781+ def test_filelist_include_1_leading_white_space(self):
782+ """Test leading whitespace is ignored in included filelist (1 space)"""
783+ fp = StringIO.StringIO(" testfiles/select/1/2\n"
784+ "testfiles/select/1\n"
785+ "testfiles/select/1/2/3\n"
786+ "testfiles/select/3/3/2")
787+ sf = self.Select.filelist_get_sf(fp, 1, "test")
788+ assert sf(self.root) == 1
789+ assert sf(self.makeext("1")) == 1
790+ assert sf(self.makeext("1/1")) == None
791+ assert sf(self.makeext("1/2/3")) == 1
792+ assert sf(self.makeext("2/2")) == None
793+ assert sf(self.makeext("3")) == 1
794+ assert sf(self.makeext("3/3")) == 1
795+ assert sf(self.makeext("3/3/3")) == None
796+
797+ def test_filelist_include_2_leading_white_spaces(self):
798+ """Test leading whitespace is ignored in included filelist (1 space)"""
799+ fp = StringIO.StringIO("testfiles/select/1/2\n"
800+ "testfiles/select/1\n"
801+ "testfiles/select/1/2/3\n"
802+ " testfiles/select/3/3/2")
803+ sf = self.Select.filelist_get_sf(fp, 1, "test")
804+ assert sf(self.root) == 1
805+ assert sf(self.makeext("1")) == 1
806+ assert sf(self.makeext("1/1")) == None
807+ assert sf(self.makeext("1/2/3")) == 1
808+ assert sf(self.makeext("2/2")) == None
809+ assert sf(self.makeext("3")) == 1
810+ assert sf(self.makeext("3/3")) == 1
811+ assert sf(self.makeext("3/3/3")) == None
812+
813 def testFilelistIncludeNullSep(self):
814 """Test included filelist but with null_separator set"""
815 fp = StringIO.StringIO("""\0testfiles/select/1/2\0testfiles/select/1\0testfiles/select/1/2/3\0testfiles/select/3/3/2\0testfiles/select/hello\nthere\0""")
816@@ -168,6 +232,42 @@
817 assert sf(self.makeext("2")) == None
818 assert sf(self.makeext("3")) == 0
819
820+ def testFilelistInclude3(self):
821+ """testFilelistInclude3 - with modifiers to check - works as expected"""
822+ fp = StringIO.StringIO("""
823+testfiles/select/1/1
824+- testfiles/select/1/2
825++ testfiles/select/1/3
826+testfiles/select/1""")
827+ sf = self.Select.filelist_get_sf(fp, 1, "test1")
828+ assert sf(self.makeext("1")) == 1
829+ assert sf(self.makeext("1/1")) == 1
830+ assert sf(self.makeext("1/1/2")) == None
831+ assert sf(self.makeext("1/2")) == 0
832+ assert sf(self.makeext("1/2/3")) == 0
833+ assert sf(self.makeext("1/3")) == 1
834+ assert sf(self.makeext("2")) == None
835+ assert sf(self.makeext("3")) == None
836+
837+# def test_filelist_include_excluded_folder_with_included_contents(self):
838+# """Check that excluded folder is included if subfolder is included at higher priority. """
839+# # ToDo - currently fails. 1/2 should be included (scanned) because 1/2/1 is. Commandline --include/--exclude
840+# # ToDo - and globbing filelists work this way
841+# fp = StringIO.StringIO("""
842+# + testfiles/select/1/2/1
843+# - testfiles/select/1/2
844+# + testfiles/select/1/3
845+# testfiles/select/1""")
846+# sf = self.Select.filelist_get_sf(fp, 1, "test1")
847+# assert sf(self.makeext("1")) == 1
848+# assert sf(self.makeext("1/1")) == None
849+# assert sf(self.makeext("1/2/1")) == 1
850+# assert sf(self.makeext("1/2")) == 0 # ToDo - what should this return?
851+# assert sf(self.makeext("1/2/3")) == 0
852+# assert sf(self.makeext("1/3")) == 1
853+# assert sf(self.makeext("2")) == None
854+# assert sf(self.makeext("3")) == None
855+
856 def testFilelistExclude2(self):
857 """testFilelistExclude2 - with modifiers"""
858 fp = StringIO.StringIO("""
859@@ -188,6 +288,123 @@
860 assert sf(self.makeext("2")) == None
861 assert sf(self.makeext("3")) == 0
862
863+ def test_filelist_exclude_2_with_trailing_white_space(self):
864+ """testFilelistExclude2 with modifiers - test trailing whitespace is ignored (1 and 2 spaces)"""
865+ fp = StringIO.StringIO("testfiles/select/1/1\n"
866+ "- testfiles/select/1/2 \n"
867+ "+ testfiles/select/1/3 \n"
868+ "- testfiles/select/3")
869+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
870+ sf_val1 = sf(self.root)
871+ assert sf_val1 == 1 or sf_val1 == None # either is OK
872+ sf_val2 = sf(self.makeext("1"))
873+ assert sf_val2 == 1 or sf_val2 == None
874+ assert sf(self.makeext("1/1")) == 0
875+ assert sf(self.makeext("1/1/2")) == 0
876+ assert sf(self.makeext("1/2")) == 0
877+ assert sf(self.makeext("1/2/3")) == 0
878+ assert sf(self.makeext("1/3")) == 1
879+ assert sf(self.makeext("2")) == None
880+ assert sf(self.makeext("3")) == 0
881+
882+ def test_filelist_exclude_with_single_quotes(self):
883+ """testFilelistExclude2 with modifiers - test unnecessary single quotes are ignored"""
884+ fp = StringIO.StringIO("testfiles/select/1/1\n"
885+ "- testfiles/select/1/2\n"
886+ "+ 'testfiles/select/1/3'\n"
887+ "- testfiles/select/3")
888+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
889+ sf_val1 = sf(self.root)
890+ assert sf_val1 == 1 or sf_val1 == None # either is OK
891+ sf_val2 = sf(self.makeext("1"))
892+ assert sf_val2 == 1 or sf_val2 == None
893+ assert sf(self.makeext("1/1")) == 0
894+ assert sf(self.makeext("1/1/2")) == 0
895+ assert sf(self.makeext("1/2")) == 0
896+ assert sf(self.makeext("1/2/3")) == 0
897+ assert sf(self.makeext("1/3")) == 1
898+ assert sf(self.makeext("2")) == None
899+ assert sf(self.makeext("3")) == 0
900+
901+ def test_filelist_exclude_with_full_line_comment(self):
902+ """testFilelistExclude2 with modifiers - test full-line comment is ignored"""
903+ fp = StringIO.StringIO("testfiles/select/1/1\n"
904+ "- testfiles/select/1/2\n"
905+ "# This is a full-line comment\n"
906+ "+ testfiles/select/1/3\n"
907+ "- testfiles/select/3")
908+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
909+ sf_val1 = sf(self.root)
910+ assert sf_val1 == 1 or sf_val1 == None # either is OK
911+ sf_val2 = sf(self.makeext("1"))
912+ assert sf_val2 == 1 or sf_val2 == None
913+ assert sf(self.makeext("1/1")) == 0
914+ assert sf(self.makeext("1/1/2")) == 0
915+ assert sf(self.makeext("1/2")) == 0
916+ assert sf(self.makeext("1/2/3")) == 0
917+ assert sf(self.makeext("1/3")) == 1
918+ assert sf(self.makeext("2")) == None
919+ assert sf(self.makeext("3")) == 0
920+
921+ def test_filelist_exclude_with_blank_line(self):
922+ """testFilelistExclude2 with modifiers - test blank line is ignored"""
923+ fp = StringIO.StringIO("testfiles/select/1/1\n"
924+ "- testfiles/select/1/2\n"
925+ "\n"
926+ "+ testfiles/select/1/3\n"
927+ "- testfiles/select/3")
928+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
929+ sf_val1 = sf(self.root)
930+ assert sf_val1 == 1 or sf_val1 == None # either is OK
931+ sf_val2 = sf(self.makeext("1"))
932+ assert sf_val2 == 1 or sf_val2 == None
933+ assert sf(self.makeext("1/1")) == 0
934+ assert sf(self.makeext("1/1/2")) == 0
935+ assert sf(self.makeext("1/2")) == 0
936+ assert sf(self.makeext("1/2/3")) == 0
937+ assert sf(self.makeext("1/3")) == 1
938+ assert sf(self.makeext("2")) == None
939+ assert sf(self.makeext("3")) == 0
940+
941+ def test_filelist_exclude_with_blank_line_and_whitespace(self):
942+ """testFilelistExclude2 with modifiers - test blank line with whitespace is ignored"""
943+ fp = StringIO.StringIO("testfiles/select/1/1\n"
944+ "- testfiles/select/1/2\n"
945+ " \n"
946+ "+ testfiles/select/1/3\n"
947+ "- testfiles/select/3")
948+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
949+ sf_val1 = sf(self.root)
950+ assert sf_val1 == 1 or sf_val1 == None # either is OK
951+ sf_val2 = sf(self.makeext("1"))
952+ assert sf_val2 == 1 or sf_val2 == None
953+ assert sf(self.makeext("1/1")) == 0
954+ assert sf(self.makeext("1/1/2")) == 0
955+ assert sf(self.makeext("1/2")) == 0
956+ assert sf(self.makeext("1/2/3")) == 0
957+ assert sf(self.makeext("1/3")) == 1
958+ assert sf(self.makeext("2")) == None
959+ assert sf(self.makeext("3")) == 0
960+
961+ def test_filelist_exclude_with_double_quotes(self):
962+ """testFilelistExclude2 with modifiers - test unnecessary double quotes are ignored"""
963+ fp = StringIO.StringIO('testfiles/select/1/1\n'
964+ '- testfiles/select/1/2\n'
965+ '+ "testfiles/select/1/3"\n'
966+ '- testfiles/select/3')
967+ sf = self.Select.filelist_get_sf(fp, 0, "test1")
968+ sf_val1 = sf(self.root)
969+ assert sf_val1 == 1 or sf_val1 == None # either is OK
970+ sf_val2 = sf(self.makeext("1"))
971+ assert sf_val2 == 1 or sf_val2 == None
972+ assert sf(self.makeext("1/1")) == 0
973+ assert sf(self.makeext("1/1/2")) == 0
974+ assert sf(self.makeext("1/2")) == 0
975+ assert sf(self.makeext("1/2/3")) == 0
976+ assert sf(self.makeext("1/3")) == 1
977+ assert sf(self.makeext("2")) == None
978+ assert sf(self.makeext("3")) == 0
979+
980 def testGlobRE(self):
981 """testGlobRE - test translation of shell pattern to regular exp"""
982 assert self.Select.glob_to_re("hello") == "hello"
983@@ -316,12 +533,154 @@
984 self.ParseTest([("--include-globbing-filelist", "file")],
985 [(), ('1',), ('1', '1'), ('1', '1', '2'),
986 ('1', '1', '3')],
987- ["""
988-- testfiles/select/1/1/1
989-testfiles/select/1/1
990-- testfiles/select/1
991-- **
992-"""])
993+ ["- testfiles/select/1/1/1\n"
994+ "testfiles/select/1/1\n"
995+ "- testfiles/select/1\n"
996+ "- **"])
997+
998+ def test_include_globbing_filelist_1_trailing_whitespace(self):
999+ """Filelist glob test similar to globbing filelist, but with 1 trailing whitespace on include"""
1000+ self.ParseTest([("--include-globbing-filelist", "file")],
1001+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1002+ ('1', '1', '3')],
1003+ ["- testfiles/select/1/1/1\n"
1004+ "testfiles/select/1/1 \n"
1005+ "- testfiles/select/1\n"
1006+ "- **"])
1007+
1008+ def test_include_globbing_filelist_2_trailing_whitespaces(self):
1009+ """Filelist glob test similar to globbing filelist, but with 2 trailing whitespaces on include"""
1010+ self.ParseTest([("--include-globbing-filelist", "file")],
1011+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1012+ ('1', '1', '3')],
1013+ ["- testfiles/select/1/1/1\n"
1014+ "testfiles/select/1/1 \n"
1015+ "- testfiles/select/1\n"
1016+ "- **"])
1017+
1018+ def test_include_globbing_filelist_1_leading_whitespace(self):
1019+ """Filelist glob test similar to globbing filelist, but with 1 leading whitespace on include"""
1020+ self.ParseTest([("--include-globbing-filelist", "file")],
1021+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1022+ ('1', '1', '3')],
1023+ ["- testfiles/select/1/1/1\n"
1024+ " testfiles/select/1/1\n"
1025+ "- testfiles/select/1\n"
1026+ "- **"])
1027+
1028+ def test_include_globbing_filelist_2_leading_whitespaces(self):
1029+ """Filelist glob test similar to globbing filelist, but with 2 leading whitespaces on include"""
1030+ self.ParseTest([("--include-globbing-filelist", "file")],
1031+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1032+ ('1', '1', '3')],
1033+ ["- testfiles/select/1/1/1\n"
1034+ " testfiles/select/1/1\n"
1035+ "- testfiles/select/1\n"
1036+ "- **"])
1037+
1038+ def test_include_globbing_filelist_1_trailing_whitespace_exclude(self):
1039+ """Filelist glob test similar to globbing filelist, but with 1 trailing whitespace on exclude"""
1040+ self.ParseTest([("--include-globbing-filelist", "file")],
1041+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1042+ ('1', '1', '3')],
1043+ ["- testfiles/select/1/1/1 \n"
1044+ "testfiles/select/1/1\n"
1045+ "- testfiles/select/1\n"
1046+ "- **"])
1047+
1048+ def test_include_globbing_filelist_2_trailing_whitespace_exclude(self):
1049+ """Filelist glob test similar to globbing filelist, but with 2 trailing whitespaces on exclude"""
1050+ self.ParseTest([("--include-globbing-filelist", "file")],
1051+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1052+ ('1', '1', '3')],
1053+ ["- testfiles/select/1/1/1 \n"
1054+ "testfiles/select/1/1\n"
1055+ "- testfiles/select/1\n"
1056+ "- **"])
1057+
1058+ def test_include_globbing_filelist_1_leading_whitespace_exclude(self):
1059+ """Filelist glob test similar to globbing filelist, but with 1 leading whitespace on exclude"""
1060+ self.ParseTest([("--include-globbing-filelist", "file")],
1061+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1062+ ('1', '1', '3')],
1063+ [" - testfiles/select/1/1/1\n"
1064+ "testfiles/select/1/1\n"
1065+ "- testfiles/select/1\n"
1066+ "- **"])
1067+
1068+ def test_include_globbing_filelist_2_leading_whitespaces_exclude(self):
1069+ """Filelist glob test similar to globbing filelist, but with 2 leading whitespaces on exclude"""
1070+ self.ParseTest([("--include-globbing-filelist", "file")],
1071+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1072+ ('1', '1', '3')],
1073+ [" - testfiles/select/1/1/1\n"
1074+ "testfiles/select/1/1\n"
1075+ "- testfiles/select/1\n"
1076+ "- **"])
1077+
1078+ def test_include_globbing_filelist_check_excluded_folder_included_for_contents(self):
1079+ """Filelist glob test to check excluded folder is included if contents are"""
1080+ self.ParseTest([("--include-globbing-filelist", "file")],
1081+ [(), ('1',), ('1', '1'), ('1', '1', '1'), ('1', '1', '2'),
1082+ ('1', '1', '3'), ('1', '2'), ('1', '2', '1'), ('1', '3'), ('1', '3', '1'), ('1', '3', '2'),
1083+ ('1', '3', '3')],
1084+ ["+ testfiles/select/1/2/1\n"
1085+ "- testfiles/select/1/2\n"
1086+ "testfiles/select/1\n"
1087+ "- **"])
1088+
1089+ def test_include_globbing_filelist_with_unnecessary_quotes(self):
1090+ """Filelist glob test similar to globbing filelist, but with quotes around one of the paths."""
1091+ self.ParseTest([("--include-globbing-filelist", "file")],
1092+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1093+ ('1', '1', '3')],
1094+ ["- 'testfiles/select/1/1/1'\n"
1095+ "testfiles/select/1/1\n"
1096+ "- testfiles/select/1\n"
1097+ "- **"])
1098+
1099+ def test_include_globbing_filelist_with_unnecessary_double_quotes(self):
1100+ """Filelist glob test similar to globbing filelist, but with double quotes around one of the paths."""
1101+ self.ParseTest([("--include-globbing-filelist", "file")],
1102+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1103+ ('1', '1', '3')],
1104+ ['- "testfiles/select/1/1/1"\n'
1105+ 'testfiles/select/1/1\n'
1106+ '- testfiles/select/1\n'
1107+ '- **'])
1108+
1109+ def test_include_globbing_filelist_with_full_line_comment(self):
1110+ """Filelist glob test similar to globbing filelist, but with a full-line comment."""
1111+ self.ParseTest([("--include-globbing-filelist", "file")],
1112+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1113+ ('1', '1', '3')],
1114+ ['- testfiles/select/1/1/1\n'
1115+ '# This is a test\n'
1116+ 'testfiles/select/1/1\n'
1117+ '- testfiles/select/1\n'
1118+ '- **'])
1119+
1120+ def test_include_globbing_filelist_with_blank_line(self):
1121+ """Filelist glob test similar to globbing filelist, but with a blank line."""
1122+ self.ParseTest([("--include-globbing-filelist", "file")],
1123+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1124+ ('1', '1', '3')],
1125+ ['- testfiles/select/1/1/1\n'
1126+ '\n'
1127+ 'testfiles/select/1/1\n'
1128+ '- testfiles/select/1\n'
1129+ '- **'])
1130+
1131+ def test_include_globbing_filelist_with_blank_line_and_whitespace(self):
1132+ """Filelist glob test similar to globbing filelist, but with a blank line and whitespace."""
1133+ self.ParseTest([("--include-globbing-filelist", "file")],
1134+ [(), ('1',), ('1', '1'), ('1', '1', '2'),
1135+ ('1', '1', '3')],
1136+ ['- testfiles/select/1/1/1\n'
1137+ ' \n'
1138+ 'testfiles/select/1/1\n'
1139+ '- testfiles/select/1\n'
1140+ '- **'])
1141
1142 def testGlob(self):
1143 """Test globbing expression"""

Subscribers

People subscribed via source and target branches