"""Tests for scripts/assurance_brief_html.py (one-page editorial assessment brief)."""
from __future__ import annotations

import sys
from pathlib import Path

_scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
if str(_scripts_dir) not in sys.path:
    sys.path.insert(0, str(_scripts_dir))

import assurance_brief_html as brief  # noqa: E402


def _scorecard():
    return {"course": {"name": "COM 100: Introduction to Communication"}, "tier": "Unassured"}


def _full_brief():
    return {
        "brief": {
            "period_lines": ["ASUO", "FY24-26"],
            "course_url": "https://canvas.asu.edu/courses/175993",
            "fetched": "2026-07-09",
            "glance": [
                {"value": "~600", "label": "Students / term"},
                {"value": "84%", "label": "Success rate"},
                {"value": "4.5", "denom": "/5", "label": "Course eval", "note": "above avg"},
            ],
            "about": "COM 100 is an online introductory course.",
            "how_graded": "The grade is spread across many small assignments.",
            "graded_items": [
                {"count": 10, "label": "Short papers", "weight_pct": 57},
                {"count": 8, "label": "Discussions", "weight_pct": 11.4},
            ],
            "working": ["Papers ask for applied thinking", "Low-stakes distribution"],
            "exposed": ["Work never shows authorship", "No AI policy"],
            "barrier": "There is no single lever to pull.",
            "directions": [
                {"lead": "Ask the papers to show process (57%).", "text": "Add an appendix."},
                {"lead": "Set a plain AI policy.", "text": "Say what is allowed."},
            ],
        }
    }


class TestFullBrief:
    def setup_method(self):
        self.html = brief.render(_scorecard(), _full_brief())

    def test_is_html_doc(self):
        assert self.html.startswith("<!DOCTYPE html")

    def test_title_says_brief_not_quickstart(self):
        assert "<title>COM 100: Introduction to Communication: Assessment Brief</title>" in self.html
        assert "Quick-Start" not in self.html and "Quickstart" not in self.html

    def test_course_name_in_masthead(self):
        assert "<h1>COM 100: Introduction to Communication</h1>" in self.html

    def test_period_lines_render(self):
        assert "ASUO<br>FY24-26" in self.html

    def test_all_sections_present(self):
        for s in ("Course at a Glance", "About This Course", "How Learning Is Assessed:",
                  "percentage share of the final grade", "What&rsquo;s Working", "Where It&rsquo;s Exposed",
                  "The Constraint", "Improvement Opportunities"):
            assert s in self.html, f"missing: {s!r}"

    def test_source_link_shows_shell_and_fetch_date(self):
        # Meeting asks #1/#7: which shell, and when it was pulled.
        assert 'href="https://canvas.asu.edu/courses/175993"' in self.html
        assert "pulled 2026-07-09" in self.html

    def test_glance_band(self):
        assert "~600" in self.html and "Students / term" in self.html
        # eval cell: denominator + green benchmark note
        assert '4.5<span class="d">/5</span>' in self.html
        assert '<span class="sub up">above avg</span>' in self.html

    def test_eval_benchmark_styling(self):
        # Green "up" style ONLY for above-average; about/below render neutral muted.
        above = brief.render(_scorecard(), {"brief": {"glance": [
            {"value": "4.7", "denom": "/5", "label": "Course eval", "note": "above avg"}]}})
        assert '<span class="sub up">above avg</span>' in above
        about = brief.render(_scorecard(), {"brief": {"glance": [
            {"value": "4.4", "denom": "/5", "label": "Course eval", "note": "about avg"}]}})
        assert '<span class="sub">about avg</span>' in about
        assert '<span class="sub up">about avg</span>' not in about
        below = brief.render(_scorecard(), {"brief": {"glance": [
            {"value": "3.9", "denom": "/5", "label": "Course eval", "note": "below avg"}]}})
        assert '<span class="sub">below avg</span>' in below
        assert '<span class="sub up">below avg</span>' not in below

    def test_graded_items_band(self):
        assert "Short papers" in self.html and "57%" in self.html
        assert "11.4%" in self.html  # non-integer weight keeps its decimal

    def test_directions_present(self):
        assert "Ask the papers to show process (57%)." in self.html
        assert "Set a plain AI policy." in self.html

    def test_editorial_design_markers(self):
        # White editorial layout: boxed stat strips + cols, no cream fills, no gold ticks.
        assert ".eyebrow::before" not in self.html  # gold ticks removed
        assert "--paper: #ffffff;" in self.html
        assert ".col { border: 1px solid var(--box); " in self.html

    def test_no_em_dashes(self):
        assert "—" not in self.html and "&mdash;" not in self.html

    def test_section_order(self):
        i_glance = self.html.index("Course at a Glance")
        i_about = self.html.index("About This Course")
        i_cols = self.html.index("What&rsquo;s Working")
        i_barrier = self.html.index("The Constraint")
        i_ops = self.html.index("Improvement Opportunities")
        assert i_glance < i_about < i_cols < i_barrier < i_ops

    def test_print_fits_paper(self):
        assert "@page { size: Letter;" in self.html
        assert "print-color-adjust: exact;" in self.html

    def test_muted_label_color_passes_aa(self):
        # Contrast fix: muted labels use the AA-passing warm gray, not the old #8f877a.
        assert "--muted: #736c60;" in self.html
        assert "#8f877a" not in self.html


