"""Tests for coverage integration utilities."""

from __future__ import annotations

import json
import textwrap
from pathlib import Path

import attrs
import pytest

from codeflash_python._model import FunctionParent
from codeflash_python.analysis._coverage import (
    CoverageData,
    CoverageStatus,
    FunctionCoverage,
    aggregate_coverage,
    build_coverage_graph,
    build_coverage_message,
    build_fully_qualified_name,
    create_empty_coverage_data,
    extract_dependent_function,
    fetch_function_coverages,
    generate_candidates,
    grab_dependent_function_from_coverage_data,
    parse_coverage_file,
    prepare_coverage_files,
)
from codeflash_python.context.models import (
    CodeOptimizationContext,
    CodeString,
    CodeStringsMarkdown,
)


def make_function_coverage(  # noqa: PLR0913
    name: str = "func",
    coverage: float = 100.0,
    executed_lines: list[int] | None = None,
    unexecuted_lines: list[int] | None = None,
    executed_branches: list[list[int]] | None = None,
    unexecuted_branches: list[list[int]] | None = None,
) -> FunctionCoverage:
    """Build a FunctionCoverage with sensible defaults."""
    return FunctionCoverage(
        name=name,
        coverage=coverage,
        executed_lines=executed_lines or [],
        unexecuted_lines=unexecuted_lines or [],
        executed_branches=executed_branches or [],
        unexecuted_branches=unexecuted_branches or [],
    )


def make_code_context(
    testgen_code_strings: list[CodeString] | None = None,
    preexisting_objects: (
        set[tuple[str, tuple[FunctionParent, ...]]] | None
    ) = None,
) -> CodeOptimizationContext:
    """Build a CodeOptimizationContext with sensible defaults."""
    return CodeOptimizationContext(
        testgen_context=CodeStringsMarkdown(
            code_strings=testgen_code_strings or [],
        ),
        preexisting_objects=preexisting_objects or set(),
    )


def make_coverage_json(
    file_key: str,
    functions: dict[str, dict[str, object]],
) -> dict[str, object]:
    """Build a coverage JSON structure matching coverage.py output."""
    return {
        "files": {
            file_key: {
                "functions": functions,
            },
        },
    }


class TestCoverageStatusEnum:
    """CoverageStatus enum."""

    def test_not_found_value(self) -> None:
        """NOT_FOUND has the expected string value."""
        assert "Coverage Data Not Found" == CoverageStatus.NOT_FOUND.value

    def test_parsed_successfully_value(self) -> None:
        """PARSED_SUCCESSFULLY has the expected string value."""
        assert (
            "Parsed Successfully" == CoverageStatus.PARSED_SUCCESSFULLY.value
        )

    def test_member_count(self) -> None:
        """Enum contains exactly two members."""
        assert 2 == len(CoverageStatus)


class TestFunctionCoverage:
    """FunctionCoverage attrs class."""

    def test_valid_construction(self) -> None:
        """Accepts valid field values."""
        obj = FunctionCoverage(
            name="my_func",
            coverage=85.5,
            executed_lines=[1, 2, 3],
            unexecuted_lines=[4, 5],
            executed_branches=[[1, 0], [2, 1]],
            unexecuted_branches=[[3, 0]],
        )
        assert "my_func" == obj.name
        assert 85.5 == obj.coverage
        assert [1, 2, 3] == obj.executed_lines
        assert [4, 5] == obj.unexecuted_lines
        assert [[1, 0], [2, 1]] == obj.executed_branches
        assert [[3, 0]] == obj.unexecuted_branches

    def test_frozen(self) -> None:
        """Instances are immutable."""
        obj = make_function_coverage()
        with pytest.raises(attrs.exceptions.FrozenInstanceError):
            obj.name = "other"  # type: ignore[misc]

    def test_empty_lists(self) -> None:
        """Accepts empty lists for all collection fields."""
        obj = FunctionCoverage(
            name="f",
            coverage=0.0,
            executed_lines=[],
            unexecuted_lines=[],
            executed_branches=[],
            unexecuted_branches=[],
        )
        assert [] == obj.executed_lines
        assert [] == obj.unexecuted_lines
        assert [] == obj.executed_branches
        assert [] == obj.unexecuted_branches


