77from flake8_no_emoji .checker import NoEmojiChecker
88
99
10- def run_checker_on_content (content , ignore_emoji_types = None , only_emoji_types = None ):
11- """Write content to temp file, set options, run checker, return results."""
12- fd , path = tempfile .mkstemp (suffix = ".py" , text = True )
10+ def run_checker_on_content (content , ignore_emoji_types = None , only_emoji_types = None , filename = None ):
11+ """
12+ Write content to a temp file (if filename not provided), set options, run checker, return results.
13+ Allows passing a real file path for special cases like unreadable or binary files.
14+ """
15+ if filename is None :
16+ fd , path = tempfile .mkstemp (suffix = ".py" , text = True )
17+ else :
18+ path = filename
19+
1320 try :
14- with os .fdopen (fd , "w" , encoding = "utf-8" ) as f :
15- f .write (content )
21+ if filename is None :
22+ with os .fdopen (fd , "w" , encoding = "utf-8" ) as f :
23+ f .write (content )
1624
1725 opts = SimpleNamespace (
1826 ignore_emoji_types = (ignore_emoji_types or "" ),
@@ -24,10 +32,11 @@ def run_checker_on_content(content, ignore_emoji_types=None, only_emoji_types=No
2432 checker ._only_categories = NoEmojiChecker ._only_categories
2533 return list (checker .run ())
2634 finally :
27- try :
28- os .unlink (path )
29- except OSError :
30- pass
35+ if filename is None :
36+ try :
37+ os .unlink (path )
38+ except OSError :
39+ pass
3140
3241
3342def test_detect_any_emoji_by_default ():
@@ -181,3 +190,159 @@ def test_multiple_lines_with_only_emojis():
181190 content = "😀\n 🐶\n ⭐\n 🛸\n 👩💻"
182191 results = run_checker_on_content (content )
183192 assert len (results ) == 5 , "Each line with single emoji should be detected"
193+
194+
195+ def test_empty_file ():
196+ results = run_checker_on_content ("" )
197+ assert results == [], "Empty file should produce no results"
198+
199+
200+ def test_empty_comment ():
201+ results = run_checker_on_content ("# " )
202+ assert results == [], "Empty comment should produce no results"
203+
204+
205+ def test_unreadable_file (tmp_path ):
206+ path = tmp_path / "unreadable.py"
207+ path .write_text ("x = '😀'" )
208+ os .chmod (path , 0 ) # remove permissions
209+ results = run_checker_on_content ("" , filename = str (path ))
210+ assert results == [], "Unreadable file should produce no results"
211+ os .chmod (path , 0o644 )
212+
213+
214+ def test_binary_file (tmp_path ):
215+ path = tmp_path / "binary.bin"
216+ path .write_bytes (b"\x00 \x01 \x02 \x03 \x04 " )
217+ results = run_checker_on_content ("" , filename = str (path ))
218+ assert results == [], "Binary file should produce no results"
219+
220+
221+ def test_disable_all_checks ():
222+ # simulate ignoring all categories
223+ results = run_checker_on_content ("x = '😀🐶⭐'" ,
224+ ignore_emoji_types = "PEOPLE,NATURE,FOOD,ACTIVITY,TRAVEL,OBJECTS,SYMBOLS,FLAGS,OTHER" )
225+ assert results == [], "All emoji checks disabled should produce no results"
226+
227+
228+ def test_non_english_with_noqa ():
229+ content = "# Привет 🌸 # noqa"
230+ results = run_checker_on_content (content )
231+ assert results == [], "Line with # noqa should skip emoji check"
232+
233+
234+ def test_comment_with_multiple_noqa ():
235+ content = "# 🚀 test # noqa something else # noqa"
236+ results = run_checker_on_content (content )
237+ assert results == [], "Multiple # noqa should skip check"
238+
239+
240+ def test_string_with_noqa ():
241+ content = "x = '😀' # noqa"
242+ results = run_checker_on_content (content )
243+ assert results == [], "String with # noqa should skip check"
244+
245+
246+ def test_emoji_in_multiline_string ():
247+ content = '''x = """Line 1
248+ 🚀 Line 2
249+ Line 3 🐶"""'''
250+ results = run_checker_on_content (content )
251+ assert len (results ) == 2 , "Should detect emoji in multiline strings"
252+
253+
254+ def test_emoji_in_docstring ():
255+ content = '''"""
256+ This is a docstring with emoji 🌸
257+ """'''
258+ results = run_checker_on_content (content )
259+ assert len (results ) == 1 , "Should detect emoji in docstrings"
260+
261+
262+ def test_emoji_in_variable_name ():
263+ content = "😀 = 5"
264+ results = run_checker_on_content (content )
265+ assert results , "Should detect emoji in variable names"
266+
267+
268+ def test_emoji_in_function_name ():
269+ content = "def 🐶():\n pass"
270+ results = run_checker_on_content (content )
271+ assert results , "Should detect emoji in function names"
272+
273+
274+ def test_multiple_noqa_in_code ():
275+ content = "# noqa 🚀\n 😀 # noqa"
276+ results = run_checker_on_content (content )
277+ assert results == [], "Multiple # noqa should skip all checks"
278+
279+
280+ def test_only_category_with_no_matches ():
281+ results = run_checker_on_content ("x = '😀🐶'" , only_emoji_types = "FLAGS" )
282+ assert results == [], "No matches for only category should yield no results"
283+
284+
285+ def test_ignore_category_with_all_matches ():
286+ results = run_checker_on_content ("x = '😀🐶⭐'" , ignore_emoji_types = "PEOPLE,NATURE,SYMBOLS" )
287+ assert results == [], "Ignoring all categories with matches should yield no results"
288+
289+
290+ def test_unicode_non_emoji_characters ():
291+ content = "x = '© ™ ∑ √'"
292+ results = run_checker_on_content (content )
293+ assert results == [], "Unicode symbols that are not emojis should not be detected"
294+
295+
296+ def test_emoji_with_combining_characters ():
297+ content = "x = '🇺🇸👩🚀'"
298+ results = run_checker_on_content (content )
299+ assert results , "Emoji with combining characters should be detected"
300+
301+
302+ def test_long_file_with_sparse_emojis (tmp_path ):
303+ path = tmp_path / "long_file.py"
304+ lines = ["print('line {}')\n " .format (i ) for i in range (1000 )]
305+ lines [500 ] = "print('🚀')\n "
306+ path .write_text ("" .join (lines ), encoding = "utf-8" )
307+ results = run_checker_on_content ("" , filename = str (path ))
308+ assert results , "Long file with sparse emoji should detect at least one"
309+
310+
311+ def test_noqa_with_different_cases ():
312+ content = "# NoQA 🚀\n 😀 # NoQa"
313+ results = run_checker_on_content (content )
314+ assert results == [], "NoQA in different cases should still skip checks"
315+
316+
317+ def test_multiple_emojis_with_noqa ():
318+ content = "x = '😀🐶⭐' # noqa"
319+ results = run_checker_on_content (content )
320+ assert results == [], "Line with multiple emojis and noqa should skip all checks"
321+
322+
323+ def test_comment_only_with_emoji ():
324+ content = "# 🚀"
325+ results = run_checker_on_content (content )
326+ assert results , "Emoji in comment should be detected"
327+
328+
329+ def test_comment_with_emoji_and_text ():
330+ content = "# This is 🚀 a comment"
331+ results = run_checker_on_content (content )
332+ assert results , "Emoji in comment with text should be detected"
333+
334+
335+ def test_long_line_with_multiple_emojis ():
336+ content = "x = '😀🐶⭐🛸👩💻🏳️🌈' * 100"
337+ results = run_checker_on_content (content )
338+ assert len (results ) == 1 , "Only first emoji per line should be reported even for long lines"
339+
340+
341+ def test_ignore_case_category_names ():
342+ results = run_checker_on_content ("x = '😀'" , ignore_emoji_types = "people" )
343+ assert results == [], "Category ignoring should be case insensitive"
344+
345+
346+ def test_only_case_category_names ():
347+ results = run_checker_on_content ("x = '🐶'" , only_emoji_types = "nature" )
348+ assert results , "Category only check should be case insensitive"
0 commit comments