← Back to team overview

duplicity-team team mailing list archive

[Merge] lp:~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch into lp:duplicity

 

Aaron Whitehouse has proposed merging lp:~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch into lp:duplicity.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch/+merge/316397

* Rename path_matches_glob_fn to select_fn_from_glob, as this more accurately reflects the return value.
* Significantly refactored unit/test_globmatch.py to make this cleaner and clearer.
-- 
Your team duplicity-team is requested to review the proposed merge of lp:~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch into lp:duplicity.
=== modified file 'duplicity/globmatch.py'
--- duplicity/globmatch.py	2017-01-29 18:11:52 +0000
+++ duplicity/globmatch.py	2017-02-05 01:16:14 +0000
@@ -49,7 +49,7 @@
     return list(map(glob_to_regex, prefixes))
 
 
-def path_matches_glob_fn(glob_str, include, ignore_case=False):
+def select_fn_from_glob(glob_str, include, ignore_case=False):
     """Return a function test_fn(path) which
     tests whether path matches glob, as per the Unix shell rules, taking as
     arguments a path, a glob string and include (0 indicating that the glob
@@ -143,7 +143,7 @@
     """Returned regular expression equivalent to shell glob pat
 
     Currently only the ?, *, [], and ** expressions are supported.
-    Ranges like [a-z] are also currently unsupported.  There is no
+    Ranges like [a-z] are currently unsupported.  There is no
     way to quote these special characters.
 
     This function taken with minor modifications from efnmatch.py

=== modified file 'duplicity/selection.py'
--- duplicity/selection.py	2017-01-29 19:03:45 +0000
+++ duplicity/selection.py	2017-02-05 01:16:14 +0000
@@ -33,7 +33,7 @@
 from duplicity import diffdir
 from duplicity import util  # @Reimport
 from duplicity.globmatch import GlobbingError, FilePrefixError, \
-    path_matches_glob_fn
+    select_fn_from_glob
 
 """Iterate exactly the requested files in a directory
 
@@ -501,13 +501,13 @@
 
         # Check to make sure prefix is ok, i.e. the glob string is within
         # the root folder being backed up
-        file_prefix_selection = path_matches_glob_fn(glob_str, include=1)(self.rootpath)
+        file_prefix_selection = select_fn_from_glob(glob_str, include=1)(self.rootpath)
         if not file_prefix_selection:
             # file_prefix_selection == 1 (include) or 2 (scan)
             raise FilePrefixError(glob_str + " glob with " + self.rootpath.name +
                                   " path gives " + str(file_prefix_selection))
 
-        return path_matches_glob_fn(glob_str, include, ignore_case)
+        return select_fn_from_glob(glob_str, include, ignore_case)
 
     def exclude_older_get_sf(self, date):
         """Return selection function based on files older than modification date """

=== modified file 'testing/unit/test_globmatch.py'
--- testing/unit/test_globmatch.py	2017-01-29 18:11:52 +0000
+++ testing/unit/test_globmatch.py	2017-02-05 01:16:14 +0000
@@ -20,75 +20,93 @@
 # along with duplicity; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-import sys
 from duplicity.globmatch import *
 from duplicity.path import *
 from . import UnitTestCase
 from mock import patch
-import unittest
-
-
-class MatchingTest(UnitTestCase):
-    """Test matching of file names against various selection functions"""
-
-    def test_glob_re(self):
+
+
+def sel_file(glob_str, include, file_path):
+    """Returns the selection value for file_path, given the include value,
+    returning:
+    0 - if the file should be excluded
+    1 - if the file should be included
+    2 - if the folder should be scanned for any included/excluded files
+    None - if the selection function has nothing to say about the file
+
+    Note: including a folder implicitly includes everything within it."""
+
+    select_fn = select_fn_from_glob(glob_str, include)
+    selection_value = select_fn(Path(file_path))
+    return selection_value
+
+
+def inc_sel_file(glob_str, file_path):
+    """Returns result of sel_file with include value set to 1"""
+    # Aids readability of the testing code to only have one number (the
+    # result of the select function)
+    return sel_file(glob_str, 1, file_path)
+
+
+def exc_sel_file(glob_str, file_path):
+    """Returns result of sel_file with include value set to 0"""
+    return sel_file(glob_str, 0, file_path)
+
+
+def sel_dir(glob_str, include, file_path):
+    """As per sel_file, but mocks file_path to be a directory"""
+    with patch('duplicity.path.Path.isdir') as mock_isdir:
+        mock_isdir.return_value = True
+        return sel_file(glob_str, include, file_path)
+
+
+def inc_sel_dir(glob_str, file_path):
+    """Returns result of sel_dir with include value set to 1"""
+    return sel_dir(glob_str, 1, file_path)
+
+
+def exc_sel_dir(glob_str, file_path):
+    """Returns result of sel_dir with include value set to 0"""
+    return sel_dir(glob_str, 0, file_path)
+
+
+class TestGlobToRegex(UnitTestCase):
+    """Test translation of glob strings into regular expressions"""
+
+    def test_glob_to_regex(self):
         """test_glob_re - test translation of shell pattern to regular exp"""
-        assert glob_to_regex("hello") == "hello"
-        assert glob_to_regex(".e?ll**o") == "\\.e[^/]ll.*o"
-        r = glob_to_regex("[abc]el[^de][!fg]h")
-        assert r == "[abc]el[^de][^fg]h", r
-        r = glob_to_regex("/usr/*/bin/")
-        assert r == "\\/usr\\/[^/]*\\/bin\\/", r
-        assert glob_to_regex("[a.b/c]") == "[a.b/c]"
-        r = glob_to_regex("[a*b-c]e[!]]")
-        assert r == "[a*b-c]e[^]]", r
-
-
-class TestMiscellaneousGlobMatching(UnitTestCase):
-    """Test various glob matching"""
+        self.assertEqual(glob_to_regex("hello"), "hello")
+        self.assertEqual(glob_to_regex(".e?ll**o"), "\\.e[^/]ll.*o")
+        self.assertEqual(glob_to_regex("[abc]el[^de][!fg]h"),
+                         "[abc]el[^de][^fg]h")
+        self.assertEqual(glob_to_regex("/usr/*/bin/"),
+                         "\\/usr\\/[^/]*\\/bin\\/")
+        self.assertEqual(glob_to_regex("[a.b/c]"), "[a.b/c]")
+        self.assertEqual(glob_to_regex("[a*b-c]e[!]]"), "[a*b-c]e[^]]")
+
+
+class TestSelectValuesFromGlobs(UnitTestCase):
+    """Test the select values returned from various globs"""
 
     def test_glob_scans_parent_directories(self):
         """Test glob scans parent"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            # Note: paths ending in '/' do not work!