class TestCoverageData:
    """CoverageData attrs class."""

    def test_valid_construction(self) -> None:
        """Accepts valid field values."""
        ctx = make_code_context()
        main_cov = make_function_coverage(name="main_func")
        obj = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=75.0,
            function_name="main_func",
            functions_being_tested=["main_func"],
            graph={},
            code_context=ctx,
            main_func_coverage=main_cov,
            dependent_func_coverage=None,
            status=CoverageStatus.PARSED_SUCCESSFULLY,
        )
        assert Path("/src/module.py") == obj.file_path
        assert 75.0 == obj.coverage
        assert "main_func" == obj.function_name
        assert ["main_func"] == obj.functions_being_tested
        assert {} == obj.graph
        assert ctx is obj.code_context
        assert main_cov is obj.main_func_coverage
        assert obj.dependent_func_coverage is None
        assert CoverageStatus.PARSED_SUCCESSFULLY == obj.status

    def test_with_dependent_coverage(self) -> None:
        """Accepts a non-None dependent function coverage."""
        ctx = make_code_context()
        main_cov = make_function_coverage(name="main")
        dep_cov = make_function_coverage(name="helper")
        obj = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=80.0,
            function_name="main",
            functions_being_tested=["main", "helper"],
            graph={},
            code_context=ctx,
            main_func_coverage=main_cov,
            dependent_func_coverage=dep_cov,
            status=CoverageStatus.PARSED_SUCCESSFULLY,
        )
        assert dep_cov is obj.dependent_func_coverage

    def test_frozen(self) -> None:
        """Instances are immutable."""
        ctx = make_code_context()
        obj = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=0.0,
            function_name="f",
            functions_being_tested=["f"],
            graph={},
            code_context=ctx,
            main_func_coverage=make_function_coverage(),
            dependent_func_coverage=None,
            status=CoverageStatus.NOT_FOUND,
        )
        with pytest.raises(attrs.exceptions.FrozenInstanceError):
            obj.coverage = 50.0  # type: ignore[misc]


class TestExtractDependentFunction:
    """extract_dependent_function function."""

    def test_single_dependent_function(self) -> None:
        """Returns the qualified name when exactly one dependent function exists."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def helper():
                            return 1
                    """),
                ),
            ],
        )
        result = extract_dependent_function("main_func", ctx)
        assert "helper" == result

    def test_returns_false_no_dependent_functions(self) -> None:
        """Returns False when testgen context has no function definitions."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(code="x = 1\n"),
            ],
        )
        result = extract_dependent_function("main_func", ctx)
        assert result is False

    def test_returns_false_multiple_dependent_functions(self) -> None:
        """Returns False when more than one dependent function exists."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def helper_a():
                            return 1

                        def helper_b():
                            return 2
                    """),
                ),
            ],
        )
        result = extract_dependent_function("main_func", ctx)
        assert result is False

    def test_excludes_main_function_from_count(self) -> None:
        """The main function itself is excluded from the dependent list."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def main_func():
                            return 0

                        def helper():
                            return 1
                    """),
                ),
            ],
        )
        result = extract_dependent_function("main_func", ctx)
        assert "helper" == result

    def test_empty_testgen_context(self) -> None:
        """Returns False when testgen context has no code strings."""
        ctx = make_code_context()
        result = extract_dependent_function("main_func", ctx)
        assert result is False

    def test_skips_code_without_def(self) -> None:
        """Skips code strings that contain no function definitions."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(code="import os\nx = 1\n"),
                CodeString(
                    code=textwrap.dedent("""\
                        def helper():
                            return 1
                    """),
                ),
            ],
        )
        result = extract_dependent_function("main_func", ctx)
        assert "helper" == result

    def test_dotted_main_function_name(self) -> None:
        """Handles dotted main function names by using bare name."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def method():
                            return 0

                        def helper():
                            return 1
                    """),
                ),
            ],
        )
        result = extract_dependent_function("MyClass.method", ctx)
        assert "helper" == result

    def test_qualifies_with_preexisting_objects(self) -> None:
        """Qualifies the dependent function name using preexisting_objects."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def helper():
                            return 1
                    """),
                ),
            ],
            preexisting_objects={
                (
                    "helper",
                    (FunctionParent(name="MyClass", type="ClassDef"),),
                ),
            },
        )
        result = extract_dependent_function("main_func", ctx)
        assert "MyClass.helper" == result


