Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests from gitignorant #34

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,5 @@ matches("/home/michael/project/__pycache__") # True
- https://github.com/snark/ignorance by Steve Cook
- https://github.com/mherrmann/gitignore_parser by Michael Herrmann
- https://github.com/bitranox/igittigitt by Robert Nowotny
- https://github.com/valohai/gitignorant by Aarni Koskela
- https://github.com/cpburnz/python-path-specification by Caleb Burns
173 changes: 173 additions & 0 deletions tests/test_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,179 @@ def test_robert_parse_rule_files(self):
self.assertFalse(matches("/home/robert/.test_venv", is_dir=False))
self.assertTrue(matches("/home/robert/.test_venv", is_dir=True))

GITIGNORE_STRING = r"""
# Hello! this line is ignored.

# comment
#comment
comment_after.file # a comment must be on its own line

*.peasoup
a?.john
zz*
!/[a-f]*.peasoup
# world
!booze/*.peasoup
!/scaffolding/*.peasoup

# Directory testing
recipes/
!/other/recipes/

# Escape testing
\!important*
spaced_out\
""" # noqa: W291

TEST_CASES = [
(False, "hello"),
(True, "hello.peasoup"),
(False, "hello.peasoupiness"),
(True, "ballo/allo.peasoup"),
(False, "allo.peasoup"),
(False, "cullo.peasoup"),
(True, "bazze/allo.peasoup"),
(False, "booze/allo.peasoup"),
(True, "booze/scaffolding/allo.peasoup"),
(False, "scaffolding/allo.peasoup"),
(True, "asdf/ab.john"),
(False, "asdf/aba.john"),
(True, "ab.john"),
(False, "asdf/cb.john"),
(True, "!important_1*"),
(True, "spaced_out "),
(False, "spaced_out"),
(True, "zztop"),
(False, "jazztop"),
(False, "# comment"),
(False, "#comment"),
(False, "comment"),
(False, "comment_after.file"),
(True, "comment_after.file # a comment must be on its own line"),
]


@pytest.mark.parametrize(["expected", "path"], TEST_CASES)
@pytest.mark.parametrize("func", ["check_match", "check_path_match"])
def test_gitignorant_files(
rules: List[Rule],
path: str,
expected: bool,
func: str,
) -> None:
if func == "check_match":
assert check_match(rules, path, is_dir=False) == expected
elif func == "check_path_match":
assert check_path_match(rules, path) == expected
else:
raise NotImplementedError("...")


@pytest.mark.parametrize(
"expected,path",
[
(True, "foo/recipes"),
(False, "other/recipes"),
(True, "/recipes"),
],
)
def test_gitignorant_dirs(rules: List[Rule], path: str, expected: bool) -> None:
assert check_match(rules, path, is_dir=True) == expected


@pytest.mark.parametrize(
"expected, path",
[
(True, "a/b"),
(True, "a/x/b"),
(True, "a/x/y/b"),
],
)
def test_spec_internal_doublestar(path: str, expected: bool) -> None:
# * A slash followed by two consecutive asterisks then a slash matches
# zero or more directories. For example, "a/**/b"
# matches "a/b", "a/x/b", "a/x/y/b" and so on.
r = try_parse_rule("a/**/b")
assert r
assert r.matches(path) == expected


@pytest.mark.parametrize(
"expected, path",
[
(True, "abc/a"),
(True, "abc/x/b"),
(True, "abc/x/y/b"),
],
)
def test_spec_trailing_doublestar(path: str, expected: bool) -> None:
# * A trailing "/**" matches everything inside. For example, "abc/**"
# matches all files inside directory "abc", relative to the location
# of the .gitignore file, with infinite depth.
r = try_parse_rule("abc/**")
assert r
assert r.matches(path) == expected


@pytest.mark.parametrize(
"expected, path",
[
(True, "doop/foo"),
(True, "abc/bloop/buup/foo"),
(False, "doop/foo/zoop"),
(False, "abc/bloop/buup/foro"),
],
)
def test_spec_leading_doublestar(path: str, expected: bool) -> None:
# * A leading "**" followed by a slash means match in all directories.
# For example, "**/foo" matches file or directory "foo" anywhere, the
# same as pattern "foo". "**/foo/bar" matches file or directory "bar"
# anywhere that is directly under directory "foo".
r = try_parse_rule("**/foo")
assert r
assert r.matches(path) == expected


def test_spec_trailing_dir_magic() -> None:
# * For example, a pattern doc/frotz/ matches doc/frotz directory, but not
# a/doc/frotz directory; however frotz/ matches frotz and a/frotz that
# is a directory (all paths are relative from the .gitignore file).
r1 = try_parse_rule("doc/frotz/")
assert r1
assert r1.matches("doc/frotz", is_dir=True)
assert not r1.matches("a/doc/frotz", is_dir=True)
r2 = try_parse_rule("frotz/")
assert r2
assert r2.matches("frotz", is_dir=True)
assert r2.matches("a/frotz", is_dir=True)


def test_unfinished_group_parsing() -> None:
r1 = try_parse_rule("unfinished/symp[athy")
assert r1
assert r1.matches("unfinished/sympa", is_dir=False)
assert r1.matches("unfinished/sympt", is_dir=False)
assert r1.matches("unfinished/symph", is_dir=False)
assert r1.matches("unfinished/sympy", is_dir=False)
assert not r1.matches("unfinished/sympathy", is_dir=False)


CHECK_PATH_MATCH_CASES = [
# These should match since `recipes/` is in the list,
# and it's not anchored to the root
("recipes/zep", True),
("splop/recipes/zep", True),
# This should not match, since `/other/recipes/` is explicitly negated
("other/recipes/zep", False),
# This too should match, since it's trying to ignore the whole folder
("recipes/", True),
]


@pytest.mark.parametrize(["path", "expected"], CHECK_PATH_MATCH_CASES)
def test_check_path_match(rules: List[Rule], path: str, expected: bool) -> None:
assert check_path_match(rules, path) == expected

def __parse_gitignore_string(self, data, mock_base_path):
with unittest.mock.patch("builtins.open", unittest.mock.mock_open(read_data="\n".join(data))):
return gitignorefile.parse(f"{mock_base_path}/.gitignore", base_path=mock_base_path)