from __future__ import annotations import typing as t import pytest from markupsafe import escape from markupsafe import escape_silent from markupsafe import Markup from markupsafe import soft_str def test_adding() -> None: unsafe = '' safe = Markup("username") assert unsafe + safe == str(escape(unsafe)) + str(safe) @pytest.mark.parametrize( ("template", "data", "expect"), ( ("%s", "", "<bad user>"), ( "%(username)s", {"username": ""}, "<bad user>", ), ("%i", 3.14, "3"), ("%.2f", 3.14, "3.14"), ), ) def test_string_interpolation(template: str, data: t.Any, expect: str) -> None: assert Markup(template) % data == expect def test_type_behavior() -> None: assert type(Markup("foo") + "bar") is Markup x = Markup("foo") assert x.__html__() is x def test_html_interop() -> None: class Foo: def __html__(self) -> str: return "awesome" def __str__(self) -> str: return "awesome" assert Markup(Foo()) == "awesome" result = Markup("%s") % Foo() assert result == "awesome" @pytest.mark.parametrize("args", ["foo", 42, ("foo", 42)]) def test_missing_interpol(args: t.Any) -> None: with pytest.raises(TypeError): assert Markup("") % args def test_tuple_interpol() -> None: result = Markup("%s:%s") % ("", "") expect = Markup("<foo>:<bar>") assert result == expect def test_dict_interpol() -> None: result = Markup("%(foo)s") % {"foo": ""} expect = Markup("<foo>") assert result == expect result = Markup("%(foo)s:%(bar)s") % {"foo": "", "bar": ""} expect = Markup("<foo>:<bar>") assert result == expect def test_escaping() -> None: assert escape("\"<>&'") == ""<>&'" assert ( Markup( "" "Foo & Bar" " \n " "" "" "" ).striptags() == "Foo & Bar" ) def test_unescape() -> None: assert Markup("<test>").unescape() == "" result = Markup("jack & tavi are cooler than mike & russ").unescape() expect = "jack & tavi are cooler than mike & russ" assert result == expect original = "&foo;" once = Markup(original).unescape() twice = Markup(once).unescape() expect = "&foo;" assert once == expect assert twice == expect def test_format() -> None: result = Markup("{awesome}").format(awesome="") assert result == "<awesome>" result = Markup("{0[1][bar]}").format([0, {"bar": ""}]) assert result == "<bar/>" result = Markup("{0[1][bar]}").format([0, {"bar": Markup("")}]) assert result == "" def test_format_map() -> None: result = Markup("{value}").format_map({"value": ""}) assert result == "<value>" def test_formatting_empty() -> None: formatted = Markup("{}").format(0) assert formatted == Markup("0") def test_custom_formatting() -> None: class HasHTMLOnly: def __html__(self) -> Markup: return Markup("") class HasHTMLAndFormat: def __html__(self) -> Markup: return Markup("") def __html_format__(self, spec: str) -> Markup: return Markup("") assert Markup("{0}").format(HasHTMLOnly()) == Markup("") assert Markup("{0}").format(HasHTMLAndFormat()) == Markup("") def test_complex_custom_formatting() -> None: class User: def __init__(self, id: int, username: str) -> None: self.id = id self.username = username def __html_format__(self, format_spec: str) -> Markup: if format_spec == "link": return Markup('{1}').format( self.id, self.__html__() ) elif format_spec: raise ValueError("Invalid format spec") return self.__html__() def __html__(self) -> Markup: return Markup("{0}").format(self.username) user = User(1, "foo") result = Markup("

User: {0:link}").format(user) expect = Markup('

User: foo') assert result == expect def test_formatting_with_objects() -> None: class Stringable: def __str__(self) -> str: return "строка" assert Markup("{s}").format(s=Stringable()) == Markup("строка") def test_escape_silent() -> None: assert escape_silent(None) == Markup() assert escape(None) == Markup(None) assert escape_silent("") == Markup("<foo>") def test_splitting() -> None: expect = [Markup("a"), Markup("b")] assert Markup("a b").split() == expect assert Markup("a b").rsplit() == expect assert Markup("a\nb").splitlines() == expect def test_mul() -> None: assert Markup("a") * 3 == Markup("aaa") def test_escape_return_type() -> None: assert isinstance(escape("a"), Markup) assert isinstance(escape(Markup("a")), Markup) class Foo: def __html__(self) -> str: return "Foo" assert isinstance(escape(Foo()), Markup) def test_soft_str() -> None: assert type(soft_str("")) is str # noqa: E721 assert type(soft_str(Markup())) is Markup # noqa: E721 assert type(soft_str(15)) is str # noqa: E721