class TestBuildFullyQualifiedName:
    """build_fully_qualified_name function."""

    def test_already_dotted_returns_as_is(self) -> None:
        """A dotted name is returned unchanged."""
        ctx = make_code_context()
        result = build_fully_qualified_name("MyClass.method", ctx)
        assert "MyClass.method" == result

    def test_bare_name_no_parents(self) -> None:
        """A bare name with no matching preexisting objects stays bare."""
        ctx = make_code_context()
        result = build_fully_qualified_name("func", ctx)
        assert "func" == result

    def test_bare_name_with_class_parent(self) -> None:
        """A bare name is qualified with its ClassDef parent."""
        ctx = make_code_context(
            preexisting_objects={
                (
                    "method",
                    (FunctionParent(name="MyClass", type="ClassDef"),),
                ),
            },
        )
        result = build_fully_qualified_name("method", ctx)
        assert "MyClass.method" == result

    def test_bare_name_with_non_class_parent(self) -> None:
        """A bare name with only non-ClassDef parents stays bare."""
        ctx = make_code_context(
            preexisting_objects={
                (
                    "inner",
                    (
                        FunctionParent(
                            name="outer",
                            type="FunctionDef",
                        ),
                    ),
                ),
            },
        )
        result = build_fully_qualified_name("inner", ctx)
        assert "inner" == result

    def test_multiple_class_parents(self) -> None:
        """A bare name with nested ClassDef parents gets all prefixed."""
        ctx = make_code_context(
            preexisting_objects={
                (
                    "method",
                    (
                        FunctionParent(
                            name="Outer",
                            type="ClassDef",
                        ),
                        FunctionParent(
                            name="Inner",
                            type="ClassDef",
                        ),
                    ),
                ),
            },
        )
        result = build_fully_qualified_name("method", ctx)
        assert "Inner.Outer.method" == result


class TestGenerateCandidates:
    """generate_candidates function."""

    def test_includes_filename(self) -> None:
        """The bare filename is always a candidate."""
        result = generate_candidates(Path("/src/pkg/module.py"))
        assert "module.py" in result

    def test_includes_absolute_posix_path(self) -> None:
        """The full POSIX path is always a candidate."""
        p = Path("/src/pkg/module.py")
        result = generate_candidates(p)
        assert p.as_posix() in result

    def test_includes_progressive_relative_paths(self) -> None:
        """Progressively longer relative paths are candidates."""
        result = generate_candidates(Path("/src/pkg/sub/module.py"))
        assert "module.py" in result
        assert "sub/module.py" in result
        assert "pkg/sub/module.py" in result
        assert "src/pkg/sub/module.py" in result

    def test_single_component_path(self) -> None:
        """A path with only a filename produces just the name and posix."""
        p = Path("module.py")
        result = generate_candidates(p)
        assert "module.py" in result


class TestPrepareCoverageFiles:
    """prepare_coverage_files function."""

    def test_returns_two_paths(self) -> None:
        """Returns a tuple of two Path objects."""
        cov_db, coveragerc = prepare_coverage_files()
        assert isinstance(cov_db, Path)
        assert isinstance(coveragerc, Path)

    def test_coveragerc_has_content(self) -> None:
        """The .coveragerc file is written with branch=True."""
        _, coveragerc = prepare_coverage_files()
        content = coveragerc.read_text()
        assert "branch = True" in content

    def test_coveragerc_references_data_file(self) -> None:
        """The .coveragerc references the data file path."""
        cov_db, coveragerc = prepare_coverage_files()
        content = coveragerc.read_text()
        assert str(cov_db) in content


