Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions mkdocs_rss_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# ##################################

# standard library
import html as html_module
import json
from copy import deepcopy
from dataclasses import asdict
Expand Down Expand Up @@ -350,14 +351,17 @@ def on_page_content(
),
comments_url=page_url_comments,
created=page_dates[0],
description=self.util.get_description_or_abstract(
in_page=page,
chars_count=self.config.abstract_chars_count,
abstract_delimiter=self.config.abstract_delimiter,
description=html_module.unescape(
self.util.get_description_or_abstract(
in_page=page,
chars_count=self.config.abstract_chars_count,
abstract_delimiter=self.config.abstract_delimiter,
)
or ""
),
guid=page.canonical_url,
link=page_url_full,
title=page.title,
title=html_module.unescape(page.title) if page.title else None,
updated=page_dates[1],
# for later fetch
_mkdocs_page_ref=MkdocsPageSubset.from_page(page),
Expand Down
11 changes: 11 additions & 0 deletions tests/fixtures/docs/page_with_special_chars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: "Test: A & B <C> D"
authors:
- Test Author
date: 2024-01-15 10:00
description: "Description with & ampersand and <angle> brackets"
---

# Test page with special characters

This page tests that special characters are properly encoded in the RSS feed.
72 changes: 72 additions & 0 deletions tests/test_double_encoded_entities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#! python3 # noqa: E265

"""Test that title and description don't contain double-encoded HTML entities.

MkDocs pre-escapes content, so Jinja's |e filter should not double-encode.

Usage from the repo root folder:

python -m unittest tests.test_double_encoded_entities

"""

# #############################################################################
# ########## Libraries #############
# ##################################

# Standard library
import logging
import tempfile
from pathlib import Path
from traceback import format_exception

# test suite
from tests.base import BaseTest

# -- Globals --
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

OUTPUT_RSS_FEED_CREATED = "feed_rss_created.xml"

# #############################################################################
# ########## Classes ###############
# ##################################


class TestDoubleEncodedEntities(BaseTest):
"""Test that HTML entities are not double-encoded in RSS feed."""

def test_no_double_encoded_entities(self):
"""Verify that title and description don't contain double-encoded HTML entities.

MkDocs pre-escapes content, so Jinja's |e filter should not double-encode.
"""
with tempfile.TemporaryDirectory() as tmpdirname:
cli_result = self.build_docs_setup(
testproject_path="docs",
mkdocs_yml_filepath=Path("tests/fixtures/mkdocs_complete.yml"),
output_path=tmpdirname,
strict=True,
)

if cli_result.exception is not None:
e = cli_result.exception
logger.debug(format_exception(type(e), e, e.__traceback__))

self.assertEqual(cli_result.exit_code, 0)
self.assertIsNone(cli_result.exception)

# Read raw XML content
rss_path = Path(tmpdirname) / OUTPUT_RSS_FEED_CREATED
rss_content = rss_path.read_text()

# Check for double-encoded entities
double_encoded = ["&amp;amp;", "&amp;lt;", "&amp;gt;"]
for entity in double_encoded:
self.assertNotIn(
entity,
rss_content,
f"Found double-encoded HTML entity {entity} in RSS feed. "
"This indicates MkDocs pre-escaping combined with Jinja |e filter.",
)