def _verdict_narrative():
    return {
        "brief": {
            "verdict": {
                "proof": {
                    "answer": "Yes, for most of the grade.",
                    "detail": "The final and five unit quizzes, worth about 62%, are taken with the camera on and the browser locked, so a student cannot look things up or pass the test to someone else.",
                },
                "design": {
                    "answer": "No, it mostly tests memory.",
                    "detail": "The locked quizzes are multiple-choice questions that check what students remember, though the course is meant to teach them to weigh arguments and judge which side holds up. It also never asks students to show their own thinking or how they used AI.",
                },
            }
        }
    }


def _verdict_scorecard(coverage=63.8, rating="Needs redesign"):
    return {
        "course": {"name": "PHI 101: Introduction to Philosophy"},
        "assurance_coverage_pct": coverage,
        "ai_forward_rating": rating,
    }


class TestVerdict:
    def test_verdict_present_renders(self):
        html = brief.render(_verdict_scorecard(), _verdict_narrative())
        assert "The Verdict" in html
        assert "Yes, for most of the grade." in html
        assert "No, it mostly tests memory." in html
        assert "Can it prove a real student did the work?" in html
        assert "Does it measure real thinking?" in html
        assert "PHI 101 is here" in html
        assert "<svg" in html

    def test_verdict_absent_renders_nothing(self):
        html = brief.render(_scorecard(), _full_brief())
        assert "The Verdict" not in html

    def test_verdict_key_missing_entirely(self):
        html = brief.render(_scorecard(), {"brief": {}})
        assert "The Verdict" not in html

    def test_verdict_is_last_section(self):
        full = dict(_full_brief())
        full["brief"] = {**full["brief"], **_verdict_narrative()["brief"]}
        html = brief.render(_scorecard(), full)
        i_ops = html.index("Improvement Opportunities")
        i_verdict = html.index("The Verdict")
        assert i_ops < i_verdict

    def test_dot_position_high_coverage_ai_forward_is_top_right(self):
        x, y = brief._verdict_dot_xy(
            _verdict_scorecard(coverage=95, rating="AI-forward"), {}
        )
        assert x > 150  # right side
        assert y < 60   # top side (svg y grows downward)

    def test_dot_position_low_coverage_needs_redesign_is_bottom_right(self):
        # Sanity check from the spec: PHI 101 sample values land bottom-right.
        x, y = brief._verdict_dot_xy(_verdict_scorecard(), {})
        assert x > 116  # right of the vertical divider
        assert y > 85   # below the horizontal divider (bottom half)

    def test_dot_position_clamped_within_bounds(self):
        x, y = brief._verdict_dot_xy(
            _verdict_scorecard(coverage=0, rating="Needs redesign"), {}
        )
        assert 70 <= x <= 190
        assert 22 <= y <= 150
        x2, y2 = brief._verdict_dot_xy(
            _verdict_scorecard(coverage=100, rating="AI-forward"), {}
        )
        assert 70 <= x2 <= 190
        assert 22 <= y2 <= 150

    def test_dot_position_xy_overrides(self):
        x, y = brief._verdict_dot_xy(
            _verdict_scorecard(coverage=0, rating="Needs redesign"),
            {"verdict": {"x": 1.0, "y": 1.0}},
        )
        assert x > 150
        assert y < 60

    def test_dot_position_missing_scorecard_fields_default(self):
        x, y = brief._verdict_dot_xy({"course": {"name": "PHI 101"}}, {})
        assert 70 <= x <= 190
        assert 22 <= y <= 150

    def test_course_code_parses_before_colon(self):
        assert brief._course_code("PHI 101: Introduction to Philosophy") == "PHI 101"
        assert brief._course_code("COM 100") == "COM 100"
        assert brief._course_code("") == "This course"
        assert brief._course_code(None) == "This course"

    def test_verdict_xss_escaped(self):
        p = "<script>alert(1)</script>"
        narrative = {
            "brief": {
                "verdict": {
                    "proof": {"answer": p, "detail": "safe"},
                    "design": {"answer": "safe", "detail": p},
                }
            }
        }
        html = brief.render(_verdict_scorecard(), narrative)
        assert "<script>alert(1)</script>" not in html
        assert "&lt;script&gt;" in html

    def test_verdict_no_em_dash(self):
        html = brief.render(_verdict_scorecard(), _verdict_narrative())
        assert "—" not in html
        assert "–" not in html