class TestParseCoverageFile:
    """parse_coverage_file function."""

    def test_parses_matching_file(self, tmp_path: Path) -> None:
        """Returns function coverage dict when the file key matches."""
        source = Path("/src/pkg/module.py")
        cov_json = make_coverage_json(
            "module.py",
            {
                "my_func": {
                    "summary": {"percent_covered": 80.0},
                    "executed_lines": [1, 2, 3],
                    "missing_lines": [4],
                    "executed_branches": [],
                    "missing_branches": [],
                },
            },
        )
        cov_file = tmp_path / "coverage.json"
        cov_file.write_text(json.dumps(cov_json))

        result, status = parse_coverage_file(cov_file, source)
        assert CoverageStatus.PARSED_SUCCESSFULLY == status
        assert "my_func" in result

    def test_returns_not_found_when_no_match(
        self,
        tmp_path: Path,
    ) -> None:
        """Returns empty dict and NOT_FOUND when no file key matches."""
        source = Path("/src/pkg/module.py")
        cov_json = make_coverage_json("other_file.py", {})
        cov_file = tmp_path / "coverage.json"
        cov_file.write_text(json.dumps(cov_json))

        result, status = parse_coverage_file(cov_file, source)
        assert CoverageStatus.NOT_FOUND == status
        assert {} == result

    def test_matches_progressive_path(self, tmp_path: Path) -> None:
        """Finds coverage data using a progressive relative path key."""
        source = Path("/src/pkg/module.py")
        cov_json = make_coverage_json(
            "pkg/module.py",
            {
                "func": {
                    "summary": {"percent_covered": 50.0},
                    "executed_lines": [1],
                    "missing_lines": [2],
                    "executed_branches": [],
                    "missing_branches": [],
                },
            },
        )
        cov_file = tmp_path / "coverage.json"
        cov_file.write_text(json.dumps(cov_json))

        result, status = parse_coverage_file(cov_file, source)
        assert CoverageStatus.PARSED_SUCCESSFULLY == status
        assert "func" in result


class TestFetchFunctionCoverages:
    """fetch_function_coverages function."""

    def test_returns_main_coverage(self) -> None:
        """Extracts main function coverage from coverage data."""
        ctx = make_code_context()
        cov_data = {
            "my_func": {
                "summary": {"percent_covered": 90.0},
                "executed_lines": [1, 2, 3],
                "missing_lines": [4],
                "executed_branches": [[1, 0]],
                "missing_branches": [[2, 0]],
            },
        }
        main_cov, dep_cov = fetch_function_coverages(
            "my_func",
            ctx,
            cov_data,
            cov_data,
        )
        assert "my_func" == main_cov.name
        assert 90.0 == main_cov.coverage
        assert [1, 2, 3] == main_cov.executed_lines
        assert [4] == main_cov.unexecuted_lines
        assert dep_cov is None

    def test_returns_empty_main_on_missing_key(self) -> None:
        """Returns zero-coverage main when function is not in data."""
        ctx = make_code_context()
        main_cov, dep_cov = fetch_function_coverages(
            "missing",
            ctx,
            {},
            {},
        )
        assert 0 == main_cov.coverage
        assert [] == main_cov.executed_lines
        assert dep_cov is None

    def test_returns_dependent_coverage(self) -> None:
        """Returns dependent function coverage when one exists."""
        ctx = make_code_context(
            testgen_code_strings=[
                CodeString(
                    code=textwrap.dedent("""\
                        def helper():
                            return 1
                    """),
                ),
            ],
        )
        cov_data = {
            "main_func": {
                "summary": {"percent_covered": 80.0},
                "executed_lines": [1, 2],
                "missing_lines": [3],
                "executed_branches": [],
                "missing_branches": [],
            },
            "helper": {
                "summary": {"percent_covered": 100.0},
                "executed_lines": [10, 11],
                "missing_lines": [],
                "executed_branches": [],
                "missing_branches": [],
            },
        }
        main_cov, dep_cov = fetch_function_coverages(
            "main_func",
            ctx,
            cov_data,
            cov_data,
        )
        assert dep_cov is not None
        assert "helper" == dep_cov.name
        assert 100.0 == dep_cov.coverage