-            # self.assertEqual(
-            #     path_matches_glob_fn("testfiles/parent/sub/", 1)(Path(
-            #         "testfiles/parent/")), 2)
-            self.assertEqual(
-                path_matches_glob_fn("testfiles/parent/sub", 1)(Path(
-                    "testfiles/parent")), 2)
-            self.assertEqual(
-                path_matches_glob_fn("testfiles/select2/3/3sub2", 1)(Path(
-                "testfiles/select2/3")), 2)
-
-
-class TestDoubleAsteriskOnIncludesExcludes(UnitTestCase):
-    """Test ** on includes and exclude patterns"""
+        self.assertEqual(
+            inc_sel_dir("testfiles/parent/sub", "testfiles/parent"), 2)
+        self.assertEqual(
+            inc_sel_dir("testfiles/select2/3/3sub2", "testfiles/select2/3"), 2)
 
     def test_double_asterisk_include(self):
         """Test a few globbing patterns, including **"""
-        self.assertEqual(
-            path_matches_glob_fn("**", 1)(Path("foo.txt")), 1)
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("**", 1)(Path("folder")), 1)
+        self.assertEqual(inc_sel_file("**", "foo.txt"), 1)
+        self.assertEqual(inc_sel_dir("**", "folder"), 1)
 
     def test_double_asterisk_extension_include(self):
         """Test **.py"""
-        self.assertEqual(
-            path_matches_glob_fn("**.py", 1)(Path("what/ever.py")), 1)
-        self.assertEqual(
-            path_matches_glob_fn("**.py", 1)(Path("what/ever.py/foo")), 1)
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("**.py", 1)(Path("foo")), 2)
-            self.assertEqual(
-                path_matches_glob_fn("**.py", 1)(Path("usr/local/bin")), 2)
-            self.assertEqual(
-                path_matches_glob_fn("**.py", 1)(Path("/usr/local/bin")), 2)
+        self.assertEqual(inc_sel_file("**.py", "what/ever.py"), 1)
+        self.assertEqual(inc_sel_file("**.py", "what/ever.py/foo"), 1)
+        self.assertEqual(inc_sel_dir("**.py", "foo"), 2)
+        self.assertEqual(inc_sel_dir("**.py", "usr/local/bin"), 2)
+        self.assertEqual(inc_sel_dir("**.py", "/usr/local/bin"), 2)
 
 
 class TestTrailingSlash(UnitTestCase):
