| from __future__ import annotations |
| |
| import typing as t |
| |
| import pytest |
| |
| from markupsafe import escape |
| from markupsafe import Markup |
| |
| |
| @pytest.mark.parametrize( |
| ("value", "expect"), |
| ( |
| # empty |
| ("", ""), |
| # ascii |
| ("abcd&><'\"efgh", "abcd&><'"efgh"), |
| ("&><'\"efgh", "&><'"efgh"), |
| ("abcd&><'\"", "abcd&><'""), |
| # 2 byte |
| ("こんにちは&><'\"こんばんは", "こんにちは&><'"こんばんは"), |
| ("&><'\"こんばんは", "&><'"こんばんは"), |
| ("こんにちは&><'\"", "こんにちは&><'""), |
| # 4 byte |
| ( |
| "\U0001f363\U0001f362&><'\"\U0001f37a xyz", |
| "\U0001f363\U0001f362&><'"\U0001f37a xyz", |
| ), |
| ("&><'\"\U0001f37a xyz", "&><'"\U0001f37a xyz"), |
| ("\U0001f363\U0001f362&><'\"", "\U0001f363\U0001f362&><'""), |
| ), |
| ) |
| def test_escape(value: str, expect: str) -> None: |
| assert escape(value) == Markup(expect) |
| |
| |
| class Proxy: |
| def __init__(self, value: t.Any) -> None: |
| self.__value = value |
| |
| @property # type: ignore[misc] |
| def __class__(self) -> type[t.Any]: |
| # Make o.__class__ and isinstance(o, str) see the proxied object. |
| return self.__value.__class__ # type: ignore[no-any-return] |
| |
| def __str__(self) -> str: |
| return str(self.__value) |
| |
| |
| def test_proxy() -> None: |
| """Handle a proxy object that pretends its __class__ is str.""" |
| p = Proxy("test") |
| assert p.__class__ is str |
| assert isinstance(p, str) |
| assert escape(p) == Markup("test") |
| |
| |
| class ReferenceStr(str): |
| def __str__(self) -> str: |
| # This should return a str, but it returns the subclass instead. |
| return self |
| |
| |
| def test_subclass() -> None: |
| """Handle if str(o) does not return a plain str.""" |
| s = ReferenceStr("test") |
| assert isinstance(s, str) |
| assert escape(s) == Markup("test") |