# ---------------------------------------------------------------------------
# Security ledger: per-assessment binary labels (docs/plan-assurance-binary-labels.md)
# ---------------------------------------------------------------------------

def _ledger_item(id, security, design="ai_resistant", needs_ai_review=False, graded=True):
    return {
        "id": id, "title": f"Item {id}", "grade_weight_pct": 10.0, "graded": graded,
        "security": security, "security_basis": "identity" if security == "secured" else "none",
        "security_evidence": "proctoring_signal (API fact)" if security == "secured" else "",
        "needs_ai_review": needs_ai_review, "design": design, "design_basis": "",
    }


class TestLedgerSection:
    """Criterion 10: the brief LEADS with per-assessment secured/unsecured +
    forward/resistant chips, sourced from scorecard['security_ledger'], not
    the narrative -- it renders even before Claude authors a narrative brief."""

    def _ledger_sc(self):
        return {
            "course": {"name": "PHI 101"},
            "security_ledger": [
                {"id": 1, "title": "Proctored Midterm", "grade_weight_pct": 30.0, "graded": True,
                 "security": "secured", "security_basis": "identity",
                 "security_evidence": "proctoring_signal (API fact)",
                 "needs_ai_review": False, "design": "n/a", "design_basis": ""},
                {"id": 2, "title": "Weekly Reflection", "grade_weight_pct": 20.0, "graded": True,
                 "security": "unsecured", "security_basis": "none", "security_evidence": "",
                 "needs_ai_review": True, "design": "ai_resistant",
                 "design_basis": "process-trail/authorship signal supports authorship, not AI-use"},
            ],
        }

    def test_ledger_renders_with_chips_no_narrative(self):
        html = brief.render(self._ledger_sc(), {})
        assert "Proctored Midterm" in html
        assert "Weekly Reflection" in html
        assert '<span class="chip sec">Secured</span>' in html
        assert '<span class="chip vul">Unsecured</span>' in html
        assert '<span class="chip na">N/A</span>' in html
        assert '<span class="chip res">AI-Resistant</span>' in html

    def test_ai_forward_chip_renders(self):
        sc = self._ledger_sc()
        sc["security_ledger"].append(
            {"id": 3, "title": "AI-Use Appendix", "grade_weight_pct": 15.0, "graded": True,
             "security": "unsecured", "security_basis": "none", "security_evidence": "",
             "needs_ai_review": False, "design": "ai_forward", "design_basis": "documents AI use"}
        )
        html = brief.render(sc, {})
        assert '<span class="chip fwd">AI-Forward</span>' in html

    def test_ledger_leads_before_course_at_a_glance(self):
        sc = self._ledger_sc()
        html = brief.render(sc, {"brief": {"glance": [{"value": "1", "label": "x"}]}})
        assert html.index("Assessment Security") < html.index("Course at a Glance")

    def test_needs_review_marker_on_unconfirmed_nominee(self):
        html = brief.render(self._ledger_sc(), {})
        assert "needs review" in html

    def test_no_needs_review_marker_on_secured_item(self):
        sc = {"course": {"name": "X"}, "security_ledger": [
            {"id": 1, "title": "Solo Item", "grade_weight_pct": 10.0, "graded": True,
             "security": "secured", "security_basis": "identity",
             "security_evidence": "proctoring_signal (API fact)",
             "needs_ai_review": False, "design": "n/a", "design_basis": ""},
        ]}
        html = brief.render(sc, {})
        assert "needs review" not in html

    def test_absent_without_security_ledger(self):
        html = brief.render(_scorecard(), _full_brief())
        assert "Assessment Security" not in html

    def test_absent_when_no_graded_items(self):
        sc = {"course": {"name": "X"}, "security_ledger": [
            {"id": 1, "title": "Ungraded Survey", "grade_weight_pct": 0.0, "graded": False,
             "security": "unsecured", "security_basis": "none", "security_evidence": "",
             "needs_ai_review": False, "design": "n/a", "design_basis": ""},
        ]}
        html = brief.render(sc, {})
        assert "Assessment Security" not in html

    def test_no_percentage_in_ledger_section(self):
        html = brief.render(self._ledger_sc(), {})
        ledger_start = html.index('<div class="ledger">')
        section_end = html.index("</section>", ledger_start)
        assert "%" not in html[ledger_start:section_end]

    def test_xss_in_ledger_title_escaped(self):
        sc = self._ledger_sc()
        sc["security_ledger"][0]["title"] = "<script>alert(1)</script>"
        html = brief.render(sc, {})
        assert "<script>alert(1)</script>" not in html
        assert "&lt;script&gt;" in html