@@ -96,175 +114,116 @@
 
     def test_trailing_slash_matches_only_dirs(self):
         """Test matching where glob includes a trailing slash"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("fold*/", 1)(Path("folder")), 1)
-
-            # Test the file named "folder" is not included if it is not a dir
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("fold*/", 1)(Path("folder")), None)
-
-            # Test the file named "folder" is not included if it is not a dir
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("folder/", 1)(Path("folder")), None)
-
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("fo*/", 1)(Path("foo.txt")), None)
+        # Test the folder named "folder" is included
+        self.assertEqual(inc_sel_dir("fold*/", "folder"), 1)
+
+        # Test the file (not folder) named "folder" is not included
+        self.assertEqual(inc_sel_file("fold*/", "folder"), None)
+        self.assertEqual(inc_sel_file("folder/", "folder"), None)
+
+        # Test miscellaneous file/folder
+        self.assertEqual(inc_sel_file("fo*/", "foo.txt"), None)
 
     def test_included_files_are_matched_no_slash(self):
         """Test that files within an included folder are matched"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("fold*", 1)(Path("folder/file.txt")), 1)
-
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("fold*", 1)(Path("folder/2/file.txt")), 1)
+        self.assertEqual(inc_sel_file("fold*", "folder/file.txt"), 1)
+        self.assertEqual(inc_sel_file("fold*", "folder/file.txt"), 1)
+        self.assertEqual(inc_sel_file("fold*", "folder/2/file.txt"), 1)
 
     def test_included_files_are_matched_no_slash_2(self):
         """Test that files within an included folder are matched"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("folder", 1)(Path("folder/file.txt")), 1)
-
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("folder/2", 1)(Path("folder/2/file.txt")), 1)
+        self.assertEqual(inc_sel_file("folder", "folder/file.txt"), 1)
+        self.assertEqual(inc_sel_file("folder/2", "folder/2/file.txt"), 1)
 
     def test_included_files_are_matched_slash(self):
         """Test that files within an included folder are matched with /"""
         # Bug #1624725
         # https://bugs.launchpad.net/duplicity/+bug/1624725
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("folder/", 1)(Path("folder/file.txt")), 1)
+        self.assertEqual(inc_sel_file("folder/", "folder/file.txt"), 1)
 
     def test_included_files_are_matched_slash_2(self):
         """Test that files within an included folder are matched with /"""
         # Bug #1624725
         # https://bugs.launchpad.net/duplicity/+bug/1624725
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1)
-                (Path("testfiles/select2/1/1sub1/1sub1sub1/1sub1sub1_file.txt")
-                 ), 1)
+        self.assertEqual(inc_sel_file(
+            "testfiles/select2/1/1sub1/1sub1sub1/",
+            "testfiles/select2/1/1sub1/1sub1sub1/1sub1sub1_file.txt"), 1)
 
     def test_included_files_are_matched_slash_2_parents(self):
         """Test that duplicity will scan parent of glob/"""
         # Bug #1624725
         # https://bugs.launchpad.net/duplicity/+bug/1624725
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1)
-                (Path("testfiles/select2/1/1sub1/1sub1sub1")
-                 ), 1)
-            self.assertEqual(
-                path_matches_glob_fn("testfiles/select2/1/1sub1/1sub1sub1/", 1)
-                (Path("testfiles/select2/1/1sub1")
-                 ), 2)
+        self.assertEqual(inc_sel_dir(
+            "testfiles/select2/1/1sub1/1sub1sub1/",
+            "testfiles/select2/1/1sub1/1sub1sub1"), 1)
+        self.assertEqual(inc_sel_dir(
+            "testfiles/select2/1/1sub1/1sub1sub1/",
+            "testfiles/select2/1/1sub1"), 2)
 
     def test_included_files_are_matched_slash_wildcard(self):
         """Test that files within an included folder are matched with /"""
         # Bug #1624725
         # https://bugs.launchpad.net/duplicity/+bug/1624725
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = False
-            self.assertEqual(
-                path_matches_glob_fn("fold*/", 1)(Path("folder/file.txt")), 1)
+        self.assertEqual(inc_sel_file("fold*/", "folder/file.txt"), 1)
 
     def test_slash_matches_everything(self):
         """Test / matches everything"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("/",
