From 7e24bff5a9b71eeffe22e99cd64b1245bba92ce1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 27 Jan 2025 20:18:37 +0200 Subject: [PATCH 1/3] gh-129350: Make tests for glob with trailing slash more strict Test that the trailing pathname separator is preserved. Multiple trailing pathname separators are only preserved if the pattern does not contain metacharacters, otherwise only one trailing pathname separator is preserved. This is rather an implementation detail. --- Lib/test/test_glob.py | 61 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index 1a836e34e8712f..b27ab5abe992a6 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -171,37 +171,41 @@ def test_glob_directory_names(self): self.norm('aab', 'F')]) def test_glob_directory_with_trailing_slash(self): - # Patterns ending with a slash shouldn't match non-dirs - res = glob.glob(self.norm('Z*Z') + os.sep) - self.assertEqual(res, []) - res = glob.glob(self.norm('ZZZ') + os.sep) - self.assertEqual(res, []) - # When there is a wildcard pattern which ends with os.sep, glob() - # doesn't blow up. - res = glob.glob(self.norm('aa*') + os.sep) - self.assertEqual(len(res), 2) - # either of these results is reasonable - self.assertIn(set(res), [ - {self.norm('aaa'), self.norm('aab')}, - {self.norm('aaa') + os.sep, self.norm('aab') + os.sep}, - ]) + seps = (os.sep, os.altsep) if os.altsep else (os.sep,) + for sep in seps: + # Patterns ending with a slash shouldn't match non-dirs + self.assertEqual(glob.glob(self.norm('Z*Z') + sep), []) + self.assertEqual(glob.glob(self.norm('ZZZ') + sep), []) + self.assertEqual(glob.glob(self.norm('aaa') + sep), + [self.norm('aaa') + sep]) + self.assertEqual(glob.glob(self.norm('aaa') + sep*2), + [self.norm('aaa') + sep*2]) + # When there is a wildcard pattern which ends with a pathname + # separator, glob() doesn't blow up. + eq = self.assertSequencesEqual_noorder + eq(glob.glob(self.norm('aa*') + sep), + [self.norm('aaa') + sep, self.norm('aab') + sep]) + eq(glob.glob(self.norm('aa*') + sep*2), + [self.norm('aaa') + sep, self.norm('aab') + sep]) def test_glob_bytes_directory_with_trailing_slash(self): # Same as test_glob_directory_with_trailing_slash, but with a # bytes argument. - res = glob.glob(os.fsencode(self.norm('Z*Z') + os.sep)) - self.assertEqual(res, []) - res = glob.glob(os.fsencode(self.norm('ZZZ') + os.sep)) - self.assertEqual(res, []) - res = glob.glob(os.fsencode(self.norm('aa*') + os.sep)) - self.assertEqual(len(res), 2) - # either of these results is reasonable - self.assertIn(set(res), [ - {os.fsencode(self.norm('aaa')), - os.fsencode(self.norm('aab'))}, - {os.fsencode(self.norm('aaa') + os.sep), - os.fsencode(self.norm('aab') + os.sep)}, - ]) + seps = (os.sep, os.altsep) if os.altsep else (os.sep,) + for sep in seps: + self.assertEqual(glob.glob(os.fsencode(self.norm('Z*Z') + sep)), []) + self.assertEqual(glob.glob(os.fsencode(self.norm('ZZZ') + sep)), []) + self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep)), + [os.fsencode(self.norm('aaa') + sep)]) + self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep*2)), + [os.fsencode(self.norm('aaa') + sep*2)]) + eq = self.assertSequencesEqual_noorder + eq(glob.glob(os.fsencode(self.norm('aa*') + sep)), + [os.fsencode(self.norm('aaa') + sep), + os.fsencode(self.norm('aab') + sep)]) + eq(glob.glob(os.fsencode(self.norm('aa*') + sep*2)), + [os.fsencode(self.norm('aaa') + sep), + os.fsencode(self.norm('aab') + sep)]) @skip_unless_symlink def test_glob_symlinks(self): @@ -209,8 +213,7 @@ def test_glob_symlinks(self): eq(self.glob('sym3'), [self.norm('sym3')]) eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'), self.norm('sym3', 'efg')]) - self.assertIn(self.glob('sym3' + os.sep), - [[self.norm('sym3')], [self.norm('sym3') + os.sep]]) + eq(self.glob('sym3' + os.sep), [self.norm('sym3') + os.sep]) eq(self.glob('*', '*F'), [self.norm('aaa', 'zzzF'), self.norm('aab', 'F'), self.norm('sym3', 'EF')]) From ec845a728e5dda2243b1720315b1d06f6f37fb8b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 28 Jan 2025 15:23:12 +0200 Subject: [PATCH 2/3] Clarify what checks are for implementation details. --- Lib/test/test_glob.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index b27ab5abe992a6..604efee1f84d8f 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -178,13 +178,16 @@ def test_glob_directory_with_trailing_slash(self): self.assertEqual(glob.glob(self.norm('ZZZ') + sep), []) self.assertEqual(glob.glob(self.norm('aaa') + sep), [self.norm('aaa') + sep]) + # Preserving the redundant separators is an implementation detail. self.assertEqual(glob.glob(self.norm('aaa') + sep*2), [self.norm('aaa') + sep*2]) # When there is a wildcard pattern which ends with a pathname - # separator, glob() doesn't blow up. + # separator, glob() doesn't blow up and preserves the trailing + # separator. eq = self.assertSequencesEqual_noorder eq(glob.glob(self.norm('aa*') + sep), [self.norm('aaa') + sep, self.norm('aab') + sep]) + # Stripping the redundant separators is an implementation detail. eq(glob.glob(self.norm('aa*') + sep*2), [self.norm('aaa') + sep, self.norm('aab') + sep]) From 264ddd51ae43698e44f73fd1b900910de51bb670 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 28 Jan 2025 16:03:35 +0200 Subject: [PATCH 3/3] Fix test on Windows. --- Lib/test/test_glob.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index 604efee1f84d8f..a45b30599d5309 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -182,14 +182,15 @@ def test_glob_directory_with_trailing_slash(self): self.assertEqual(glob.glob(self.norm('aaa') + sep*2), [self.norm('aaa') + sep*2]) # When there is a wildcard pattern which ends with a pathname - # separator, glob() doesn't blow up and preserves the trailing - # separator. + # separator, glob() doesn't blow. + # The result should end with the pathname separator. + # Normalizing the trailing separator is an implementation detail. eq = self.assertSequencesEqual_noorder eq(glob.glob(self.norm('aa*') + sep), - [self.norm('aaa') + sep, self.norm('aab') + sep]) + [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) # Stripping the redundant separators is an implementation detail. eq(glob.glob(self.norm('aa*') + sep*2), - [self.norm('aaa') + sep, self.norm('aab') + sep]) + [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) def test_glob_bytes_directory_with_trailing_slash(self): # Same as test_glob_directory_with_trailing_slash, but with a @@ -204,11 +205,11 @@ def test_glob_bytes_directory_with_trailing_slash(self): [os.fsencode(self.norm('aaa') + sep*2)]) eq = self.assertSequencesEqual_noorder eq(glob.glob(os.fsencode(self.norm('aa*') + sep)), - [os.fsencode(self.norm('aaa') + sep), - os.fsencode(self.norm('aab') + sep)]) + [os.fsencode(self.norm('aaa') + os.sep), + os.fsencode(self.norm('aab') + os.sep)]) eq(glob.glob(os.fsencode(self.norm('aa*') + sep*2)), - [os.fsencode(self.norm('aaa') + sep), - os.fsencode(self.norm('aab') + sep)]) + [os.fsencode(self.norm('aaa') + os.sep), + os.fsencode(self.norm('aab') + os.sep)]) @skip_unless_symlink def test_glob_symlinks(self):