class TestVerdictDotDrivenByLedgerCounts:
    """Criterion 10 / plan %6b: when security_ledger is present, the Verdict
    matrix dot is driven by counts (secured vs unsecured; forward vs
    resistant), not the deprecated coverage percentage / ai_forward_rating."""

    def _sc(self, ledger, coverage=5.0, rating="Needs redesign"):
        return {
            "course": {"name": "PHI 101"},
            "assurance_coverage_pct": coverage,
            "ai_forward_rating": rating,
            "security_ledger": ledger,
        }

    def test_mostly_secured_ledger_ignores_low_coverage_pct(self):
        # coverage_pct=5 would put the dot far left under the deprecated
        # logic, but 4 of 5 graded items are actually secured.
        ledger = [_ledger_item(i, "secured") for i in range(4)] + [_ledger_item(4, "unsecured")]
        x, _y = brief._verdict_dot_xy(self._sc(ledger, coverage=5.0), {})
        assert x > 150

    def test_mostly_unsecured_ledger_ignores_high_coverage_pct(self):
        ledger = [_ledger_item(i, "unsecured") for i in range(4)] + [_ledger_item(4, "secured")]
        x, _y = brief._verdict_dot_xy(self._sc(ledger, coverage=95.0), {})
        assert x < 116

    def test_mostly_ai_forward_ledger_ignores_rating(self):
        ledger = [_ledger_item(i, "unsecured", design="ai_forward") for i in range(4)]
        _x, y = brief._verdict_dot_xy(self._sc(ledger, rating="Needs redesign"), {})
        assert y < 60

    def test_mostly_ai_resistant_ledger_ignores_rating(self):
        ledger = [_ledger_item(i, "unsecured", design="ai_resistant") for i in range(4)]
        _x, y = brief._verdict_dot_xy(self._sc(ledger, rating="AI-forward"), {})
        assert y > 85

    def test_na_design_items_excluded_from_y_denominator(self):
        # All n/a (auto-graded objective quizzes): no forward/resistant signal
        # at all -- falls back to ai_forward_rating rather than a bogus 0/0.
        ledger = [_ledger_item(i, "secured", design="n/a") for i in range(3)]
        _x, y = brief._verdict_dot_xy(self._sc(ledger, rating="AI-forward"), {})
        assert y < 60

    def test_empty_ledger_falls_back_to_legacy_pct_and_rating(self):
        # Same PHI 101 sanity-check values as
        # test_dot_position_low_coverage_needs_redesign_is_bottom_right.
        x, y = brief._verdict_dot_xy(self._sc([], coverage=63.8, rating="Needs redesign"), {})
        assert x > 116
        assert y > 85

    def test_ungraded_items_excluded_from_ledger_counts(self):
        # A single graded+secured item plus a bunch of ungraded noise must
        # read as fully secured (1/1), not diluted by the ungraded entries.
        ledger = [_ledger_item(1, "secured")] + [
            _ledger_item(i, "unsecured", graded=False) for i in range(2, 5)
        ]
        x, _y = brief._verdict_dot_xy(self._sc(ledger), {})
        assert x > 150

    def test_explicit_xy_override_still_wins_over_ledger_counts(self):
        ledger = [_ledger_item(i, "unsecured") for i in range(4)]
        x, y = brief._verdict_dot_xy(self._sc(ledger), {"verdict": {"x": 1.0, "y": 1.0}})
        assert x > 150
        assert y < 60


class TestMissingFields:
    def test_empty_brief_renders_masthead_only(self):
        html = brief.render(_scorecard(), {})
        assert html.startswith("<!DOCTYPE html")
        assert "<h1>COM 100: Introduction to Communication</h1>" in html
        assert "Course at a Glance" not in html
        assert "Improvement Opportunities" not in html

    def test_no_narrative_at_all(self):
        html = brief.render(_scorecard(), None)
        assert "COM 100: Introduction to Communication" in html

    def test_missing_course_name_defaults(self):
        html = brief.render({}, {})
        assert "<h1>Course</h1>" in html

    def test_partial_brief_skips_absent_sections(self):
        html = brief.render(_scorecard(), {"brief": {"working": ["a"], "exposed": ["b"]}})
        assert "What&rsquo;s Working" in html
        assert "The Constraint" not in html
        assert "Improvement Opportunities" not in html
        assert "Course at a Glance" not in html

    def test_constraint_frames_itself_as_not_a_problem(self):
        # The frame line disambiguates the section from a quality judgment.
        html = brief.render(_scorecard(), {"brief": {"barrier": "no single lever to pull."}})
        assert "The Constraint" in html
        assert "Not a problem to solve" in html
        assert "no single lever to pull." in html


class TestEscaping:
    def test_xss_in_every_brief_field_escaped(self):
        p = "<script>alert(1)</script>"
        b = {"brief": {
            "period_lines": [p],
            "glance": [{"value": p, "label": p, "denom": p, "note": p}],
            "about": p, "how_graded": p,
            "graded_items": [{"count": p, "label": p, "weight_pct": p}],
            "working": [p], "exposed": [p], "barrier": p,
            "directions": [{"lead": p, "text": p}],
            "fetched": p,
        }}
        html = brief.render(_scorecard(), b)
        assert "<script>alert(1)</script>" not in html
        assert "&lt;script&gt;" in html

    def test_course_name_escaped(self):
        html = brief.render({"course": {"name": "<b>X</b>"}}, {})
        assert "<h1><b>X</b></h1>" not in html
        assert "&lt;b&gt;X&lt;/b&gt;" in html


class TestStatHelper:
    def test_stat_with_denom_and_note(self):
        cell = brief._stat("4.5", "Course eval", denom="/5", sub="above avg", sub_up=True)
        assert '4.5<span class="d">/5</span>' in cell
        assert '<span class="sub up">above avg</span>' in cell

    def test_stat_plain(self):
        cell = brief._stat("~600", "Students / term")
        assert '<span class="fig">~600</span>' in cell
        assert '<span class="lab">Students / term</span>' in cell
        assert "sub" not in cell


class TestPercentHelper:
    def test_integer_weight_no_decimal(self):
        assert brief._pct(57) == "57%"
        assert brief._pct(57.0) == "57%"

    def test_fractional_weight_kept(self):
        assert brief._pct(11.4) == "11.4%"

    def test_non_numeric_passthrough_escaped(self):
        assert brief._pct("n/a") == "n/a"


class TestCLI:
    def test_main_writes_output(self, tmp_path):
        import json
        sc = tmp_path / "sc.json"
        sc.write_text(json.dumps(_scorecard()), encoding="utf-8")
        narr = tmp_path / "narr.json"
        narr.write_text(json.dumps(_full_brief()), encoding="utf-8")
        out = tmp_path / "brief.html"
        brief.main(["--scorecard", str(sc), "--narrative", str(narr), "--output", str(out)])
        assert out.exists()
        assert "Improvement Opportunities" in out.read_text(encoding="utf-8")


# The .canvaslink CSS rule is always in the <style> block, so absence must be
# asserted on the rendered markup, not on the bare class name.
_LINK_DIV = '<div class="canvaslink">'