-                                     1)(Path("/tmp/testfiles/select/1/2")), 1)
-            self.assertEqual(
-                path_matches_glob_fn("/",
-                                     1)(Path("/test/random/path")), 1)
-            self.assertEqual(
-                path_matches_glob_fn("/",
-                                     1)(Path("/")), 1)
-            self.assertEqual(
-                path_matches_glob_fn("/",
-                                     1)(Path("/var/log")), 1)
-            self.assertEqual(
-                path_matches_glob_fn("/",
-                                     1)(Path("/var/log/log.txt")), 1)
+        self.assertEqual(inc_sel_dir("/", "/tmp/testfiles/select/1/2"), 1)
+        self.assertEqual(inc_sel_dir("/", "/test/random/path"), 1)
+        self.assertEqual(exc_sel_dir("/", "/test/random/path"), 0)
+        self.assertEqual(inc_sel_dir("/", "/"), 1)
+        self.assertEqual(inc_sel_dir("/", "/var/log"), 1)
+        self.assertEqual(inc_sel_file("/", "/var/log/log.txt"), 1)
 
     def test_slash_star_scans_folder(self):
         """Test that folder/* scans folder/"""
         # This behaviour is a bit ambiguous - either include or scan could be
         # argued as most appropriate here, but only an empty folder is at stake
         # so long as test_slash_star_includes_folder_contents passes.
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("folder/*", 1)(Path("folder")), 2)
+        self.assertEqual(inc_sel_dir("folder/*", "folder"), 2)
 
     def test_slash_star_includes_folder_contents(self):
         """Test that folder/* includes folder contents"""
-        self.assertEqual(path_matches_glob_fn("folder/*", 1)
-                         (Path("folder/file.txt")), 1)
-        self.assertEqual(path_matches_glob_fn("folder/*", 1)
-                         (Path("folder/other_file.log")), 1)
+        self.assertEqual(inc_sel_file("folder/*", "folder/file.txt"), 1)
+        self.assertEqual(inc_sel_file("folder/*", "folder/other_file.log"), 1)
 
-    def test_slash_star_star_includes_folder(self):
-        """Test that folder/** includes folder/"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
+    def test_slash_star_star_scans_folder(self):
+        """Test that folder/** scans folder/"""
+        self.assertEqual(inc_sel_dir("folder/**", "folder"), 2)
 
     def test_simple_trailing_slash_match(self):
         """Test that a normal folder string ending in / matches that path"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            test_path = "testfiles/select/1/2/1"
-            self.assertEqual(
-                path_matches_glob_fn(test_path, 1)(Path(test_path)), 1)
+        self.assertEqual(inc_sel_dir("testfiles/select/1/2/1/",
+                                     "testfiles/select/1/2/1"), 1)
 
     def test_double_asterisk_string_slash(self):
         """Test string starting with ** and ending in /"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("**/1/2/",
-                                     1)(Path("testfiles/select/1/2")), 1)
+        self.assertEqual(inc_sel_dir("**/1/2/", "testfiles/select/1/2"), 1)
 
     def test_string_double_asterisk_string_slash(self):
         """Test string ** string /"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("testfiles**/2/",
-                                     1)(Path("testfiles/select/1/2")), 1)
+        self.assertEqual(inc_sel_dir("testfiles**/2/",
+                                     "testfiles/select/1/2"), 1)
 
 
 class TestDoubleAsterisk(UnitTestCase):
     """Test glob matching where the glob finishes with a **"""
 
-    def test_simple_trailing_slash_match(self):
+    def test_double_asterisk_no_match(self):
+        """Test that a folder string ending /** does not match other paths"""
+        self.assertEqual(inc_sel_dir("/test/folder/**", "/test/foo"), None)
+
+    def test_double_asterisk_match(self):
         """Test that a folder string ending in /** matches that path"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("/test/folder/**", 1)(
-                    Path("/test/foo")), None)
+        self.assertEqual(inc_sel_dir("/test/folder/**",
+                                     "/test/folder/foo"), 1)
+        self.assertEqual(inc_sel_file("/test/folder/**",
+                                      "/test/folder/foo.txt"), 1)
+        self.assertEqual(inc_sel_dir("/test/folder/**",
+                                     "/test/folder/2/foo"), 1)
+        self.assertEqual(inc_sel_file("/test/folder/**",
+                                      "/test/folder/2/foo.txt"), 1)
 
-    def test_simple_trailing_slash_match_2(self):
+    def test_asterisk_slash_double_asterisk(self):
         """Test folder string ending in */**"""
-        with patch('duplicity.path.Path.isdir') as mock_isdir:
-            mock_isdir.return_value = True
-            self.assertEqual(
-                path_matches_glob_fn("fold*/**", 1)(
-                    Path("folder")), 2)
\ No newline at end of file
+        self.assertEqual(inc_sel_dir("fold*/**", "folder"), 2)


Follow ups