import hashlib
import textwrap
from io import BytesIO
from unittest import mock

import pytest

from installer import install
from installer.exceptions import InvalidWheelSource
from installer.records import RecordEntry
from installer.sources import WheelSource


# --------------------------------------------------------------------------------------
# Helpers
# --------------------------------------------------------------------------------------
def hash_and_size(data):
    return hashlib.sha256(data).hexdigest(), len(data)


@pytest.fixture
def mock_destination():
    retval = mock.Mock()

    # A hacky approach to making sure we got the right objects going in.
    def custom_write_file(scheme, path, stream, is_executable):
        assert isinstance(stream, BytesIO)
        return (path, scheme, 0)

    def custom_write_script(name, module, attr, section):
        return (name, module, attr, section)

    retval.write_file.side_effect = custom_write_file
    retval.write_script.side_effect = custom_write_script

    return retval


class FakeWheelSource(WheelSource):
    def __init__(self, *, distribution, version, regular_files, dist_info_files):
        super().__init__(distribution, version)

        self.dist_info_files = {
            file: textwrap.dedent(content.decode("utf-8"))
            for file, content in dist_info_files.items()
        }
        self.regular_files = {
            file: textwrap.dedent(content.decode("utf-8")).encode("utf-8")
            for file, content in regular_files.items()
        }

        # Compute RECORD file.
        _records = [record for record, _, _ in self.get_contents()]
        self.dist_info_files["RECORD"] = "\n".join(
            sorted(
                ",".join([file, "sha256=" + hash_, str(size)])
                for file, hash_, size in _records
            )
        )

    @property
    def dist_info_filenames(self):
        return list(self.dist_info_files)

    def read_dist_info(self, filename):
        return self.dist_info_files[filename]

    def get_contents(self):
        # Sort for deterministic behaviour for Python versions that do not preserve
        # insertion order for dictionaries.
        for file, content in sorted(self.regular_files.items()):
            hashed, size = hash_and_size(content)
            record = (file, f"sha256={hashed}", str(size))
            with BytesIO(content) as stream:
                yield record, stream, False

        # Sort for deterministic behaviour for Python versions that do not preserve
        # insertion order for dictionaries.
        for file, text in sorted(self.dist_info_files.items()):
            content = text.encode("utf-8")
            hashed, size = hash_and_size(content)
            record = (
                self.dist_info_dir + "/" + file,
                f"sha256={hashed}",
                str(size),
            )
            with BytesIO(content) as stream:
                yield record, stream, False


# --------------------------------------------------------------------------------------
# Actual Tests
# --------------------------------------------------------------------------------------
class TestInstall:
    def test_calls_destination_correctly(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    def main():
                        print("I'm a fancy package")
                """,
                "fancy/__main__.py": b"""\
                    if __name__ == "__main__":
                        from . import main
                        main()
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        install(
            source=source,
            destination=mock_destination,
            additional_metadata={
                "fun_file.txt": b"this should be in dist-info!",
            },
        )

        mock_destination.assert_has_calls(
            [
                mock.call.write_script(
                    name="fancy",
                    module="fancy",
                    attr="main",
                    section="console",
                ),
                mock.call.write_script(
                    name="fancy-gui",
                    module="fancy",
                    attr="main",
                    section="gui",
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__init__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__main__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/METADATA",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/WHEEL",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/entry_points.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/top_level.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/fun_file.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.finalize_installation(
                    scheme="purelib",
                    record_file_path="fancy-1.0.0.dist-info/RECORD",
                    records=[
                        ("scripts", ("fancy", "fancy", "main", "console")),
                        ("scripts", ("fancy-gui", "fancy", "main", "gui")),
                        ("purelib", ("fancy/__init__.py", "purelib", 0)),
                        ("purelib", ("fancy/__main__.py", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None),
                        ),
                    ],
                ),
            ]
        )

    def test_no_entrypoints_is_ok(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    def main():
                        print("I'm a fancy package")
                """,
                "fancy/__main__.py": b"""\
                    if __name__ == "__main__":
                        from . import main
                        main()
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        install(
            source=source,
            destination=mock_destination,
            additional_metadata={
                "fun_file.txt": b"this should be in dist-info!",
            },
        )

        mock_destination.assert_has_calls(
            [
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__init__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__main__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/METADATA",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/WHEEL",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/top_level.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/fun_file.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.finalize_installation(
                    scheme="purelib",
                    record_file_path="fancy-1.0.0.dist-info/RECORD",
                    records=[
                        ("purelib", ("fancy/__init__.py", "purelib", 0)),
                        ("purelib", ("fancy/__main__.py", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/fun_file.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None),
                        ),
                    ],
                ),
            ]
        )

    def test_handles_platlib(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    def main():
                        print("I'm a fancy package")
                """,
                "fancy/__main__.py": b"""\
                    if __name__ == "__main__":
                        from . import main
                        main()
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: false
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        install(
            source=source,
            destination=mock_destination,
            additional_metadata={
                "fun_file.txt": b"this should be in dist-info!",
            },
        )

        mock_destination.assert_has_calls(
            [
                mock.call.write_script(
                    name="fancy",
                    module="fancy",
                    attr="main",
                    section="console",
                ),
                mock.call.write_script(
                    name="fancy-gui",
                    module="fancy",
                    attr="main",
                    section="gui",
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy/__init__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy/__main__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy-1.0.0.dist-info/METADATA",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy-1.0.0.dist-info/WHEEL",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy-1.0.0.dist-info/entry_points.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy-1.0.0.dist-info/top_level.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy-1.0.0.dist-info/fun_file.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.finalize_installation(
                    scheme="platlib",
                    record_file_path="fancy-1.0.0.dist-info/RECORD",
                    records=[
                        ("scripts", ("fancy", "fancy", "main", "console")),
                        ("scripts", ("fancy-gui", "fancy", "main", "gui")),
                        ("platlib", ("fancy/__init__.py", "platlib", 0)),
                        ("platlib", ("fancy/__main__.py", "platlib", 0)),
                        ("platlib", ("fancy-1.0.0.dist-info/METADATA", "platlib", 0)),
                        ("platlib", ("fancy-1.0.0.dist-info/WHEEL", "platlib", 0)),
                        (
                            "platlib",
                            ("fancy-1.0.0.dist-info/entry_points.txt", "platlib", 0),
                        ),
                        (
                            "platlib",
                            ("fancy-1.0.0.dist-info/top_level.txt", "platlib", 0),
                        ),
                        (
                            "platlib",
                            ("fancy-1.0.0.dist-info/fun_file.txt", "platlib", 0),
                        ),
                        (
                            "platlib",
                            RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None),
                        ),
                    ],
                ),
            ]
        )

    def test_accepts_newer_minor_wheel_versions(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    def main():
                        print("I'm a fancy package")
                """,
                "fancy/__main__.py": b"""\
                    if __name__ == "__main__":
                        from . import main
                        main()
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.1
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        install(
            source=source,
            destination=mock_destination,
            additional_metadata={
                "fun_file.txt": b"this should be in dist-info!",
            },
        )

        # no assertions necessary, since we want to make sure this test didn't
        # raises errors.
        assert True

    def test_rejects_newer_major_wheel_versions(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    def main():
                        print("I'm a fancy package")
                """,
                "fancy/__main__.py": b"""\
                    if __name__ == "__main__":
                        from . import main
                        main()
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 2.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        with pytest.raises(InvalidWheelSource) as ctx:
            install(
                source=source,
                destination=mock_destination,
                additional_metadata={
                    "fun_file.txt": b"this should be in dist-info!",
                },
            )

        assert "Incompatible Wheel-Version" in str(ctx.value)

    def test_handles_data_properly(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    # put me in purelib
                """,
                "fancy-1.0.0.data/purelib/fancy/purelib.py": b"""\
                    # put me in purelib
                """,
                "fancy-1.0.0.data/platlib/fancy/platlib.py": b"""\
                    # put me in platlib
                """,
                "fancy-1.0.0.data/scripts/fancy/scripts.py": b"""\
                    # put me in scripts
                """,
                "fancy-1.0.0.data/headers/fancy/headers.py": b"""\
                    # put me in headers
                """,
                "fancy-1.0.0.data/data/fancy/data.py": b"""\
                    # put me in data
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        install(
            source=source,
            destination=mock_destination,
            additional_metadata={},
        )

        mock_destination.assert_has_calls(
            [
                mock.call.write_script(
                    name="fancy",
                    module="fancy",
                    attr="main",
                    section="console",
                ),
                mock.call.write_script(
                    name="fancy-gui",
                    module="fancy",
                    attr="main",
                    section="gui",
                ),
                mock.call.write_file(
                    scheme="data",
                    path="fancy/data.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="headers",
                    path="fancy/headers.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="platlib",
                    path="fancy/platlib.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/purelib.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="scripts",
                    path="fancy/scripts.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__init__.py",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/METADATA",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/WHEEL",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/entry_points.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/top_level.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
                mock.call.finalize_installation(
                    scheme="purelib",
                    record_file_path="fancy-1.0.0.dist-info/RECORD",
                    records=[
                        ("scripts", ("fancy", "fancy", "main", "console")),
                        ("scripts", ("fancy-gui", "fancy", "main", "gui")),
                        ("data", ("fancy/data.py", "data", 0)),
                        ("headers", ("fancy/headers.py", "headers", 0)),
                        ("platlib", ("fancy/platlib.py", "platlib", 0)),
                        ("purelib", ("fancy/purelib.py", "purelib", 0)),
                        ("scripts", ("fancy/scripts.py", "scripts", 0)),
                        ("purelib", ("fancy/__init__.py", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/METADATA", "purelib", 0)),
                        ("purelib", ("fancy-1.0.0.dist-info/WHEEL", "purelib", 0)),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/entry_points.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            ("fancy-1.0.0.dist-info/top_level.txt", "purelib", 0),
                        ),
                        (
                            "purelib",
                            RecordEntry("fancy-1.0.0.dist-info/RECORD", None, None),
                        ),
                    ],
                ),
            ]
        )

    def test_errors_out_when_given_invalid_scheme_in_data(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    # put me in purelib
                """,
                "fancy-1.0.0.data/purelib/fancy/purelib.py": b"""\
                    # put me in purelib
                """,
                "fancy-1.0.0.data/invalid/fancy/invalid.py": b"""\
                    # i am invalid
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "entry_points.txt": b"""\
                    [console_scripts]
                    fancy = fancy:main

                    [gui_scripts]
                    fancy-gui = fancy:main
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )

        with pytest.raises(InvalidWheelSource) as ctx:
            install(
                source=source,
                destination=mock_destination,
                additional_metadata={},
            )

        assert "fancy-1.0.0.data/invalid/fancy/invalid.py" in str(ctx.value)

    def test_ensure_non_executable_for_additional_metadata(self, mock_destination):
        # Create a fake wheel
        source = FakeWheelSource(
            distribution="fancy",
            version="1.0.0",
            regular_files={
                "fancy/__init__.py": b"""\
                    # put me in purelib
                """,
            },
            dist_info_files={
                "top_level.txt": b"""\
                    fancy
                """,
                "WHEEL": b"""\
                    Wheel-Version: 1.0
                    Generator: magic (1.0.0)
                    Root-Is-Purelib: true
                    Tag: py3-none-any
                """,
                "METADATA": b"""\
                    Metadata-Version: 2.1
                    Name: fancy
                    Version: 1.0.0
                    Summary: A fancy package
                    Author: Agendaless Consulting
                    Author-email: nobody@example.com
                    License: MIT
                    Keywords: fancy amazing
                    Platform: UNKNOWN
                    Classifier: Intended Audience :: Developers
                """,
            },
        )
        all_contents = list(source.get_contents())
        source.get_contents = lambda: (
            (*contents, True) for (*contents, _) in all_contents
        )
        install(
            source=source,
            destination=mock_destination,
            additional_metadata={
                "fun_file.txt": b"this should be in dist-info!",
            },
        )

        mock_destination.assert_has_calls(
            [
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy/__init__.py",
                    stream=mock.ANY,
                    is_executable=True,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/METADATA",
                    stream=mock.ANY,
                    is_executable=True,
                ),
                mock.call.write_file(
                    scheme="purelib",
                    path="fancy-1.0.0.dist-info/fun_file.txt",
                    stream=mock.ANY,
                    is_executable=False,
                ),
            ],
            any_order=True,
        )