class TestCourseLink:
    """The brief links the live Canvas course so an ID can confirm the shell."""

    def _html(self, url):
        return brief.render({"course": {"name": "PHI 101"}},
                            {"brief": {"course_url": url}})

    def test_link_renders_with_href_and_label(self):
        html = self._html("https://canvas.asu.edu/courses/232013")
        assert 'href="https://canvas.asu.edu/courses/232013"' in html
        assert "canvas.asu.edu/courses/232013</a>" in html  # scheme stripped from label

    def test_absent_when_not_supplied(self):
        html = brief.render({"course": {"name": "PHI 101"}}, {"brief": {}})
        assert _LINK_DIV not in html

    def test_javascript_scheme_is_rejected(self):
        # html.escape does not neutralize a javascript: href; the allowlist must.
        html = self._html("javascript:alert(1)")
        assert "javascript:" not in html
        assert _LINK_DIV not in html

    def test_other_schemes_rejected(self):
        for bad in ("data:text/html,<script>x</script>", "file:///etc/passwd",
                    "vbscript:msgbox", "  javascript:alert(1)", "JaVaScRiPt:alert(1)"):
            assert _LINK_DIV not in self._html(bad), f"accepted unsafe scheme: {bad!r}"

    def test_http_allowed(self):
        assert 'href="http://example.edu/courses/1"' in self._html("http://example.edu/courses/1")

    def test_quotes_in_url_are_escaped(self):
        html = self._html('https://x.edu/"><script>alert(1)</script>')
        assert "<script>" not in html
        assert "&quot;" in html

    def test_none_and_empty_are_safe(self):
        for v in (None, "", "   "):
            assert _LINK_DIV not in self._html(v)

    def test_link_never_has_empty_accessible_name(self):
        # A bare scheme leaves nothing after "://"; the label falls back to the
        # full url so the anchor is never empty (WCAG 2.4.4 link purpose).
        html = self._html("http://")
        assert "<a href=\"http://\"></a>" not in html
        assert ">http://</a>" in html


# ---------------------------------------------------------------------------
# Verdict-matrix colors (assurance accuracy v2, workstream 4a)
# ---------------------------------------------------------------------------

def _extract_svg(html: str) -> str:
    start = html.index("<svg")
    end = html.index("</svg>") + len("</svg>")
    return html[start:end]


class TestVerdictSvgFunction:
    """_verdict_svg() is the shared matrix renderer -- assurance_report_html.py
    imports it directly, so the brief's and the report's matrices can never
    drift apart."""

    def test_returns_svg_markup(self):
        svg = brief._verdict_svg("PHI 101", 120.0, 60.0)
        assert svg.startswith("<svg")
        assert svg.endswith("</svg>")

    def test_no_green_goal_fill(self):
        assert "#2f7d32" not in brief._verdict_svg("PHI 101", 120.0, 60.0)

    def test_no_maroon_anywhere(self):
        assert "#8c1d40" not in brief._verdict_svg("PHI 101", 120.0, 60.0)

    def test_gold_on_goal_marker(self):
        svg = brief._verdict_svg("PHI 101", 120.0, 60.0)
        assert "#ffc627" in svg

    def test_ink_on_course_dot(self):
        svg = brief._verdict_svg("PHI 101", 120.0, 60.0)
        assert 'fill="#12100e"' in svg

    def test_proven_but_shallow_is_muted(self):
        svg = brief._verdict_svg("PHI 101", 120.0, 60.0)
        assert svg.count("#8f877a") >= 3

    def test_course_code_is_escaped(self):
        svg = brief._verdict_svg("<script>alert(1)</script>", 120.0, 60.0)
        assert "<script>alert(1)</script>" not in svg
        assert "&lt;script&gt;" in svg


class TestVerdictMatrixColorsInRenderedBrief:
    """Same color checks, exercised through the full render() path with real
    verdict narrative so the SVG actually appears in the page."""

    def _svg(self):
        html = brief.render(_verdict_scorecard(), _verdict_narrative())
        return _extract_svg(html)

    def test_no_green_or_maroon_in_matrix(self):
        svg = self._svg()
        assert "#2f7d32" not in svg
        assert "#8c1d40" not in svg

    def test_has_gold_and_ink(self):
        svg = self._svg()
        assert "#ffc627" in svg
        assert 'fill="#12100e"' in svg
