| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- # test_ignore.py -- tests for porcelain ignore (check_ignore)
- # Copyright (C) 2017 Jelmer Vernooij <jelmer@jelmer.uk>
- #
- # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
- # General Public License as published by the Free Software Foundation; version 2.0
- # or (at your option) any later version. You can redistribute it and/or
- # modify it under the terms of either of these two licenses.
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # You should have received a copy of the licenses; if not, see
- # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
- # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
- # License, Version 2.0.
- #
- """Tests for porcelain ignore (check_ignore) functions."""
- import os
- import shutil
- import tempfile
- from dulwich.porcelain import _quote_path, check_ignore
- from dulwich.repo import Repo
- from .. import TestCase
- class CheckIgnoreQuotePathTests(TestCase):
- """Integration tests for check_ignore with quote_path parameter."""
- def setUp(self) -> None:
- self.test_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, self.test_dir)
- def test_quote_path_true_unicode_filenames(self) -> None:
- """Test that quote_path=True returns quoted unicode filenames."""
- # Create a repository
- repo = Repo.init(self.test_dir)
- self.addCleanup(repo.close)
- # Create .gitignore with unicode patterns
- gitignore_path = os.path.join(self.test_dir, ".gitignore")
- with open(gitignore_path, "w", encoding="utf-8") as f:
- f.write("тест*\n")
- f.write("*.测试\n")
- # Create unicode files
- test_files = ["тест.txt", "файл.测试", "normal.txt"]
- for filename in test_files:
- filepath = os.path.join(self.test_dir, filename)
- with open(filepath, "w", encoding="utf-8") as f:
- f.write("test content")
- # Test with quote_path=True (default)
- abs_paths = [os.path.join(self.test_dir, f) for f in test_files]
- ignored_quoted = set(check_ignore(self.test_dir, abs_paths, quote_path=True))
- # Test with quote_path=False
- ignored_unquoted = set(check_ignore(self.test_dir, abs_paths, quote_path=False))
- # Verify quoted results
- expected_quoted = {
- '"\\321\\202\\320\\265\\321\\201\\321\\202.txt"', # тест.txt
- '"\\321\\204\\320\\260\\320\\271\\320\\273.\\346\\265\\213\\350\\257\\225"', # файл.测试
- }
- self.assertEqual(ignored_quoted, expected_quoted)
- # Verify unquoted results
- expected_unquoted = {"тест.txt", "файл.测试"}
- self.assertEqual(ignored_unquoted, expected_unquoted)
- def test_quote_path_ascii_filenames(self) -> None:
- """Test that ASCII filenames are unaffected by quote_path setting."""
- # Create a repository
- repo = Repo.init(self.test_dir)
- self.addCleanup(repo.close)
- # Create .gitignore
- gitignore_path = os.path.join(self.test_dir, ".gitignore")
- with open(gitignore_path, "w") as f:
- f.write("*.tmp\n")
- f.write("test*\n")
- # Create ASCII files
- test_files = ["test.txt", "file.tmp", "normal.txt"]
- for filename in test_files:
- filepath = os.path.join(self.test_dir, filename)
- with open(filepath, "w") as f:
- f.write("test content")
- # Test both settings
- abs_paths = [os.path.join(self.test_dir, f) for f in test_files]
- ignored_quoted = set(check_ignore(self.test_dir, abs_paths, quote_path=True))
- ignored_unquoted = set(check_ignore(self.test_dir, abs_paths, quote_path=False))
- # Both should return the same results for ASCII filenames
- expected = {"test.txt", "file.tmp"}
- self.assertEqual(ignored_quoted, expected)
- self.assertEqual(ignored_unquoted, expected)
- class QuotePathTests(TestCase):
- """Tests for _quote_path function."""
- def test_ascii_paths(self) -> None:
- """Test that ASCII paths are not quoted."""
- self.assertEqual(_quote_path("file.txt"), "file.txt")
- self.assertEqual(_quote_path("dir/file.txt"), "dir/file.txt")
- self.assertEqual(_quote_path("path with spaces.txt"), "path with spaces.txt")
- def test_unicode_paths(self) -> None:
- """Test that unicode paths are quoted with C-style escapes."""
- # Russian characters
- self.assertEqual(
- _quote_path("тест.txt"), '"\\321\\202\\320\\265\\321\\201\\321\\202.txt"'
- )
- # Chinese characters
- self.assertEqual(
- _quote_path("файл.测试"),
- '"\\321\\204\\320\\260\\320\\271\\320\\273.\\346\\265\\213\\350\\257\\225"',
- )
- # Mixed ASCII and unicode
- self.assertEqual(
- _quote_path("test-тест.txt"),
- '"test-\\321\\202\\320\\265\\321\\201\\321\\202.txt"',
- )
- def test_special_characters(self) -> None:
- """Test that special characters are properly escaped."""
- # Quotes in filename
- self.assertEqual(
- _quote_path('file"with"quotes.txt'), '"file\\"with\\"quotes.txt"'
- )
- # Backslashes in filename
- self.assertEqual(
- _quote_path("file\\with\\backslashes.txt"),
- '"file\\\\with\\\\backslashes.txt"',
- )
- # Mixed special chars and unicode
- self.assertEqual(
- _quote_path('тест"файл.txt'),
- '"\\321\\202\\320\\265\\321\\201\\321\\202\\"\\321\\204\\320\\260\\320\\271\\320\\273.txt"',
- )
- def test_empty_and_edge_cases(self) -> None:
- """Test edge cases."""
- self.assertEqual(_quote_path(""), "")
- self.assertEqual(_quote_path("a"), "a") # Single ASCII char
- self.assertEqual(_quote_path("я"), '"\\321\\217"') # Single unicode char
|