22from pathlib import Path
33from tempfile import TemporaryDirectory
44
5- from gitignore_parser import parse_gitignore
5+ from gitignore_parser import parse_gitignore , parse_gitignore_str
66
77from unittest import TestCase , main , SkipTest
88
99
1010class Test (TestCase ):
1111 def test_simple (self ):
12- matches = _parse_gitignore_string (
12+ matches = parse_gitignore_str (
1313 '__pycache__/\n '
1414 '*.py[cod]' ,
15- fake_base_dir = '/home/michael'
15+ base_dir = '/home/michael'
1616 )
1717 self .assertFalse (matches ('/home/michael/main.py' ))
1818 self .assertTrue (matches ('/home/michael/main.pyc' ))
1919 self .assertTrue (matches ('/home/michael/dir/main.pyc' ))
2020 self .assertTrue (matches ('/home/michael/__pycache__' ))
2121
22+ def test_simple_parse_file (self ):
23+ with patch ('builtins.open' , mock_open (read_data =
24+ '__pycache__/\n '
25+ '*.py[cod]' )):
26+ matches = parse_gitignore ('/home/michael/.gitignore' )
27+ self .assertFalse (matches ('/home/michael/main.py' ))
28+ self .assertTrue (matches ('/home/michael/main.pyc' ))
29+ self .assertTrue (matches ('/home/michael/dir/main.pyc' ))
30+ self .assertTrue (matches ('/home/michael/__pycache__' ))
31+
2232 def test_incomplete_filename (self ):
23- matches = _parse_gitignore_string ('o.py' , fake_base_dir = '/home/michael' )
33+ matches = parse_gitignore_str ('o.py' , base_dir = '/home/michael' )
2434 self .assertTrue (matches ('/home/michael/o.py' ))
2535 self .assertFalse (matches ('/home/michael/foo.py' ))
2636 self .assertFalse (matches ('/home/michael/o.pyc' ))
@@ -29,9 +39,9 @@ def test_incomplete_filename(self):
2939 self .assertFalse (matches ('/home/michael/dir/o.pyc' ))
3040
3141 def test_wildcard (self ):
32- matches = _parse_gitignore_string (
42+ matches = parse_gitignore_str (
3343 'hello.*' ,
34- fake_base_dir = '/home/michael'
44+ base_dir = '/home/michael'
3545 )
3646 self .assertTrue (matches ('/home/michael/hello.txt' ))
3747 self .assertTrue (matches ('/home/michael/hello.foobar/' ))
@@ -41,22 +51,22 @@ def test_wildcard(self):
4151 self .assertFalse (matches ('/home/michael/helloX' ))
4252
4353 def test_anchored_wildcard (self ):
44- matches = _parse_gitignore_string (
54+ matches = parse_gitignore_str (
4555 '/hello.*' ,
46- fake_base_dir = '/home/michael'
56+ base_dir = '/home/michael'
4757 )
4858 self .assertTrue (matches ('/home/michael/hello.txt' ))
4959 self .assertTrue (matches ('/home/michael/hello.c' ))
5060 self .assertFalse (matches ('/home/michael/a/hello.java' ))
5161
5262 def test_trailingspaces (self ):
53- matches = _parse_gitignore_string (
63+ matches = parse_gitignore_str (
5464 'ignoretrailingspace \n '
5565 'notignoredspace\\ \n '
5666 'partiallyignoredspace\\ \n '
5767 'partiallyignoredspace2 \\ \n '
5868 'notignoredmultiplespace\\ \\ \\ ' ,
59- fake_base_dir = '/home/michael'
69+ base_dir = '/home/michael'
6070 )
6171 self .assertTrue (matches ('/home/michael/ignoretrailingspace' ))
6272 self .assertFalse (matches ('/home/michael/ignoretrailingspace ' ))
@@ -73,59 +83,66 @@ def test_trailingspaces(self):
7383 self .assertFalse (matches ('/home/michael/notignoredmultiplespace' ))
7484
7585 def test_comment (self ):
76- matches = _parse_gitignore_string (
86+ matches = parse_gitignore_str (
7787 'somematch\n '
7888 '#realcomment\n '
7989 'othermatch\n '
8090 '\\ #imnocomment' ,
81- fake_base_dir = '/home/michael'
91+ base_dir = '/home/michael'
8292 )
8393 self .assertTrue (matches ('/home/michael/somematch' ))
8494 self .assertFalse (matches ('/home/michael/#realcomment' ))
8595 self .assertTrue (matches ('/home/michael/othermatch' ))
8696 self .assertTrue (matches ('/home/michael/#imnocomment' ))
8797
8898 def test_ignore_directory (self ):
89- matches = _parse_gitignore_string ('.venv/' , fake_base_dir = '/home/michael' )
99+ matches = \
100+ parse_gitignore_str ('.venv/' , base_dir = '/home/michael' )
90101 self .assertTrue (matches ('/home/michael/.venv' ))
91102 self .assertTrue (matches ('/home/michael/.venv/folder' ))
92103 self .assertTrue (matches ('/home/michael/.venv/file.txt' ))
93104 self .assertFalse (matches ('/home/michael/.venv_other_folder' ))
94105 self .assertFalse (matches ('/home/michael/.venv_no_folder.py' ))
95106
96107 def test_ignore_directory_asterisk (self ):
97- matches = _parse_gitignore_string ('.venv/*' , fake_base_dir = '/home/michael' )
108+ matches = \
109+ parse_gitignore_str ('.venv/*' , base_dir = '/home/michael' )
98110 self .assertFalse (matches ('/home/michael/.venv' ))
99111 self .assertTrue (matches ('/home/michael/.venv/folder' ))
100112 self .assertTrue (matches ('/home/michael/.venv/file.txt' ))
101113
102114 def test_negation (self ):
103- matches = _parse_gitignore_string (
115+ matches = parse_gitignore_str (
104116 '''
105117*.ignore
106118!keep.ignore
107119 ''' ,
108- fake_base_dir = '/home/michael'
120+ base_dir = '/home/michael'
109121 )
110122 self .assertTrue (matches ('/home/michael/trash.ignore' ))
111123 self .assertFalse (matches ('/home/michael/keep.ignore' ))
112124 self .assertTrue (matches ('/home/michael/waste.ignore' ))
113125
114126 def test_literal_exclamation_mark (self ):
115- matches = _parse_gitignore_string ('\\ !ignore_me!' , fake_base_dir = '/home/michael' )
127+ matches = parse_gitignore_str (
128+ '\\ !ignore_me!' , base_dir = '/home/michael'
129+ )
116130 self .assertTrue (matches ('/home/michael/!ignore_me!' ))
117131 self .assertFalse (matches ('/home/michael/ignore_me!' ))
118132 self .assertFalse (matches ('/home/michael/ignore_me' ))
119133
120134 def test_double_asterisks (self ):
121- matches = _parse_gitignore_string ('foo/**/Bar' , fake_base_dir = '/home/michael' )
135+ matches = parse_gitignore_str (
136+ 'foo/**/Bar' , base_dir = '/home/michael'
137+ )
122138 self .assertTrue (matches ('/home/michael/foo/hello/Bar' ))
123139 self .assertTrue (matches ('/home/michael/foo/world/Bar' ))
124140 self .assertTrue (matches ('/home/michael/foo/Bar' ))
125141 self .assertFalse (matches ('/home/michael/foo/BarBar' ))
126142
127143 def test_double_asterisk_without_slashes_handled_like_single_asterisk (self ):
128- matches = _parse_gitignore_string ('a/b**c/d' , fake_base_dir = '/home/michael' )
144+ matches = \
145+ parse_gitignore_str ('a/b**c/d' , base_dir = '/home/michael' )
129146 self .assertTrue (matches ('/home/michael/a/bc/d' ))
130147 self .assertTrue (matches ('/home/michael/a/bXc/d' ))
131148 self .assertTrue (matches ('/home/michael/a/bbc/d' ))
@@ -136,42 +153,50 @@ def test_double_asterisk_without_slashes_handled_like_single_asterisk(self):
136153 self .assertFalse (matches ('/home/michael/a/bb/XX/cc/d' ))
137154
138155 def test_more_asterisks_handled_like_single_asterisk (self ):
139- matches = _parse_gitignore_string ('***a/b' , fake_base_dir = '/home/michael' )
156+ matches = \
157+ parse_gitignore_str ('***a/b' , base_dir = '/home/michael' )
140158 self .assertTrue (matches ('/home/michael/XYZa/b' ))
141159 self .assertFalse (matches ('/home/michael/foo/a/b' ))
142- matches = _parse_gitignore_string ('a/b***' , fake_base_dir = '/home/michael' )
160+ matches = \
161+ parse_gitignore_str ('a/b***' , base_dir = '/home/michael' )
143162 self .assertTrue (matches ('/home/michael/a/bXYZ' ))
144163 self .assertFalse (matches ('/home/michael/a/b/foo' ))
145164
146165 def test_directory_only_negation (self ):
147- matches = _parse_gitignore_string ('''
166+ matches = parse_gitignore_str ('''
148167data/**
149168!data/**/
150169!.gitkeep
151170!data/01_raw/*
152171 ''' ,
153- fake_base_dir = '/home/michael'
172+ base_dir = '/home/michael'
154173 )
155174 self .assertFalse (matches ('/home/michael/data/01_raw/' ))
156175 self .assertFalse (matches ('/home/michael/data/01_raw/.gitkeep' ))
157176 self .assertFalse (matches ('/home/michael/data/01_raw/raw_file.csv' ))
158177 self .assertFalse (matches ('/home/michael/data/02_processed/' ))
159178 self .assertFalse (matches ('/home/michael/data/02_processed/.gitkeep' ))
160- self .assertTrue (matches ('/home/michael/data/02_processed/processed_file.csv' ))
179+ self .assertTrue (
180+ matches ('/home/michael/data/02_processed/processed_file.csv' )
181+ )
161182
162183 def test_single_asterisk (self ):
163- matches = _parse_gitignore_string ('*' , fake_base_dir = '/home/michael' )
184+ matches = parse_gitignore_str ('*' , base_dir = '/home/michael' )
164185 self .assertTrue (matches ('/home/michael/file.txt' ))
165186 self .assertTrue (matches ('/home/michael/directory' ))
166187 self .assertTrue (matches ('/home/michael/directory-trailing/' ))
167188
168189 def test_supports_path_type_argument (self ):
169- matches = _parse_gitignore_string ('file1\n !file2' , fake_base_dir = '/home/michael' )
190+ matches = parse_gitignore_str (
191+ 'file1\n !file2' , base_dir = '/home/michael'
192+ )
170193 self .assertTrue (matches (Path ('/home/michael/file1' )))
171194 self .assertFalse (matches (Path ('/home/michael/file2' )))
172195
173196 def test_slash_in_range_does_not_match_dirs (self ):
174- matches = _parse_gitignore_string ('abc[X-Z/]def' , fake_base_dir = '/home/michael' )
197+ matches = parse_gitignore_str (
198+ 'abc[X-Z/]def' , base_dir = '/home/michael'
199+ )
175200 self .assertFalse (matches ('/home/michael/abcdef' ))
176201 self .assertTrue (matches ('/home/michael/abcXdef' ))
177202 self .assertTrue (matches ('/home/michael/abcYdef' ))
@@ -180,37 +205,43 @@ def test_slash_in_range_does_not_match_dirs(self):
180205 self .assertFalse (matches ('/home/michael/abcXYZdef' ))
181206
182207 def test_symlink_to_another_directory (self ):
183- """Test the behavior of a symlink to another directory.
184-
185- The issue https://github.com/mherrmann/gitignore_parser/issues/29 describes how
186- a symlink to another directory caused an exception to be raised during matching.
187-
188- This test ensures that the issue is now fixed.
189- """
190- with TemporaryDirectory () as project_dir , TemporaryDirectory () as another_dir :
208+ with TemporaryDirectory () as project_dir :
209+ project_dir = Path (project_dir ).resolve ()
210+ with TemporaryDirectory () as another_dir :
211+ another_dir = Path (another_dir ).resolve ()
212+ matches = parse_gitignore_str ('link' , base_dir = project_dir )
213+
214+ # Create a symlink to another directory.
215+ link = project_dir / 'link'
216+ target = another_dir / 'target'
217+ try :
218+ link .symlink_to (target )
219+ except OSError :
220+ raise SkipTest (
221+ "Current user does not have permissions to perform symlink."
222+ )
223+
224+ # Check the intended behavior according to
225+ # https://git-scm.com/docs/gitignore#_notes:
226+ # Symbolic links are not followed and are matched as if they
227+ # were regular files.
228+ self .assertTrue (matches (link ))
229+
230+ def test_symlink_to_symlink_directory (self ):
231+ with TemporaryDirectory () as project_dir :
191232 project_dir = Path (project_dir ).resolve ()
192- another_dir = Path (another_dir ).resolve ()
193- matches = _parse_gitignore_string ('link' , fake_base_dir = project_dir )
194-
195- # Create a symlink to another directory.
196- link = project_dir / 'link'
197- target = another_dir / 'target'
198-
199- try :
200- link .symlink_to (target )
201- except OSError :
202- e = "Current user does not have permissions to perform symlink."
203- raise SkipTest (e )
204- # Check the intended behavior according to
205- # https://git-scm.com/docs/gitignore#_notes:
206- # Symbolic links are not followed and are matched as if they were regular
207- # files.
208- self .assertTrue (matches (link ))
209-
210- def _parse_gitignore_string (data : str , fake_base_dir : str = None ):
211- with patch ('builtins.open' , mock_open (read_data = data )):
212- success = parse_gitignore (f'{ fake_base_dir } /.gitignore' , fake_base_dir )
213- return success
233+ with TemporaryDirectory () as link_dir :
234+ link_dir = link_dir .resolve ()
235+ link = link_dir / 'link'
236+ try :
237+ link .symlink_to (project_dir )
238+ except OSError :
239+ raise SkipTest (
240+ "Current user does not have permissions to perform symlink."
241+ )
242+ file = Path (link , 'file.txt' )
243+ matches = parse_gitignore_str ('file.txt' , base_dir = str (link_dir ))
244+ self .assertTrue (matches (file ))
214245
215246if __name__ == '__main__' :
216247 main ()
0 commit comments