class TestAggregateCoverage:
    """aggregate_coverage function."""

    def test_main_only(self) -> None:
        """Returns main lines when no dependent coverage."""
        main = make_function_coverage(
            executed_lines=[1, 2, 3],
            unexecuted_lines=[4, 5],
        )
        executed, unexecuted = aggregate_coverage(main, None)
        assert {1, 2, 3} == executed
        assert {4, 5} == unexecuted

    def test_with_dependent(self) -> None:
        """Merges main and dependent lines."""
        main = make_function_coverage(
            executed_lines=[1, 2],
            unexecuted_lines=[3],
        )
        dep = make_function_coverage(
            executed_lines=[10, 11],
            unexecuted_lines=[12],
        )
        executed, unexecuted = aggregate_coverage(main, dep)
        assert {1, 2, 10, 11} == executed
        assert {3, 12} == unexecuted

    def test_overlapping_lines(self) -> None:
        """Handles overlapping line numbers via set union."""
        main = make_function_coverage(
            executed_lines=[1, 2],
            unexecuted_lines=[3],
        )
        dep = make_function_coverage(
            executed_lines=[2, 3],
            unexecuted_lines=[4],
        )
        executed, unexecuted = aggregate_coverage(main, dep)
        assert {1, 2, 3} == executed
        assert {3, 4} == unexecuted

    def test_empty_lines(self) -> None:
        """Handles empty line lists gracefully."""
        main = make_function_coverage()
        executed, unexecuted = aggregate_coverage(main, None)
        assert set() == executed
        assert set() == unexecuted


class TestBuildCoverageGraph:
    """build_coverage_graph function."""

    def test_main_only(self) -> None:
        """Builds a graph with only the main function entry."""
        main = make_function_coverage(
            name="func",
            executed_lines=[1, 2],
            unexecuted_lines=[3],
            executed_branches=[[1, 0]],
            unexecuted_branches=[[2, 0]],
        )
        graph = build_coverage_graph(main, None)
        assert "func" in graph
        assert {1, 2} == graph["func"]["executed_lines"]
        assert {3} == graph["func"]["unexecuted_lines"]
        assert [[1, 0]] == graph["func"]["executed_branches"]
        assert [[2, 0]] == graph["func"]["unexecuted_branches"]

    def test_with_dependent(self) -> None:
        """Builds a graph with both main and dependent entries."""
        main = make_function_coverage(
            name="main_func",
            executed_lines=[1],
        )
        dep = make_function_coverage(
            name="helper",
            executed_lines=[10],
        )
        graph = build_coverage_graph(main, dep)
        assert "main_func" in graph
        assert "helper" in graph

    def test_no_dependent_only_one_entry(self) -> None:
        """Graph has exactly one entry when no dependent coverage."""
        main = make_function_coverage(name="solo")
        graph = build_coverage_graph(main, None)
        assert 1 == len(graph)
        assert "solo" in graph


class TestGrabDependentFunctionFromCoverageData:
    """grab_dependent_function_from_coverage_data function."""

    def test_found_in_coverage_data(self) -> None:
        """Returns coverage when the function is in coverage_data."""
        cov_data = {
            "helper": {
                "summary": {"percent_covered": 75.0},
                "executed_lines": [10, 11],
                "missing_lines": [12],
                "executed_branches": [],
                "missing_branches": [],
            },
        }
        result = grab_dependent_function_from_coverage_data(
            "helper",
            cov_data,
            {},
        )
        assert "helper" == result.name
        assert 75.0 == result.coverage
        assert [10, 11] == result.executed_lines
        assert [12] == result.unexecuted_lines

    def test_falls_back_to_original_data(self) -> None:
        """Falls back to original_cov_data when not in coverage_data."""
        original = make_coverage_json(
            "module.py",
            {
                "helper": {
                    "summary": {"percent_covered": 60.0},
                    "executed_lines": [5],
                    "missing_lines": [6],
                    "executed_branches": [],
                    "missing_branches": [],
                },
            },
        )
        result = grab_dependent_function_from_coverage_data(
            "helper",
            {},
            original,
        )
        assert "helper" == result.name
        assert 60.0 == result.coverage

    def test_raises_when_original_data_has_no_files_key(self) -> None:
        """Raises ValueError when original_cov_data has no 'files' key."""
        with pytest.raises(ValueError, match="Coverage data not found"):
            grab_dependent_function_from_coverage_data(
                "nonexistent",
                {},
                {},
            )

    def test_returns_zero_coverage_when_not_in_files(self) -> None:
        """Returns zero-coverage FunctionCoverage when not in either source."""
        result = grab_dependent_function_from_coverage_data(
            "nonexistent",
            {},
            {"files": {}},
        )
        assert "nonexistent" == result.name
        assert 0 == result.coverage


