feat: add Nex and Gopher listeners
Reuses md2txt's existing nex and text renderers (both already ship unmodified) -- rendered unwrapped gemtext still works for Gemini/Spartan clients that wrap themselves, but Nex and Gopher clients don't, so those two get the classic 80-column pre-wrap instead. Neither protocol has a redirect status of its own, so Site.resolve_flat() follows the /foo.md -> /foo canonical bounce and the WML-card-only -> parent redirect server-side and hands back real content directly, rather than leaving the two new listeners to invent a redirect convention that doesn't exist on the wire. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
12956a5034
commit
0b67069760
8 changed files with 290 additions and 13 deletions
|
|
@ -114,6 +114,58 @@ class TestWmlCardUrls:
|
|||
doc = site.resolve("/trail")
|
||||
assert b"{.card" not in doc.xhtml
|
||||
|
||||
def test_directive_line_does_not_leak_into_nex_or_gopher(self, site: Site):
|
||||
doc = site.resolve("/trail")
|
||||
assert b"{.card" not in doc.nex
|
||||
assert b"{.card" not in doc.gopher
|
||||
assert b"Cold and clear" in doc.nex
|
||||
assert b"Cold and clear" in doc.gopher
|
||||
|
||||
|
||||
class TestNexAndGopherRendering:
|
||||
def test_nex_and_gopher_fields_are_rendered(self, site: Site):
|
||||
doc = site.resolve("/about")
|
||||
assert isinstance(doc, Document)
|
||||
assert b"About" in doc.nex
|
||||
assert b"Body." in doc.nex
|
||||
# md2txt's `text` renderer (unlike `nex`) still FIGlet-banners
|
||||
# h1-h3 by default, so only plain paragraph text is checked here.
|
||||
assert b"Body." in doc.gopher
|
||||
|
||||
def test_nex_heading_has_no_figlet_banner(self, site: Site):
|
||||
# The nex renderer uses a plain setext-style underline, never a
|
||||
# FIGlet banner -- unlike md2txt's own `text` renderer, which does
|
||||
# use one for h1-h3 by default.
|
||||
doc = site.resolve("/")
|
||||
assert b"# Home" not in doc.nex
|
||||
assert b"Home" in doc.nex
|
||||
assert b"====" in doc.nex
|
||||
|
||||
|
||||
class TestResolveFlat:
|
||||
def test_canonical_md_redirect_is_resolved_not_bounced(self, site: Site):
|
||||
# Nex and Gopher have no redirect status: a request for the .md
|
||||
# form must come back with the real document, not a Redirect.
|
||||
resource = site.resolve_flat("/about.md")
|
||||
assert isinstance(resource, Document)
|
||||
assert b"About" in resource.nex
|
||||
|
||||
def test_unmatched_card_is_resolved_to_parent_document(self, site: Site):
|
||||
resource = site.resolve_flat("/trail/nonexistent-card")
|
||||
assert isinstance(resource, Document)
|
||||
assert b"North: open" in resource.gopher
|
||||
|
||||
def test_card_subpath_is_resolved_to_parent_document_not_the_wml_card(self, site: Site):
|
||||
# /trail/weather is WML-only URL space; resolve_flat must land on
|
||||
# trail.md's own Document (which has .nex/.gopher), never leak a
|
||||
# WmlCard (which has neither) out to the Nex/Gopher servers.
|
||||
resource = site.resolve_flat("/trail/weather")
|
||||
assert isinstance(resource, Document)
|
||||
|
||||
def test_still_raises_not_found_for_a_missing_path(self, site: Site):
|
||||
with pytest.raises(NotFound):
|
||||
site.resolve_flat("/nope")
|
||||
|
||||
|
||||
class TestHtmlFallbackHasNoXmlProlog:
|
||||
def test_html_field_has_no_prolog(self, site: Site):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue