"""Tests for scripts/pdf_font_repair.py and its wiring into remediate_pdf.py.

CI-light: pure pikepdf fixtures built in-memory, no vendored ODL/java/verapdf.
"""

import json
import os
import sys

import pikepdf
import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))

import pdf_font_repair as pfr
import remediate_pdf as rp


# ── fixtures ─────────────────────────────────────────────────────────────

def _subset_type1_font(pdf, with_charset=True, subset=True):
    fd_dict = {"/Type": pikepdf.Name("/FontDescriptor")}
    if with_charset:
        fd_dict["/CharSet"] = pikepdf.String("/A/B/C")
    fd = pdf.make_indirect(pikepdf.Dictionary(fd_dict))
    name = "/ABCDEF+Georgia" if subset else "/Georgia"
    return pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"),
        "/Subtype": pikepdf.Name("/Type1"),
        "/BaseFont": pikepdf.Name(name),
        "/FontDescriptor": fd,
    }))


def _truetype_font_no_tounicode(pdf, encoding="/MacRomanEncoding", first=65, last=67):
    return pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"),
        "/Subtype": pikepdf.Name("/TrueType"),
        "/BaseFont": pikepdf.Name("/Arial"),
        "/Encoding": pikepdf.Name(encoding),
        "/FirstChar": first,
        "/LastChar": last,
    }))


_CMAP_TMPL = """/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
1 begincodespacerange
<00> <FF>
endcodespacerange
{body}
endcmap
end
end
"""


def _font_with_tounicode(pdf, body):
    stream = pdf.make_stream(_CMAP_TMPL.format(body=body).encode("latin-1"))
    return pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"),
        "/Subtype": pikepdf.Name("/Type1"),
        "/BaseFont": pikepdf.Name("/Helvetica"),
        "/ToUnicode": stream,
    }))


# ── pass 1: CharSet deletion ────────────────────────────────────────────

class TestCharSetDeletion:
    def test_subset_prefixed_charset_deleted(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        font = _subset_type1_font(pdf, with_charset=True, subset=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["charsets_deleted"] == 1
        assert "/CharSet" not in font.FontDescriptor

    def test_non_subset_name_keeps_charset(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        font = _subset_type1_font(pdf, with_charset=True, subset=False)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["charsets_deleted"] == 0
        assert "/CharSet" in font.FontDescriptor


# ── pass 2: build missing ToUnicode ─────────────────────────────────────

class TestBuildMissing:
    def test_builds_cmap_from_named_encoding(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        font = _truetype_font_no_tounicode(pdf)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_built"] == 1
        parsed = pfr._parse_existing_cmap(font.ToUnicode.read_bytes())
        assert parsed[0x41] == "0041"

    def test_no_encoding_no_build(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        font = pdf.make_indirect(pikepdf.Dictionary({
            "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/TrueType"),
            "/BaseFont": pikepdf.Name("/Arial"),
        }))
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_built"] == 0
        assert "/ToUnicode" not in font


# ── pass 3: rewrite existing ToUnicode ──────────────────────────────────

class TestRewriteExisting:
    def test_rewrite_full_coverage_gap_fill_and_scrub(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        # code 0x41 maps to forbidden U+0000; all other codes are gaps.
        font = _font_with_tounicode(pdf, "1 beginbfchar\n<41> <0000>\nendbfchar")
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_rewritten"] == 1
        parsed = pfr._parse_existing_cmap(font.ToUnicode.read_bytes())
        assert len(parsed) == 256
        assert parsed[0x41] == "FFFD"  # scrubbed forbidden value
        assert parsed[0x42] == "FFFD"  # gap fill
        assert all(int(v, 16) not in pfr.FORBIDDEN for v in parsed.values())

    def test_bfrange_expansion_preserved(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        font = _font_with_tounicode(pdf, "1 beginbfrange\n<41> <43> <0041>\nendbfrange")
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_rewritten"] == 1
        parsed = pfr._parse_existing_cmap(font.ToUnicode.read_bytes())
        assert parsed[0x41] == "0041"
        assert parsed[0x42] == "0042"
        assert parsed[0x43] == "0043"


# ── cycle guard ──────────────────────────────────────────────────────────

class TestCycleGuard:
    def test_recursive_form_resources_do_not_infinite_loop(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page()
        form_res = pikepdf.Dictionary({})
        form = pdf.make_indirect(pikepdf.Stream(
            pdf, b"", {"/Subtype": pikepdf.Name("/Form"), "/Resources": form_res}))
        font = _truetype_font_no_tounicode(pdf)
        form.Resources["/Font"] = pikepdf.Dictionary({"/F1": font})
        form.Resources["/XObject"] = pikepdf.Dictionary({"/Fx": form})  # self-cycle
        page.Resources = pikepdf.Dictionary({"/XObject": pikepdf.Dictionary({"/Fx": form})})

        counts = pfr.repair_fonts(pdf)  # would RecursionError without the guard

        assert counts["cmaps_built"] == 1


# ── remediate_pdf.py wiring ──────────────────────────────────────────────

def _tiny_pdf(path):
    import fitz  # PyMuPDF
    doc = fitz.open()
    page = doc.new_page(width=200, height=200)
    page.insert_text((10, 20), "Hello world", fontsize=10)
    doc.save(str(path))
    doc.close()
    return path


class TestRemediatePdfWiring:
    def test_e3_path_calls_repair_fonts_and_records_edits(self, tmp_path, monkeypatch):
        p = _tiny_pdf(tmp_path / "tagged.pdf")
        calls = []

        def fake_repair(pdf):
            calls.append(pdf)
            return {"charsets_deleted": 1, "cmaps_built": 0, "cmaps_rewritten": 0}

        monkeypatch.setattr(rp.pdf_font_repair, "repair_fonts", fake_repair)
        monkeypatch.setattr(rp.verapdf_gate, "run_verapdf",
                             lambda *_a, **_k: {"compliant": True, "failed_summaries": []})
        monkeypatch.setattr(rp.fidelity_gate, "pixel_diff",
                             lambda *_a, **_k: {"identical": True})

        result = rp.remediate_pdf(p, judgment={}, cls="digital-tagged")

        assert len(calls) == 1
        assert result["edits"]["font_repair"] == {
            "charsets_deleted": 1, "cmaps_built": 0, "cmaps_rewritten": 0}

    def test_e2_path_calls_repair_fonts_and_records_edits(self, tmp_path, monkeypatch):
        p = _tiny_pdf(tmp_path / "untagged.pdf")
        calls = []

        def fake_repair(pdf):
            calls.append(pdf)
            return {"charsets_deleted": 0, "cmaps_built": 2, "cmaps_rewritten": 0}

        def fake_run_odl(pdf_path, outdir, timeout=None):
            json_path = os.path.join(outdir, "manifest.json")
            with open(json_path, "w", encoding="utf-8") as f:
                json.dump({"kids": []}, f)
            tagged_path = os.path.join(outdir, "tagged.pdf")
            pikepdf.open(str(pdf_path)).save(tagged_path)
            return json_path, tagged_path

        monkeypatch.setattr(rp, "_run_odl", fake_run_odl)
        monkeypatch.setattr(rp.pdf_font_repair, "repair_fonts", fake_repair)

        edits, title = rp._run_e2(p, p, tmp_path / "out.pdf", {}, None, "en-US", [])

        assert len(calls) == 1
        assert edits["font_repair"] == {"charsets_deleted": 0, "cmaps_built": 2, "cmaps_rewritten": 0}

    def test_zero_counts_omitted_from_edits(self, tmp_path, monkeypatch):
        p = _tiny_pdf(tmp_path / "tagged.pdf")

        monkeypatch.setattr(rp.pdf_font_repair, "repair_fonts",
                             lambda pdf: {"charsets_deleted": 0, "cmaps_built": 0, "cmaps_rewritten": 0})
        monkeypatch.setattr(rp.verapdf_gate, "run_verapdf",
                             lambda *_a, **_k: {"compliant": True, "failed_summaries": []})
        monkeypatch.setattr(rp.fidelity_gate, "pixel_diff",
                             lambda *_a, **_k: {"identical": True})

        result = rp.remediate_pdf(p, judgment={}, cls="digital-tagged")

        assert "font_repair" not in result["edits"]


def test_type0_cid_font_untouched(tmp_path):
    """Reviewer finding: Type0/CID ToUnicode (2-byte codespace) must never be
    rewritten to a 1-byte 0-255 CMap — that corrupts CID text extraction."""
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(612, 792))
    cid_cmap = (b"/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n"
                b"1 begincodespacerange\n<0000> <FFFF>\nendcodespacerange\n"
                b"1 beginbfchar\n<01A4> <0041>\nendbfchar\n"
                b"endcmap\nend\nend")
    tu = pdf.make_stream(cid_cmap)
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/Type0"),
        "/BaseFont": pikepdf.Name("/ABCDEF+SomeCID"),
        "/ToUnicode": tu}))
    page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})
    before = font["/ToUnicode"].read_bytes()
    counts = pfr.repair_fonts(pdf)
    assert counts["cmaps_rewritten"] == 0 and counts["cmaps_built"] == 0
    assert font["/ToUnicode"].read_bytes() == before


def test_bfrange_destination_array_preserved(tmp_path):
    """Codex finding 1: <lo> <hi> [<d1> <d2>...] entries must survive rewrite."""
    cmap = (b"/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n"
            b"1 begincodespacerange\n<00> <FF>\nendcodespacerange\n"
            b"1 beginbfrange\n<41> <43> [<0066> <00660069> <0058>]\nendbfrange\n"
            b"endcmap\nend\nend")
    m = pfr._parse_existing_cmap(cmap)
    assert m[0x41] == "0066" and m[0x42] == "00660069" and m[0x43] == "0058"
    # and through the full rewrite: values preserved, multi-unit intact
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(612, 792))
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/TrueType"),
        "/BaseFont": pikepdf.Name("/Foo"), "/ToUnicode": pdf.make_stream(cmap)}))
    page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})
    pfr.repair_fonts(pdf)
    m2 = pfr._parse_existing_cmap(font["/ToUnicode"].read_bytes())
    assert m2[0x41] == "0066" and m2[0x42] == "00660069" and m2[0x43] == "0058"
    assert m2[0x20] == "FFFD"  # gap-filled


def test_build_full_coverage_ignores_declared_range():
    """Codex finding 2: coverage is 0-255 even when FirstChar/LastChar lie."""
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(612, 792))
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/TrueType"),
        "/BaseFont": pikepdf.Name("/Bar"),
        "/Encoding": pikepdf.Name("/MacRomanEncoding"),
        "/FirstChar": 65, "/LastChar": 67}))
    page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})
    counts = pfr.repair_fonts(pdf)
    assert counts["cmaps_built"] == 1
    m = pfr._parse_existing_cmap(font["/ToUnicode"].read_bytes())
    assert m[0x41] == "0041" and 0x00 in m and 0xFF in m and len(m) == 256


def test_repair_idempotent(tmp_path):
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(612, 792))
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/TrueType"),
        "/BaseFont": pikepdf.Name("/Baz"),
        "/Encoding": pikepdf.Name("/MacRomanEncoding")}))
    page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})
    pfr.repair_fonts(pdf)
    first = font["/ToUnicode"].read_bytes()
    # second run: rewrite of our own full-coverage output must be stable
    pfr.repair_fonts(pdf)
    assert font["/ToUnicode"].read_bytes() == first


# ── pass 4: CIDToGIDMap for CIDFontType2 ────────────────────────────────

def _type0_font(pdf, descendant_subtype="/CIDFontType2", with_c2g=False):
    cid_dict = {"/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name(descendant_subtype),
                "/BaseFont": pikepdf.Name("/ABCDEF+Some")}
    if with_c2g:
        cid_dict["/CIDToGIDMap"] = pikepdf.Name("/Identity")
    cid = pdf.make_indirect(pikepdf.Dictionary(cid_dict))
    return pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/Type0"),
        "/BaseFont": pikepdf.Name("/ABCDEF+Some"),
        "/DescendantFonts": pikepdf.Array([cid]),
    })), cid


class TestCIDToGIDMap:
    def test_cidfonttype2_no_map_gets_identity(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid = _type0_font(pdf, "/CIDFontType2", with_c2g=False)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidtogidmap_set"] == 1
        assert str(cid["/CIDToGIDMap"]) == "/Identity"

    def test_cidfonttype2_existing_map_untouched_idempotent(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid = _type0_font(pdf, "/CIDFontType2", with_c2g=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidtogidmap_set"] == 0
        assert str(cid["/CIDToGIDMap"]) == "/Identity"

    def test_cidfonttype0_not_touched(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid = _type0_font(pdf, "/CIDFontType0", with_c2g=False)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidtogidmap_set"] == 0
        assert "/CIDToGIDMap" not in cid


# ── pass 5: CIDSet deletion (7.21.4.2 CID counterpart of pass 1) ────────

def _type0_font_with_cidset(pdf, subset=True, with_cidset=True):
    base_name = "/ABCDEF+Some" if subset else "/Some"
    cid_fd_dict = {"/Type": pikepdf.Name("/FontDescriptor")}
    if with_cidset:
        cid_fd_dict["/CIDSet"] = pdf.make_stream(b"\xff\xff\xff")
    cid_fd = pdf.make_indirect(pikepdf.Dictionary(cid_fd_dict))
    cid = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/CIDFontType2"),
        "/BaseFont": pikepdf.Name(base_name), "/FontDescriptor": cid_fd,
    }))
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/Type0"),
        "/BaseFont": pikepdf.Name(base_name),
        "/DescendantFonts": pikepdf.Array([cid]),
    }))
    return font, cid, cid_fd


class TestCIDSetDeletion:
    def test_subset_prefixed_cidset_deleted(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid, cid_fd = _type0_font_with_cidset(pdf, subset=True, with_cidset=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidsets_deleted"] == 1
        assert "/CIDSet" not in cid_fd

    def test_non_subset_name_keeps_cidset(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid, cid_fd = _type0_font_with_cidset(pdf, subset=False, with_cidset=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidsets_deleted"] == 0
        assert "/CIDSet" in cid_fd

    def test_no_cidset_is_noop(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid, cid_fd = _type0_font_with_cidset(pdf, subset=True, with_cidset=False)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidsets_deleted"] == 0
        assert "/CIDSet" not in cid_fd

    def test_cidtogidmap_still_set_alongside_cidset_deletion(self):
        """Pass 4 and pass 5 both run on the same Type0 font in one visit."""
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid, cid_fd = _type0_font_with_cidset(pdf, subset=True, with_cidset=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cidsets_deleted"] == 1
        assert counts["cidtogidmap_set"] == 1
        assert str(cid["/CIDToGIDMap"]) == "/Identity"

    def test_idempotent(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font, cid, cid_fd = _type0_font_with_cidset(pdf, subset=True, with_cidset=True)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        first = pfr.repair_fonts(pdf)
        second = pfr.repair_fonts(pdf)

        assert first["cidsets_deleted"] == 1
        assert second["cidsets_deleted"] == 0
        assert "/CIDSet" not in cid_fd


# ── pass 2b: /Differences encoding -> ToUnicode via AGL ─────────────────

def _differences_font(pdf, diffs, base_encoding=None, first=1, last=3):
    enc_dict = {"/Differences": pikepdf.Array(diffs)}
    if base_encoding:
        enc_dict["/BaseEncoding"] = pikepdf.Name(base_encoding)
    return pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/Type1"),
        "/BaseFont": pikepdf.Name("/Custom"),
        "/Encoding": pikepdf.Dictionary(enc_dict),
        "/FirstChar": first, "/LastChar": last,
    }))


class TestDifferencesToUnicode:
    def test_builds_cmap_from_differences(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        diffs = [1, pikepdf.Name("/A"), 2, pikepdf.Name("/fi"), 3, pikepdf.Name("/bullet")]
        font = _differences_font(pdf, diffs)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_built"] == 1
        assert "/ToUnicode" in font
        raw = font["/ToUnicode"].read_bytes()
        assert b"<01> <0041>" in raw  # /A -> U+0041
        assert b"<02> <FB01>" in raw  # /fi -> U+FB01 ligature
        parsed = pfr._parse_existing_cmap(raw)
        assert parsed[1] == "0041"
        assert parsed[2] == "FB01"

    def test_winansi_base_encoding_non_overridden_codes_correct(self):
        """Blocker regression: a WinAnsi-base /Differences font that only
        overrides one code must still get CORRECT (not StandardEncoding-
        mismapped) Unicode for every other WinAnsi code in range."""
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        diffs = [0x80, pikepdf.Name("/Euro")]
        font = _differences_font(pdf, diffs, base_encoding="/WinAnsiEncoding",
                                  first=0x20, last=0xFF)
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_built"] == 1
        parsed = pfr._parse_existing_cmap(font["/ToUnicode"].read_bytes())
        assert parsed[0x80] == "20AC"  # overridden -> Euro
        assert parsed[0xE9] == "00E9"  # e-acute, WinAnsi-correct
        assert parsed[0xF1] == "00F1"  # n-tilde
        assert parsed[0xA9] == "00A9"  # copyright
        assert parsed[0x96] == "2013"  # en-dash
        assert parsed[0x92] == "2019"  # right single quote

    def test_named_encoding_still_uses_named_path(self):
        pdf = pikepdf.new()
        page = pdf.add_blank_page(page_size=(612, 792))
        font = _truetype_font_no_tounicode(pdf, encoding="/WinAnsiEncoding")
        page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})

        counts = pfr.repair_fonts(pdf)

        assert counts["cmaps_built"] == 1
        parsed = pfr._parse_existing_cmap(font.ToUnicode.read_bytes())
        assert parsed[0x41] == "0041"


def test_type0_charset_untouched():
    """Codex re-review: the CID gate covers the CharSet pass too."""
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(612, 792))
    fd = pikepdf.Dictionary({"/Type": pikepdf.Name("/FontDescriptor"),
                             "/CharSet": pikepdf.String("/A/B")})
    font = pdf.make_indirect(pikepdf.Dictionary({
        "/Type": pikepdf.Name("/Font"), "/Subtype": pikepdf.Name("/Type0"),
        "/BaseFont": pikepdf.Name("/ABCDEF+SomeCID"), "/FontDescriptor": fd}))
    page.Resources = pikepdf.Dictionary({"/Font": pikepdf.Dictionary({"/F1": font})})
    counts = pfr.repair_fonts(pdf)
    assert counts["charsets_deleted"] == 0
    assert "/CharSet" in font["/FontDescriptor"]