class TestCreateEmptyCoverageData:
    """create_empty_coverage_data function."""

    def test_returns_zero_coverage(self) -> None:
        """Returns a CoverageData with zero coverage."""
        ctx = make_code_context()
        result = create_empty_coverage_data(
            Path("/src/module.py"),
            "my_func",
            ctx,
        )
        assert 0.0 == result.coverage
        assert CoverageStatus.NOT_FOUND == result.status
        assert "my_func" == result.function_name
        assert Path("/src/module.py") == result.file_path

    def test_main_func_coverage_is_empty(self) -> None:
        """The main function coverage has zero values."""
        ctx = make_code_context()
        result = create_empty_coverage_data(
            Path("/src/module.py"),
            "my_func",
            ctx,
        )
        assert 0.0 == result.main_func_coverage.coverage
        assert [] == result.main_func_coverage.executed_lines
        assert [] == result.main_func_coverage.unexecuted_lines

    def test_dependent_coverage_is_none(self) -> None:
        """The dependent function coverage is None."""
        ctx = make_code_context()
        result = create_empty_coverage_data(
            Path("/src/module.py"),
            "my_func",
            ctx,
        )
        assert result.dependent_func_coverage is None

    def test_functions_being_tested_contains_name(self) -> None:
        """The functions_being_tested list contains the function name."""
        ctx = make_code_context()
        result = create_empty_coverage_data(
            Path("/src/module.py"),
            "my_func",
            ctx,
        )
        assert ["my_func"] == result.functions_being_tested

    def test_graph_has_empty_entries(self) -> None:
        """The graph has empty sets/lists for the function."""
        ctx = make_code_context()
        result = create_empty_coverage_data(
            Path("/src/module.py"),
            "my_func",
            ctx,
        )
        assert "my_func" in result.graph


class TestBuildCoverageMessage:
    """build_coverage_message function."""

    def test_not_found_status(self) -> None:
        """Returns a descriptive message when status is NOT_FOUND."""
        ctx = make_code_context()
        data = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=0.0,
            function_name="my_func",
            functions_being_tested=["my_func"],
            graph={},
            code_context=ctx,
            main_func_coverage=make_function_coverage(name="my_func"),
            dependent_func_coverage=None,
            status=CoverageStatus.NOT_FOUND,
        )
        msg = build_coverage_message(data)
        assert "my_func" in msg

    def test_parsed_successfully_shows_percentage(self) -> None:
        """Returns a percentage string when status is PARSED_SUCCESSFULLY."""
        ctx = make_code_context()
        data = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=85.7,
            function_name="my_func",
            functions_being_tested=["my_func"],
            graph={},
            code_context=ctx,
            main_func_coverage=make_function_coverage(
                name="my_func",
                coverage=85.7,
            ),
            dependent_func_coverage=None,
            status=CoverageStatus.PARSED_SUCCESSFULLY,
        )
        msg = build_coverage_message(data)
        assert "85.7%" in msg

    def test_zero_coverage_parsed(self) -> None:
        """Returns a zero percentage when coverage is 0.0."""
        ctx = make_code_context()
        data = CoverageData(
            file_path=Path("/src/module.py"),
            coverage=0.0,
            function_name="my_func",
            functions_being_tested=["my_func"],
            graph={},
            code_context=ctx,
            main_func_coverage=make_function_coverage(
                name="my_func",
                coverage=0.0,
            ),
            dependent_func_coverage=None,
            status=CoverageStatus.PARSED_SUCCESSFULLY,
        )
        msg = build_coverage_message(data)
        assert "0.0%" in msg
