test(detect): harden nested-ignore tests (#1847 followup)
Tighten the brittle negation test to use .py files so classification lands in the deterministic `code` bucket (was checking a fuzzy document+unclassified union), and add a composition test asserting a nested `.gitignore` `!` re-include outranks both a root `.gitignore` and `.git/info/exclude` (#1810) — locking the precedence across all three ignore sources. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8a5287a979
commit
7ca43ab314
+32
-13
@@ -269,23 +269,42 @@ def test_gitignore_nested_below_root_prunes_whole_directory(tmp_path):
|
||||
|
||||
def test_gitignore_nested_negation_overrides_broader_root_rule(tmp_path):
|
||||
"""A closer (nested) .gitignore's `!` re-include wins over a root exclude,
|
||||
matching git's closer-file-wins precedence."""
|
||||
(tmp_path / ".gitignore").write_text("*.txt\n")
|
||||
matching git's closer-file-wins precedence. Uses .py so classification lands
|
||||
in the deterministic `code` bucket."""
|
||||
(tmp_path / ".gitignore").write_text("*.py\n")
|
||||
sub = tmp_path / "vendor" / "sub"
|
||||
sub.mkdir(parents=True)
|
||||
(sub / ".gitignore").write_text("!important.txt\n")
|
||||
(tmp_path / "root.txt").write_text("a")
|
||||
(sub / "important.txt").write_text("b")
|
||||
(sub / "other.txt").write_text("c")
|
||||
(sub / ".gitignore").write_text("!important.py\n")
|
||||
(tmp_path / "root.py").write_text("a = 1")
|
||||
(sub / "important.py").write_text("b = 1")
|
||||
(sub / "other.py").write_text("c = 1")
|
||||
|
||||
result = detect(tmp_path)
|
||||
# .txt is not a code extension so check the document bucket instead
|
||||
doc_files = result["files"]["document"] if "document" in result["files"] else []
|
||||
unclassified = result.get("unclassified", [])
|
||||
all_seen = doc_files + unclassified
|
||||
assert any("important.txt" in f for f in all_seen)
|
||||
assert not any(f.endswith("root.txt") for f in all_seen)
|
||||
assert not any(f.endswith("other.txt") for f in all_seen)
|
||||
code = result["files"]["code"]
|
||||
# nested `!important.py` re-includes it despite the root `*.py` exclude...
|
||||
assert any("vendor/sub/important.py" in f for f in code)
|
||||
# ...while the root-excluded and non-re-included files stay out
|
||||
assert not any(f.endswith("root.py") for f in code)
|
||||
assert not any(f.endswith("other.py") for f in code)
|
||||
|
||||
|
||||
def test_nested_ignore_overrides_git_info_exclude_and_root(tmp_path):
|
||||
"""Precedence across all three sources: a nested `.gitignore` `!` re-include
|
||||
outranks both a root `.gitignore` and `.git/info/exclude` (lowest, from
|
||||
#1810), while an info/exclude-only file with no re-include stays out."""
|
||||
(tmp_path / ".git" / "info").mkdir(parents=True)
|
||||
(tmp_path / ".git" / "info" / "exclude").write_text("*.py\n")
|
||||
(tmp_path / ".gitignore").write_text("keep.py\n") # root also excludes it
|
||||
sub = tmp_path / "a" / "b"
|
||||
sub.mkdir(parents=True)
|
||||
(sub / ".gitignore").write_text("!keep.py\n") # nearest wins -> re-included
|
||||
(sub / "keep.py").write_text("x = 1")
|
||||
(tmp_path / "drop.py").write_text("y = 1") # only info/exclude -> excluded
|
||||
|
||||
result = detect(tmp_path)
|
||||
code = result["files"]["code"]
|
||||
assert any("a/b/keep.py" in f for f in code), "nested ! must beat root + info/exclude"
|
||||
assert not any(f.endswith("drop.py") for f in code)
|
||||
|
||||
|
||||
def test_detect_handles_circular_symlinks(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user