From 91acd13c3312d9c87f953456b632adefe286a4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Ri=C3=9Fe?= Date: Thu, 23 Feb 2023 11:47:08 +0100 Subject: [PATCH] Add tests for better handling of symlinks These tests assume the interpretation of the REUSE specification that: 1. a symlink pointing to a covered file is considered to be the same file as the covered file and can therefore be ignored. 2. a symlink pointing to a file that is not a covered file is itself considered to be a covered file and should not be ignored, unless the symlink itself is ignored by other means. --- tests/conftest.py | 10 +++++++ tests/test_project.py | 66 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 601f5ecc4..25260db57 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017 Free Software Foundation Europe e.V. # SPDX-FileCopyrightText: 2022 Florian Snow # SPDX-FileCopyrightText: 2022 Carmen Bianca Bakker +# SPDX-FileCopyrightText: 2023 Matthias Riße # # SPDX-License-Identifier: GPL-3.0-or-later @@ -137,6 +138,15 @@ def fake_repository(tmpdir_factory) -> Path: encoding="utf-8", ) + (directory / "symlink-to-covered").symlink_to(directory / "doc/index.rst") + (directory / "symlink-to-not-covered").symlink_to(directory) + (directory / "symlink-to-not-covered.license").write_text( + "# SPDX-FileCopyrightText: 2017 Jane Doe\n" + "#\n" + "# SPDX-License-Identifier: GPL-3.0-or-later", + encoding="utf-8", + ) + os.chdir(directory) return directory diff --git a/tests/test_project.py b/tests/test_project.py index 59ab96f08..7bd4a2970 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2017 Free Software Foundation Europe e.V. # SPDX-FileCopyrightText: © 2020 Liferay, Inc. # SPDX-FileCopyrightText: 2022 Florian Snow +# SPDX-FileCopyrightText: 2023 Matthias Riße # # SPDX-License-Identifier: GPL-3.0-or-later @@ -98,8 +99,8 @@ def test_all_files_ignore_hg(empty_directory): @posix -def test_all_files_symlinks(empty_directory): - """All symlinks must be ignored.""" +def test_all_files_ignore_symlinks_to_covered_file(empty_directory): + """All symlinks to covered files must be ignored.""" (empty_directory / "blob").write_text("foo") (empty_directory / "blob.license").write_text( cleandoc( @@ -115,6 +116,15 @@ def test_all_files_symlinks(empty_directory): assert Path("symlink").absolute() not in project.all_files() +@posix +@pytest.mark.parametrize("target", ["/outside_file", "non-existent-file"]) +def test_all_files_cover_symlinks_to_uncovered_files(empty_directory, target): + """All symlinks to files not covered must be included.""" + (empty_directory / "symlink").symlink_to(target) + project = Project(empty_directory) + assert Path("symlink").absolute() in project.all_files() + + def test_all_files_ignore_zero_sized(empty_directory): """Empty files should be skipped.""" (empty_directory / "foo").touch() @@ -157,6 +167,33 @@ def test_all_files_git_ignored_contains_newline(git_repository): assert Path("hello\nworld.pyc").absolute() not in project.all_files() +@posix +def test_all_files_git_ignore_symlinks_to_covered_file(git_repository): + """All symlinks to covered files must be ignored.""" + (git_repository / "symlink").symlink_to("doc/index.rst") + project = Project(git_repository) + assert Path("symlink").absolute() not in project.all_files() + + +@posix +@pytest.mark.parametrize( + "target", + [ + "/outside_file", + ".git/file-in-dotgit", + "build/hello.py", + "non-existent-file", + ], +) +def test_all_files_git_cover_symlinks_to_uncovered_files( + git_repository, target +): + """All symlinks to files not covered must be included.""" + (git_repository / "symlink").symlink_to(target) + project = Project(git_repository) + assert Path("symlink").absolute() in project.all_files() + + def test_all_files_submodule_is_ignored(submodule_repository): """If a submodule is ignored, all_files should not raise an Exception.""" (submodule_repository / "submodule/foo.py").write_text("foo") @@ -202,6 +239,31 @@ def test_all_files_hg_ignored_contains_newline(hg_repository): assert Path("hello\nworld.pyc").absolute() not in project.all_files() +@posix +def test_all_files_hg_ignore_symlinks_to_covered_file(hg_repository): + """All symlinks to covered files must be ignored.""" + (hg_repository / "symlink").symlink_to("doc/index.rst") + project = Project(hg_repository) + assert Path("symlink").absolute() not in project.all_files() + + +@posix +@pytest.mark.parametrize( + "target", + [ + "/outside_file", + ".hg/file-in-dothg", + "build/hello.py", + "non-existent-file", + ], +) +def test_all_files_hg_cover_symlinks_to_uncovered_files(hg_repository, target): + """All symlinks to files not covered must be included.""" + (hg_repository / "symlink").symlink_to(target) + project = Project(hg_repository) + assert Path("symlink").absolute() in project.all_files() + + def test_reuse_info_of_file_does_not_exist(fake_repository): """Raise FileNotFoundError when asking for the REUSE info of a file that does not exist.