import pytest
from flask import Markup

from notifications_utils.formatters import (
    unlink_govuk_escaped,
    notify_email_markdown,
    notify_letter_preview_markdown,
    notify_plain_text_email_markdown,
    sms_encode,
    formatted_list,
    strip_dvla_markup,
    strip_pipes,
    escape_html,
    remove_whitespace_before_punctuation,
    make_quotes_smart,
    replace_hyphens_with_en_dashes,
    tweak_dvla_list_markup,
    nl2li,
    strip_whitespace,
    strip_and_remove_obscure_whitespace,
    remove_smart_quotes_from_email_addresses,
    strip_unsupported_characters,
    normalise_whitespace
)
from notifications_utils.template import (
    HTMLEmailTemplate,
    PlainTextEmailTemplate,
    SMSMessageTemplate,
    SMSPreviewTemplate
)


@pytest.mark.parametrize(
    "url", [
        "http://example.com",
        "http://www.gov.uk/",
        "https://www.gov.uk/",
        "http://service.gov.uk",
        "http://service.gov.uk/blah.ext?q=a%20b%20c&order=desc#fragment",
        pytest.param("http://service.gov.uk/blah.ext?q=one two three", marks=pytest.mark.xfail),
    ]
)
def test_makes_links_out_of_URLs(url):
    link = '<a style="word-wrap: break-word; color: #005ea5;" href="{}">{}</a>'.format(url, url)
    assert (notify_email_markdown(url) == (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '{}'
        '</p>'
    ).format(link))


@pytest.mark.parametrize('input, output', [
    (
        (
            'this is some text with a link http://example.com in the middle'
        ),
        (
            'this is some text with a link '
            '<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a>'
            ' in the middle'
        ),
    ),
    (
        (
            'this link is in brackets (http://example.com)'
        ),
        (
            'this link is in brackets '
            '(<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a>)'
        ),
    )
])
def test_makes_links_out_of_URLs_in_context(input, output):
    assert notify_email_markdown(input) == (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '{}'
        '</p>'
    ).format(output)


@pytest.mark.parametrize(
    "url", [
        "example.com",
        "www.example.com",
        "ftp://example.com",
        "test@example.com",
        "mailto:test@example.com",
        "<a href=\"https://example.com\">Example</a>",
    ]
)
def test_doesnt_make_links_out_of_invalid_urls(url):
    assert notify_email_markdown(url) == (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '{}'
        '</p>'
    ).format(url)


def test_handles_placeholders_in_urls():
    assert notify_email_markdown(
        "http://example.com/?token=<span class='placeholder'>((token))</span>&key=1"
    ) == (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com/?token=">'
        'http://example.com/?token='
        '</a>'
        '<span class=\'placeholder\'>((token))</span>&amp;key=1'
        '</p>'
    )


@pytest.mark.parametrize(
    "url, expected_html, expected_html_in_template", [
        (
            """https://example.com"onclick="alert('hi')""",
            """<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert('hi</a>')""",  # noqa
            """<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert('hi</a>‘)""",  # noqa
        ),
        (
            """https://example.com"style='text-decoration:blink'""",
            """<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style='text-decoration:blink</a>'""",  # noqa
            """<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style='text-decoration:blink</a>’""",  # noqa
        ),
    ]
)
def test_URLs_get_escaped(url, expected_html, expected_html_in_template):
    assert notify_email_markdown(url) == (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '{}'
        '</p>'
    ).format(expected_html)
    assert expected_html_in_template in str(HTMLEmailTemplate({'content': url, 'subject': ''}))


def test_HTML_template_has_URLs_replaced_with_links():
    assert (
        '<a style="word-wrap: break-word; color: #005ea5;" href="https://service.example.com/accept_invite/a1b2c3d4">'
        'https://service.example.com/accept_invite/a1b2c3d4'
        '</a>'
    ) in str(HTMLEmailTemplate({'content': (
        'You’ve been invited to a service. Click this link:\n'
        'https://service.example.com/accept_invite/a1b2c3d4\n'
        '\n'
        'Thanks\n'
    ), 'subject': ''}))


@pytest.mark.parametrize('markdown_function, expected_output', [
    (notify_email_markdown, (
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        '<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com">'
        'https://example.com'
        '</a>'
        '</p>'
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
        'Next paragraph'
        '</p>'
    )),
    (notify_plain_text_email_markdown, (
        '\n'
        '\nhttps://example.com'
        '\n'
        '\nNext paragraph'
    )),
])
def test_preserves_whitespace_when_making_links(
    markdown_function, expected_output
):
    assert markdown_function(
        'https://example.com\n'
        '\n'
        'Next paragraph'
    ) == expected_output


@pytest.mark.parametrize(
    "template_content,expected", [
        ("gov.uk", u"gov.\u200Buk"),
        ("GOV.UK", u"GOV.\u200BUK"),
        ("Gov.uk", u"Gov.\u200Buk"),
        ("https://gov.uk", "https://gov.uk"),
        ("https://www.gov.uk", "https://www.gov.uk"),
        ("www.gov.uk", "www.gov.uk"),
        ("gov.uk/register-to-vote", "gov.uk/register-to-vote"),
        ("gov.uk?q=", "gov.uk?q=")
    ]
)
def test_escaping_govuk_in_email_templates(template_content, expected):
    assert unlink_govuk_escaped(template_content) == expected
    assert expected in str(PlainTextEmailTemplate({'content': template_content, 'subject': ''}))
    assert expected in str(HTMLEmailTemplate({'content': template_content, 'subject': ''}))


@pytest.mark.parametrize(
    "subject,expected", [
        ("bonjour | hi", "bonjour | hi"),
        ("bonjour .", "bonjour."),
        ('double -- dash', 'double \u2013 dash'),
    ]
)
def test_subject_is_cleaned_up(subject, expected):
    assert expected == HTMLEmailTemplate({'content': '', 'subject': subject}).subject


@pytest.mark.parametrize(
    "prefix, body, expected", [
        ("a", "b", "a: b"),
        (None, "b", "b"),
    ]
)
def test_sms_message_adds_prefix(prefix, body, expected):
    template = SMSMessageTemplate({'content': body})
    template.prefix = prefix
    template.sender = None
    assert str(template) == expected


def test_sms_preview_adds_newlines():
    template = SMSPreviewTemplate({'content': """
        the
        quick

        brown fox
    """})
    template.prefix = None
    template.sender = None
    assert '<br>' in str(template)


@pytest.mark.parametrize(
    'markdown_function, expected',
    (
        [
            notify_letter_preview_markdown,
            'print("hello")'
        ],
        [
            notify_email_markdown,
            'print("hello")'
        ],
        [
            notify_plain_text_email_markdown,
            'print("hello")'
        ],
    )
)
def test_block_code(markdown_function, expected):
    assert markdown_function('```\nprint("hello")\n```') == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>inset text</p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<blockquote '
            'style="Margin: 0 0 20px 0; border-left: 10px solid #BFC1C3;'
            'padding: 15px 0 0.1px 15px; font-size: 19px; line-height: 25px;'
            '">'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p>'
            '</blockquote>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\ninset text'
        ),
    ],
))
def test_block_quote(markdown_function, expected):
    assert markdown_function('^ inset text') == expected


@pytest.mark.parametrize('heading', (
    '# heading',
    '#heading',
))
@pytest.mark.parametrize(
    'markdown_function, expected',
    (
        [
            notify_letter_preview_markdown,
            '<h2>heading</h2>\n'
        ],
        [
            notify_email_markdown,
            (
                '<h2 style="Margin: 0 0 20px 0; padding: 0; font-size: 27px; '
                'line-height: 35px; font-weight: bold; color: #0B0C0C;">'
                'heading'
                '</h2>'
            )
        ],
        [
            notify_plain_text_email_markdown,
            (
                '\n'
                '\n'
                '\nheading'
                '\n-----------------------------------------------------------------'
            ),
        ],
    )
)
def test_level_1_header(markdown_function, heading, expected):
    assert markdown_function(heading) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>inset text</p>'
    ],
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p>'
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\ninset text'
        ),
    ],
))
def test_level_2_header(markdown_function, expected):
    assert markdown_function('## inset text') == (expected)


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>a</p>'
            '<div class="page-break">&nbsp;</div>'
            '<p>b</p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">a</p>'
            '<hr style="border: 0; height: 1px; background: #BFC1C3; Margin: 30px 0 30px 0;">'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">b</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\na'
            '\n'
            '\n================================================================='
            '\n'
            '\nb'
        ),
    ],
))
def test_hrule(markdown_function, expected):
    assert markdown_function('a\n\n***\n\nb') == expected
    assert markdown_function('a\n\n---\n\nb') == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<ol>\n'
            '<li>one</li>\n'
            '<li>two</li>\n'
            '<li>three</li>\n'
            '</ol>\n'
        )
    ],
    [
        notify_email_markdown,
        (
            '<table role="presentation" style="padding: 0 0 20px 0;">'
            '<tr>'
            '<td style="font-family: Helvetica, Arial, sans-serif;">'
            '<ol style="Margin: 0 0 0 20px; padding: 0; list-style-type: decimal;">'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">one</li>'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">two</li>'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">three</li>'
            '</ol>'
            '</td>'
            '</tr>'
            '</table>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\n1. one'
            '\n2. two'
            '\n3. three'
        ),
    ],
))
def test_ordered_list(markdown_function, expected):
    assert markdown_function(
        '1. one\n'
        '2. two\n'
        '3. three\n'
    ) == expected
    assert markdown_function(
        '1.one\n'
        '2.two\n'
        '3.three\n'
    ) == expected


@pytest.mark.parametrize('markdown', (
    (  # no space
        '*one\n'
        '*two\n'
        '*three\n'
    ),
    (  # single space
        '* one\n'
        '* two\n'
        '* three\n'
    ),
    (  # two spaces
        '*  one\n'
        '*  two\n'
        '*  three\n'
    ),
    (  # tab
        '*  one\n'
        '*  two\n'
        '*  three\n'
    ),
    (  # dash as bullet
        '- one\n'
        '- two\n'
        '- three\n'
    ),
    pytest.param((  # plus as bullet
        '+ one\n'
        '+ two\n'
        '+ three\n'
    ), marks=pytest.mark.xfail(raises=AssertionError)),
    (  # bullet as bullet
        '• one\n'
        '• two\n'
        '• three\n'
    ),
))
@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<ul>\n'
            '<li>one</li>\n'
            '<li>two</li>\n'
            '<li>three</li>\n'
            '</ul>\n'
        )
    ],
    [
        notify_email_markdown,
        (
            '<table role="presentation" style="padding: 0 0 20px 0;">'
            '<tr>'
            '<td style="font-family: Helvetica, Arial, sans-serif;">'
            '<ul style="Margin: 0 0 0 20px; padding: 0; list-style-type: disc;">'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">one</li>'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">two</li>'
            '<li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;'
            'line-height: 25px; color: #0B0C0C;">three</li>'
            '</ul>'
            '</td>'
            '</tr>'
            '</table>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\n• one'
            '\n• two'
            '\n• three'
        ),
    ],
))
def test_unordered_list(markdown, markdown_function, expected):
    assert markdown_function(markdown) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>+ one</p><p>+ two</p><p>+ three</p>',
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ one</p>'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ two</p>'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ three</p>'
        ),
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n\n+ one'
            '\n\n+ two'
            '\n\n+ three'
        ),
    ],
))
def test_pluses_dont_render_as_lists(markdown_function, expected):
    assert markdown_function(
        '+ one\n'
        '+ two\n'
        '+ three\n'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>'
            'line one<br>'
            'line two'
            '</p>'
            '<p>'
            'new paragraph'
            '</p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">line one<br />'
            'line two</p>'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">new paragraph</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\nline one'
            '\nline two'
            '\n'
            '\nnew paragraph'
        ),
    ],
))
def test_paragraphs(markdown_function, expected):
    assert markdown_function(
        'line one\n'
        'line two\n'
        '\n'
        'new paragraph'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>before</p>'
            '<p>after</p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">before</p>'
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">after</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\nbefore'
            '\n'
            '\nafter'
        ),
    ],
))
def test_multiple_newlines_get_truncated(markdown_function, expected):
    assert markdown_function(
        'before\n\n\n\n\n\nafter'
    ) == expected


@pytest.mark.parametrize('markdown_function', (
    notify_letter_preview_markdown, notify_email_markdown, notify_plain_text_email_markdown
))
def test_table(markdown_function):
    assert markdown_function(
        'col | col\n'
        '----|----\n'
        'val | val\n'
    ) == (
        ''
    )


@pytest.mark.parametrize('markdown_function, link, expected', (
    [
        notify_letter_preview_markdown,
        'http://example.com',
        '<p><strong>example.com</strong></p>'
    ],
    [
        notify_email_markdown,
        'http://example.com',
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
            '<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a>'
            '</p>'
        )
    ],
    [
        notify_email_markdown,
        """https://example.com"onclick="alert('hi')""",
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">'
            '<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">'
            'https://example.com"onclick="alert(\'hi'
            '</a>\')'
            '</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        'http://example.com',
        (
            '\n'
            '\nhttp://example.com'
        ),
    ],
))
def test_autolink(markdown_function, link, expected):
    assert markdown_function(link) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>variable called thing</p>'
    ],
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">variable called thing</p>'
    ],
    [
        notify_plain_text_email_markdown,
        '\n\nvariable called thing',
    ],
))
def test_codespan(markdown_function, expected):
    assert markdown_function(
        'variable called `thing`'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>something important</p>'
    ],
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something **important**</p>'
    ],
    [
        notify_plain_text_email_markdown,
        '\n\nsomething **important**',
    ],
))
def test_double_emphasis(markdown_function, expected):
    assert markdown_function(
        'something **important**'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>something important</p>'
    ],
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something *important*</p>'
    ],
    [
        notify_plain_text_email_markdown,
        '\n\nsomething *important*',
    ],
))
def test_emphasis(markdown_function, expected):
    assert markdown_function(
        'something *important*'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">foo ****** bar</p>'
    ],
    [
        notify_plain_text_email_markdown,
        '\n\nfoo ****** bar',
    ],
))
def test_nested_emphasis(markdown_function, expected):
    assert markdown_function(
        'foo ****** bar'
    ) == expected


@pytest.mark.parametrize('markdown_function', (
    notify_letter_preview_markdown, notify_email_markdown, notify_plain_text_email_markdown
))
def test_image(markdown_function):
    assert markdown_function(
        '![alt text](http://example.com/image.png)'
    ) == (
        ''
    )


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>Example: <strong>example.com</strong></p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; '
            'color: #0B0C0C;">'
            '<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">Example</a>'
            '</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\nExample: http://example.com'
        ),
    ],
))
def test_link(markdown_function, expected):
    assert markdown_function(
        '[Example](http://example.com)'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        (
            '<p>Example: <strong>example.com</strong></p>'
        )
    ],
    [
        notify_email_markdown,
        (
            '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; '
            'color: #0B0C0C;">'
            '<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com" title="An example URL">'
            'Example'
            '</a>'
            '</p>'
        )
    ],
    [
        notify_plain_text_email_markdown,
        (
            '\n'
            '\nExample (An example URL): http://example.com'
        ),
    ],
))
def test_link_with_title(markdown_function, expected):
    assert markdown_function(
        '[Example](http://example.com "An example URL")'
    ) == expected


@pytest.mark.parametrize('markdown_function, expected', (
    [
        notify_letter_preview_markdown,
        '<p>Strike</p>'
    ],
    [
        notify_email_markdown,
        '<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">Strike</p>'
    ],
    [
        notify_plain_text_email_markdown,
        '\n\nStrike'
    ],
))
def test_strikethrough(markdown_function, expected):
    assert markdown_function('~~Strike~~') == expected


def test_footnotes():
    # Can’t work out how to test this
    pass


def test_sms_encode():
    assert sms_encode('aàá…') == 'aàa...'


@pytest.mark.parametrize('items, kwargs, expected_output', [
    ([1], {}, '‘1’'),
    ([1, 2], {}, '‘1’ and ‘2’'),
    ([1, 2, 3], {}, '‘1’, ‘2’ and ‘3’'),
    ([1, 2, 3], {'prefix': 'foo', 'prefix_plural': 'bar'}, 'bar ‘1’, ‘2’ and ‘3’'),
    ([1], {'prefix': 'foo', 'prefix_plural': 'bar'}, 'foo ‘1’'),
    ([1, 2, 3], {'before_each': 'a', 'after_each': 'b'}, 'a1b, a2b and a3b'),
    ([1, 2, 3], {'conjunction': 'foo'}, '‘1’, ‘2’ foo ‘3’'),
    (['&'], {'before_each': '<i>', 'after_each': '</i>'}, '<i>&amp;</i>'),
    ([1, 2, 3], {'before_each': '<i>', 'after_each': '</i>'}, '<i>1</i>, <i>2</i> and <i>3</i>'),
])
def test_formatted_list(items, kwargs, expected_output):
    assert formatted_list(items, **kwargs) == expected_output


def test_formatted_list_returns_markup():
    assert isinstance(formatted_list([0]), Markup)


def test_removing_dvla_markup():
    assert strip_dvla_markup(
        (
            'some words & some more <words>'
            '<cr><h1><h2><p><normal><op><np><bul><tab>'
            '<CR><H1><H2><P><NORMAL><OP><NP><BUL><TAB>'
            '<tAb>'
        )
    ) == 'some words & some more <words>'


def test_removing_pipes():
    assert strip_pipes('|a|b|c') == 'abc'


def test_bleach_doesnt_try_to_make_valid_html_before_cleaning():
    assert escape_html(
        "<to cancel daily cat facts reply 'cancel'>"
    ) == (
        "&lt;to cancel daily cat facts reply 'cancel'&gt;"
    )


@pytest.mark.parametrize('dirty, clean', [
    (
        'Hello ((name)) ,\n\nThis is a message',
        'Hello ((name)),\n\nThis is a message'
    ),
    (
        'Hello Jo ,\n\nThis is a message',
        'Hello Jo,\n\nThis is a message'
    ),
    (
        '\n   \t    , word',
        '\n, word',
    ),
    (
        'bonjour | hi',
        'bonjour | hi',
    ),
])
def test_removing_whitespace_before_punctuation(dirty, clean):
    assert remove_whitespace_before_punctuation(dirty) == clean


@pytest.mark.parametrize('dirty, clean', [
    (
        'Hello ((name)) .\n\nThis is a message',
        'Hello ((name)).\n\nThis is a message'
    ),
    (
        'Hello Jo .\n\nThis is a message',
        'Hello Jo.\n\nThis is a message'
    ),
    (
        '\n   \t    . word',
        '\n. word',
    ),
])
def test_removing_whitespace_before_full_stops(dirty, clean):
    assert remove_whitespace_before_punctuation(dirty) == clean


@pytest.mark.parametrize('dumb, smart', [
    (
        """And I said, "what about breakfast at Tiffany's"?""",
        """And I said, “what about breakfast at Tiffany’s”?""",
    ),
    (
        """
            <a href="http://example.com?q='foo'">http://example.com?q='foo'</a>
        """,
        """
            <a href="http://example.com?q='foo'">http://example.com?q='foo'</a>
        """,
    ),
])
def test_smart_quotes(dumb, smart):
    assert make_quotes_smart(dumb) == smart


@pytest.mark.parametrize('nasty, nice', [
    (
        (
            'The en dash - always with spaces in running text when, as '
            'discussed in this section, indicating a parenthesis or '
            'pause - and the spaced em dash both have a certain '
            'technical advantage over the unspaced em dash. '
        ),
        (
            'The en dash \u2013 always with spaces in running text when, as '
            'discussed in this section, indicating a parenthesis or '
            'pause \u2013 and the spaced em dash both have a certain '
            'technical advantage over the unspaced em dash. '
        ),
    ),
    (
        'double -- dash',
        'double \u2013 dash',
    ),
    (
        'triple --- dash',
        'triple \u2013 dash',
    ),
    (
        'quadruple ---- dash',
        'quadruple ---- dash',
    ),
    (
        'em — dash',
        'em – dash',
    ),
    (
        'already\u0020–\u0020correct',  # \u0020 is a normal space character
        'already\u0020–\u0020correct',
    ),
    (
        '2004-2008',
        '2004-2008',  # no replacement
    ),
    (
        'bonjour | hi',
        'bonjour | hi',
    ),
])
def test_en_dashes(nasty, nice):
    assert replace_hyphens_with_en_dashes(nasty) == nice


def test_unicode_dash_lookup():
    en_dash_replacement_sequence = '\u0020\u2013'
    hyphen = '-'
    en_dash = '–'
    space = ' '
    non_breaking_space = ' '
    assert en_dash_replacement_sequence == space + en_dash
    assert non_breaking_space not in en_dash_replacement_sequence
    assert hyphen not in en_dash_replacement_sequence


@pytest.mark.parametrize('markup, expected_fixed', [
    (
        'a',
        'a',
    ),
    (
        'before<p><cr><p><cr>after',
        'before<p><cr>after',
    ),
    (
        'before<cr><cr><np>after',
        'before<cr><np>after',
    ),
    (
        'before{}<np>after'.format('<cr>' * 4),
        'before{}<np>after'.format('<cr>' * 3),
    ),
])
def test_tweaking_dvla_list_markup(markup, expected_fixed):
    assert tweak_dvla_list_markup(markup) == expected_fixed


def test_make_list_from_linebreaks():
    assert nl2li(
        'a\n'
        'b\n'
        'c\n'
    ) == (
        '<ul>'
        '<li>a</li>'
        '<li>b</li>'
        '<li>c</li>'
        '</ul>'
    )


@pytest.mark.parametrize('value', [
    'bar',
    ' bar ',
    """
        \t    bar
    """,
    ' \u180E\u200B \u200C bar \u200D \u2060\uFEFF ',
])
def test_strip_whitespace(value):
    assert strip_whitespace(value) == 'bar'


@pytest.mark.parametrize('value', [
    'notifications-email',
    '  \tnotifications-email \x0c ',
    '\rn\u200Coti\u200Dfi\u200Bcati\u2060ons-\u180Eemai\uFEFFl\uFEFF',
])
def test_strip_and_remove_obscure_whitespace(value):
    assert strip_and_remove_obscure_whitespace(value) == 'notifications-email'


def test_strip_and_remove_obscure_whitespace_only_removes_normal_whitespace_from_ends():
    sentence = '   words \n over multiple lines with \ttabs\t   '
    assert strip_and_remove_obscure_whitespace(sentence) == 'words \n over multiple lines with \ttabs'


def test_remove_smart_quotes_from_email_addresses():
    assert remove_smart_quotes_from_email_addresses("""
        line one’s quote
        first.o’last@example.com is someone’s email address
        line ‘three’
    """) == ("""
        line one’s quote
        first.o'last@example.com is someone’s email address
        line ‘three’
    """)


def test_strip_unsupported_characters():
    assert strip_unsupported_characters("line one\u2028line two") == ("line oneline two")


def test_normalise_whitespace():
    assert normalise_whitespace('\u200C Your tax   is\ndue\n\n') == 'Your tax is due'

[((52, 1, 72, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(52, 25, 52, 40): '"""input, output"""', (52, 42, 72, 1): '[(\'this is some text with a link http://example.com in the middle\',\n    \'this is some text with a link <a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a> in the middle\'\n    ), (\'this link is in brackets (http://example.com)\',\n    \'this link is in brackets (<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a>)\'\n    )]'}, {}), '(\'input, output\', [(\n    \'this is some text with a link http://example.com in the middle\',\n    \'this is some text with a link <a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a> in the middle\'\n    ), (\'this link is in brackets (http://example.com)\',\n    \'this link is in brackets (<a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a>)\'\n    )])', False, 'import pytest\n'), ((81, 1, 90, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(82, 4, 82, 9): '"""url"""', (82, 11, 89, 5): '[\'example.com\', \'www.example.com\', \'ftp://example.com\', \'test@example.com\',\n    \'mailto:test@example.com\', \'<a href="https://example.com">Example</a>\']'}, {}), '(\'url\', [\'example.com\', \'www.example.com\',\n    \'ftp://example.com\', \'test@example.com\', \'mailto:test@example.com\',\n    \'<a href="https://example.com">Example</a>\'])', False, 'import pytest\n'), ((112, 1, 125, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(113, 4, 113, 51): '"""url, expected_html, expected_html_in_template"""', (113, 53, 124, 5): '[(\'https://example.com"onclick="alert(\\\'hi\\\')\',\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>\\\')\'\n    ,\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>‘)\'\n    ), (\'https://example.com"style=\\\'text-decoration:blink\\\'\',\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style=\\\'text-decoration:blink</a>\\\'\'\n    ,\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style=\\\'text-decoration:blink</a>’\'\n    )]'}, {}), '(\'url, expected_html, expected_html_in_template\', [(\n    \'https://example.com"onclick="alert(\\\'hi\\\')\',\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>\\\')\'\n    ,\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>‘)\'\n    ), (\'https://example.com"style=\\\'text-decoration:blink\\\'\',\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style=\\\'text-decoration:blink</a>\\\'\'\n    ,\n    \'<a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22style=%27text-decoration:blink">https://example.com"style=\\\'text-decoration:blink</a>’\'\n    )])', False, 'import pytest\n'), ((148, 1, 165, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(148, 25, 148, 61): '"""markdown_function, expected_output"""', (148, 63, 165, 1): '[(notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="https://example.com">https://example.com</a></p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">Next paragraph</p>\'\n    ), (notify_plain_text_email_markdown,\n    """\n\nhttps://example.com\n\nNext paragraph""")]'}, {}), '(\'markdown_function, expected_output\', [(\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="https://example.com">https://example.com</a></p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">Next paragraph</p>\'\n    ), (notify_plain_text_email_markdown,\n    """\n\nhttps://example.com\n\nNext paragraph""")])', False, 'import pytest\n'), ((176, 1, 187, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(177, 4, 177, 31): '"""template_content,expected"""', (177, 33, 186, 5): "[('gov.uk', u'gov.\\u200buk'), ('GOV.UK', u'GOV.\\u200bUK'), ('Gov.uk',\n    u'Gov.\\u200buk'), ('https://gov.uk', 'https://gov.uk'), (\n    'https://www.gov.uk', 'https://www.gov.uk'), ('www.gov.uk',\n    'www.gov.uk'), ('gov.uk/register-to-vote', 'gov.uk/register-to-vote'),\n    ('gov.uk?q=', 'gov.uk?q=')]"}, {}), "('template_content,expected', [('gov.uk',\n    u'gov.\\u200buk'), ('GOV.UK', u'GOV.\\u200bUK'), ('Gov.uk',\n    u'Gov.\\u200buk'), ('https://gov.uk', 'https://gov.uk'), (\n    'https://www.gov.uk', 'https://www.gov.uk'), ('www.gov.uk',\n    'www.gov.uk'), ('gov.uk/register-to-vote', 'gov.uk/register-to-vote'),\n    ('gov.uk?q=', 'gov.uk?q=')])", False, 'import pytest\n'), ((194, 1, 200, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(195, 4, 195, 22): '"""subject,expected"""', (195, 24, 199, 5): "[('bonjour | hi', 'bonjour | hi'), ('bonjour .', 'bonjour.'), (\n    'double -- dash', 'double – dash')]"}, {}), "('subject,expected', [('bonjour | hi',\n    'bonjour | hi'), ('bonjour .', 'bonjour.'), ('double -- dash',\n    'double – dash')])", False, 'import pytest\n'), ((205, 1, 210, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(206, 4, 206, 28): '"""prefix, body, expected"""', (206, 30, 209, 5): "[('a', 'b', 'a: b'), (None, 'b', 'b')]"}, {}), "('prefix, body, expected', [('a', 'b', 'a: b'), (\n    None, 'b', 'b')])", False, 'import pytest\n'), ((230, 1, 246, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(231, 4, 231, 33): '"""markdown_function, expected"""', (232, 4, 245, 5): '([notify_letter_preview_markdown, \'print("hello")\'], [notify_email_markdown,\n    \'print("hello")\'], [notify_plain_text_email_markdown, \'print("hello")\'])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'print("hello")\'], [\n    notify_email_markdown, \'print("hello")\'], [\n    notify_plain_text_email_markdown, \'print("hello")\']))', False, 'import pytest\n'), ((251, 1, 276, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(251, 25, 251, 54): '"""markdown_function, expected"""', (251, 56, 276, 1): '([notify_letter_preview_markdown, \'<p>inset text</p>\'], [\n    notify_email_markdown,\n    \'<blockquote style="Margin: 0 0 20px 0; border-left: 10px solid #BFC1C3;padding: 15px 0 0.1px 15px; font-size: 19px; line-height: 25px;"><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p></blockquote>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\ninset text\'])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>inset text</p>\'], [\n    notify_email_markdown,\n    \'<blockquote style="Margin: 0 0 20px 0; border-left: 10px solid #BFC1C3;padding: 15px 0 0.1px 15px; font-size: 19px; line-height: 25px;"><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p></blockquote>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\ninset text\']))', False, 'import pytest\n'), ((281, 1, 284, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(281, 25, 281, 34): '"""heading"""', (281, 36, 284, 1): "('# heading', '#heading')"}, {}), "('heading', ('# heading', '#heading'))", False, 'import pytest\n'), ((285, 1, 311, 1), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(286, 4, 286, 33): '"""markdown_function, expected"""', (287, 4, 310, 5): '([notify_letter_preview_markdown, \'<h2>heading</h2>\\n\'], [\n    notify_email_markdown,\n    \'<h2 style="Margin: 0 0 20px 0; padding: 0; font-size: 27px; line-height: 35px; font-weight: bold; color: #0B0C0C;">heading</h2>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\n\nheading\n-----------------------------------------------------------------"""\n    ])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, """<h2>heading</h2>\n"""], [\n    notify_email_markdown,\n    \'<h2 style="Margin: 0 0 20px 0; padding: 0; font-size: 27px; line-height: 35px; font-weight: bold; color: #0B0C0C;">heading</h2>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\n\nheading\n-----------------------------------------------------------------"""\n    ]))', False, 'import pytest\n'), ((316, 1, 332, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(316, 25, 316, 54): '"""markdown_function, expected"""', (316, 56, 332, 1): '([notify_letter_preview_markdown, \'<p>inset text</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\ninset text\'])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>inset text</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">inset text</p>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\ninset text\']))', False, 'import pytest\n'), ((337, 1, 365, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(337, 25, 337, 54): '"""markdown_function, expected"""', (337, 56, 365, 1): '([notify_letter_preview_markdown,\n    \'<p>a</p><div class="page-break">&nbsp;</div><p>b</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">a</p><hr style="border: 0; height: 1px; background: #BFC1C3; Margin: 30px 0 30px 0;"><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">b</p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\na\n\n=================================================================\n\nb"""\n    ])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    \'<p>a</p><div class="page-break">&nbsp;</div><p>b</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">a</p><hr style="border: 0; height: 1px; background: #BFC1C3; Margin: 30px 0 30px 0;"><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">b</p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\na\n\n=================================================================\n\nb"""\n    ]))', False, 'import pytest\n'), ((371, 1, 410, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(371, 25, 371, 54): '"""markdown_function, expected"""', (371, 56, 410, 1): '([notify_letter_preview_markdown,\n    """<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n"""], [\n    notify_email_markdown,\n    \'<table role="presentation" style="padding: 0 0 20px 0;"><tr><td style="font-family: Helvetica, Arial, sans-serif;"><ol style="Margin: 0 0 0 20px; padding: 0; list-style-type: decimal;"><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">one</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">two</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">three</li></ol></td></tr></table>\'\n    ], [notify_plain_text_email_markdown, """\n\n1. one\n2. two\n3. three"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    """<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n"""], [\n    notify_email_markdown,\n    \'<table role="presentation" style="padding: 0 0 20px 0;"><tr><td style="font-family: Helvetica, Arial, sans-serif;"><ol style="Margin: 0 0 0 20px; padding: 0; list-style-type: decimal;"><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">one</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">two</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">three</li></ol></td></tr></table>\'\n    ], [notify_plain_text_email_markdown, """\n\n1. one\n2. two\n3. three"""]))', False, 'import pytest\n'), ((461, 1, 500, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(461, 25, 461, 54): '"""markdown_function, expected"""', (461, 56, 500, 1): '([notify_letter_preview_markdown,\n    """<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n"""], [\n    notify_email_markdown,\n    \'<table role="presentation" style="padding: 0 0 20px 0;"><tr><td style="font-family: Helvetica, Arial, sans-serif;"><ul style="Margin: 0 0 0 20px; padding: 0; list-style-type: disc;"><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">one</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">two</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">three</li></ul></td></tr></table>\'\n    ], [notify_plain_text_email_markdown, """\n\n• one\n• two\n• three"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    """<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n"""], [\n    notify_email_markdown,\n    \'<table role="presentation" style="padding: 0 0 20px 0;"><tr><td style="font-family: Helvetica, Arial, sans-serif;"><ul style="Margin: 0 0 0 20px; padding: 0; list-style-type: disc;"><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">one</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">two</li><li style="Margin: 5px 0 5px; padding: 0 0 0 5px; font-size: 19px;line-height: 25px; color: #0B0C0C;">three</li></ul></td></tr></table>\'\n    ], [notify_plain_text_email_markdown, """\n\n• one\n• two\n• three"""]))', False, 'import pytest\n'), ((505, 1, 526, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(505, 25, 505, 54): '"""markdown_function, expected"""', (505, 56, 526, 1): '([notify_letter_preview_markdown, \'<p>+ one</p><p>+ two</p><p>+ three</p>\'],\n    [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ one</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ two</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ three</p>\'\n    ], [notify_plain_text_email_markdown, """\n\n+ one\n\n+ two\n\n+ three"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    \'<p>+ one</p><p>+ two</p><p>+ three</p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ one</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ two</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">+ three</p>\'\n    ], [notify_plain_text_email_markdown, """\n\n+ one\n\n+ two\n\n+ three"""]))', False, 'import pytest\n'), ((535, 1, 566, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(535, 25, 535, 54): '"""markdown_function, expected"""', (535, 56, 566, 1): '([notify_letter_preview_markdown,\n    \'<p>line one<br>line two</p><p>new paragraph</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">line one<br />line two</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">new paragraph</p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\nline one\nline two\n\nnew paragraph"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    \'<p>line one<br>line two</p><p>new paragraph</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">line one<br />line two</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">new paragraph</p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\nline one\nline two\n\nnew paragraph"""]))', False, 'import pytest\n'), ((576, 1, 600, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(576, 25, 576, 54): '"""markdown_function, expected"""', (576, 56, 600, 1): '([notify_letter_preview_markdown, \'<p>before</p><p>after</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">before</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">after</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nbefore\n\nafter"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>before</p><p>after</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">before</p><p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">after</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nbefore\n\nafter"""]))', False, 'import pytest\n'), ((607, 1, 609, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(607, 25, 607, 44): '"""markdown_function"""', (607, 46, 609, 1): '(notify_letter_preview_markdown, notify_email_markdown,\n    notify_plain_text_email_markdown)'}, {}), "('markdown_function', (\n    notify_letter_preview_markdown, notify_email_markdown,\n    notify_plain_text_email_markdown))", False, 'import pytest\n'), ((620, 1, 654, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(620, 25, 620, 60): '"""markdown_function, link, expected"""', (620, 62, 654, 1): '([notify_letter_preview_markdown, \'http://example.com\',\n    \'<p><strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'http://example.com\',\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a></p>\'\n    ], [notify_email_markdown, \'https://example.com"onclick="alert(\\\'hi\\\')\',\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>\\\')</p>\'\n    ], [notify_plain_text_email_markdown, \'http://example.com\',\n    """\n\nhttp://example.com"""])'}, {}), '(\'markdown_function, link, expected\', ([\n    notify_letter_preview_markdown, \'http://example.com\',\n    \'<p><strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'http://example.com\',\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">http://example.com</a></p>\'\n    ], [notify_email_markdown, \'https://example.com"onclick="alert(\\\'hi\\\')\',\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="https://example.com%22onclick=%22alert%28%27hi">https://example.com"onclick="alert(\\\'hi</a>\\\')</p>\'\n    ], [notify_plain_text_email_markdown, \'http://example.com\',\n    """\n\nhttp://example.com"""]))', False, 'import pytest\n'), ((659, 1, 672, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(659, 25, 659, 54): '"""markdown_function, expected"""', (659, 56, 672, 1): '([notify_letter_preview_markdown, \'<p>variable called thing</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">variable called thing</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nvariable called thing"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>variable called thing</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">variable called thing</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nvariable called thing"""]))', False, 'import pytest\n'), ((679, 1, 692, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(679, 25, 679, 54): '"""markdown_function, expected"""', (679, 56, 692, 1): '([notify_letter_preview_markdown, \'<p>something important</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something **important**</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nsomething **important**"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>something important</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something **important**</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nsomething **important**"""]))', False, 'import pytest\n'), ((699, 1, 712, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(699, 25, 699, 54): '"""markdown_function, expected"""', (699, 56, 712, 1): '([notify_letter_preview_markdown, \'<p>something important</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something *important*</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nsomething *important*"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>something important</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">something *important*</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nsomething *important*"""]))', False, 'import pytest\n'), ((719, 1, 728, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(719, 25, 719, 54): '"""markdown_function, expected"""', (719, 56, 728, 1): '([notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">foo ****** bar</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nfoo ****** bar"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">foo ****** bar</p>\'\n    ], [notify_plain_text_email_markdown, """\n\nfoo ****** bar"""]))', False, 'import pytest\n'), ((735, 1, 737, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(735, 25, 735, 44): '"""markdown_function"""', (735, 46, 737, 1): '(notify_letter_preview_markdown, notify_email_markdown,\n    notify_plain_text_email_markdown)'}, {}), "('markdown_function', (\n    notify_letter_preview_markdown, notify_email_markdown,\n    notify_plain_text_email_markdown))", False, 'import pytest\n'), ((746, 1, 769, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(746, 25, 746, 54): '"""markdown_function, expected"""', (746, 56, 769, 1): '([notify_letter_preview_markdown,\n    \'<p>Example: <strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">Example</a></p>\'\n    ], [notify_plain_text_email_markdown, """\n\nExample: http://example.com"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    \'<p>Example: <strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com">Example</a></p>\'\n    ], [notify_plain_text_email_markdown, """\n\nExample: http://example.com"""])\n    )', False, 'import pytest\n'), ((776, 1, 801, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(776, 25, 776, 54): '"""markdown_function, expected"""', (776, 56, 801, 1): '([notify_letter_preview_markdown,\n    \'<p>Example: <strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com" title="An example URL">Example</a></p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\nExample (An example URL): http://example.com"""])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown,\n    \'<p>Example: <strong>example.com</strong></p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;"><a style="word-wrap: break-word; color: #005ea5;" href="http://example.com" title="An example URL">Example</a></p>\'\n    ], [notify_plain_text_email_markdown,\n    """\n\nExample (An example URL): http://example.com"""]))', False, 'import pytest\n'), ((808, 1, 821, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(808, 25, 808, 54): '"""markdown_function, expected"""', (808, 56, 821, 1): '([notify_letter_preview_markdown, \'<p>Strike</p>\'], [notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">Strike</p>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\nStrike\'])'}, {}), '(\'markdown_function, expected\', ([\n    notify_letter_preview_markdown, \'<p>Strike</p>\'], [\n    notify_email_markdown,\n    \'<p style="Margin: 0 0 20px 0; font-size: 11pt; line-height: 25px; color: #0B0C0C;">Strike</p>\'\n    ], [notify_plain_text_email_markdown, \'\\n\\nStrike\']))', False, 'import pytest\n'), ((835, 1, 845, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(835, 25, 835, 57): '"""items, kwargs, expected_output"""', (835, 59, 845, 1): "[([1], {}, '‘1’'), ([1, 2], {}, '‘1’ and ‘2’'), ([1, 2, 3], {},\n    '‘1’, ‘2’ and ‘3’'), ([1, 2, 3], {'prefix': 'foo', 'prefix_plural':\n    'bar'}, 'bar ‘1’, ‘2’ and ‘3’'), ([1], {'prefix': 'foo',\n    'prefix_plural': 'bar'}, 'foo ‘1’'), ([1, 2, 3], {'before_each': 'a',\n    'after_each': 'b'}, 'a1b, a2b and a3b'), ([1, 2, 3], {'conjunction':\n    'foo'}, '‘1’, ‘2’ foo ‘3’'), (['&'], {'before_each': '<i>',\n    'after_each': '</i>'}, '<i>&amp;</i>'), ([1, 2, 3], {'before_each':\n    '<i>', 'after_each': '</i>'}, '<i>1</i>, <i>2</i> and <i>3</i>')]"}, {}), "('items, kwargs, expected_output', [([1], {}, '‘1’'),\n    ([1, 2], {}, '‘1’ and ‘2’'), ([1, 2, 3], {}, '‘1’, ‘2’ and ‘3’'), ([1, \n    2, 3], {'prefix': 'foo', 'prefix_plural': 'bar'},\n    'bar ‘1’, ‘2’ and ‘3’'), ([1], {'prefix': 'foo', 'prefix_plural': 'bar'\n    }, 'foo ‘1’'), ([1, 2, 3], {'before_each': 'a', 'after_each': 'b'},\n    'a1b, a2b and a3b'), ([1, 2, 3], {'conjunction': 'foo'},\n    '‘1’, ‘2’ foo ‘3’'), (['&'], {'before_each': '<i>', 'after_each':\n    '</i>'}, '<i>&amp;</i>'), ([1, 2, 3], {'before_each': '<i>',\n    'after_each': '</i>'}, '<i>1</i>, <i>2</i> and <i>3</i>')])", False, 'import pytest\n'), ((877, 1, 894, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(877, 25, 877, 39): '"""dirty, clean"""', (877, 41, 894, 1): '[("""Hello ((name)) ,\n\nThis is a message""",\n    """Hello ((name)),\n\nThis is a message"""), (\n    """Hello Jo ,\n\nThis is a message""", """Hello Jo,\n\nThis is a message"""\n    ), (\'\\n   \\t    , word\', \'\\n, word\'), (\'bonjour | hi\', \'bonjour | hi\')]'}, {}), '(\'dirty, clean\', [(\n    """Hello ((name)) ,\n\nThis is a message""",\n    """Hello ((name)),\n\nThis is a message"""), (\n    """Hello Jo ,\n\nThis is a message""", """Hello Jo,\n\nThis is a message"""\n    ), (\'\\n   \\t    , word\', \'\\n, word\'), (\'bonjour | hi\', \'bonjour | hi\')])', False, 'import pytest\n'), ((899, 1, 912, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(899, 25, 899, 39): '"""dirty, clean"""', (899, 41, 912, 1): '[("""Hello ((name)) .\n\nThis is a message""",\n    """Hello ((name)).\n\nThis is a message"""), (\n    """Hello Jo .\n\nThis is a message""", """Hello Jo.\n\nThis is a message"""\n    ), (\'\\n   \\t    . word\', \'\\n. word\')]'}, {}), '(\'dirty, clean\', [(\n    """Hello ((name)) .\n\nThis is a message""",\n    """Hello ((name)).\n\nThis is a message"""), (\n    """Hello Jo .\n\nThis is a message""", """Hello Jo.\n\nThis is a message"""\n    ), (\'\\n   \\t    . word\', \'\\n. word\')])', False, 'import pytest\n'), ((917, 1, 930, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(917, 25, 917, 38): '"""dumb, smart"""', (917, 40, 930, 1): '[(\'And I said, "what about breakfast at Tiffany\\\'s"?\',\n    \'And I said, “what about breakfast at Tiffany’s”?\'), (\n    """\n            <a href="http://example.com?q=\'foo\'">http://example.com?q=\'foo\'</a>\n        """\n    ,\n    """\n            <a href="http://example.com?q=\'foo\'">http://example.com?q=\'foo\'</a>\n        """\n    )]'}, {}), '(\'dumb, smart\', [(\n    \'And I said, "what about breakfast at Tiffany\\\'s"?\',\n    \'And I said, “what about breakfast at Tiffany’s”?\'), (\n    """\n            <a href="http://example.com?q=\'foo\'">http://example.com?q=\'foo\'</a>\n        """\n    ,\n    """\n            <a href="http://example.com?q=\'foo\'">http://example.com?q=\'foo\'</a>\n        """\n    )])', False, 'import pytest\n'), ((935, 1, 978, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(935, 25, 935, 38): '"""nasty, nice"""', (935, 40, 978, 1): "[(\n    'The en dash - always with spaces in running text when, as discussed in this section, indicating a parenthesis or pause - and the spaced em dash both have a certain technical advantage over the unspaced em dash. '\n    ,\n    'The en dash – always with spaces in running text when, as discussed in this section, indicating a parenthesis or pause – and the spaced em dash both have a certain technical advantage over the unspaced em dash. '\n    ), ('double -- dash', 'double – dash'), ('triple --- dash',\n    'triple – dash'), ('quadruple ---- dash', 'quadruple ---- dash'), (\n    'em — dash', 'em – dash'), ('already – correct', 'already – correct'),\n    ('2004-2008', '2004-2008'), ('bonjour | hi', 'bonjour | hi')]"}, {}), "('nasty, nice', [(\n    'The en dash - always with spaces in running text when, as discussed in this section, indicating a parenthesis or pause - and the spaced em dash both have a certain technical advantage over the unspaced em dash. '\n    ,\n    'The en dash – always with spaces in running text when, as discussed in this section, indicating a parenthesis or pause – and the spaced em dash both have a certain technical advantage over the unspaced em dash. '\n    ), ('double -- dash', 'double – dash'), ('triple --- dash',\n    'triple – dash'), ('quadruple ---- dash', 'quadruple ---- dash'), (\n    'em — dash', 'em – dash'), ('already – correct', 'already – correct'),\n    ('2004-2008', '2004-2008'), ('bonjour | hi', 'bonjour | hi')])", False, 'import pytest\n'), ((1030, 1, 1037, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(1030, 25, 1030, 32): '"""value"""', (1030, 34, 1037, 1): '[\'bar\', \' bar \', """\n        \t    bar\n    """,\n    \' \\u180e\\u200b \\u200c bar \\u200d \\u2060\\ufeff \']'}, {}), '(\'value\', [\'bar\', \' bar \',\n    """\n        \t    bar\n    """,\n    \' \\u180e\\u200b \\u200c bar \\u200d \\u2060\\ufeff \'])', False, 'import pytest\n'), ((1042, 1, 1046, 2), 'pytest.mark.parametrize', 'pytest.mark.parametrize', ({(1042, 25, 1042, 32): '"""value"""', (1042, 34, 1046, 1): "['notifications-email', '  \\tnotifications-email \\x0c ',\n    '\\rn\\u200coti\\u200dfi\\u200bcati\\u2060ons-\\u180eemai\\ufeffl\\ufeff']"}, {}), "('value', ['notifications-email',\n    '  \\tnotifications-email \\x0c ',\n    '\\rn\\u200coti\\u200dfi\\u200bcati\\u2060ons-\\u180eemai\\ufeffl\\ufeff'])", False, 'import pytest\n'), ((212, 15, 212, 52), 'notifications_utils.template.SMSMessageTemplate', 'SMSMessageTemplate', ({(212, 34, 212, 51): "{'content': body}"}, {}), "({'content': body})", False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((219, 15, 224, 9), 'notifications_utils.template.SMSPreviewTemplate', 'SMSPreviewTemplate', ({(219, 34, 224, 8): '{\'content\': """\n        the\n        quick\n\n        brown fox\n    """}'}, {}), '({\'content\':\n    """\n        the\n        quick\n\n        brown fox\n    """})', False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((45, 12, 45, 38), 'notifications_utils.formatters.notify_email_markdown', 'notify_email_markdown', ({(45, 34, 45, 37): 'url'}, {}), '(url)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((40, 8, 40, 95), 'pytest.param', 'pytest.param', (), '', False, 'import pytest\n'), ((74, 11, 74, 39), 'notifications_utils.formatters.notify_email_markdown', 'notify_email_markdown', ({(74, 33, 74, 38): 'input'}, {}), '(input)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((92, 11, 92, 37), 'notifications_utils.formatters.notify_email_markdown', 'notify_email_markdown', ({(92, 33, 92, 36): 'url'}, {}), '(url)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((100, 11, 102, 5), 'notifications_utils.formatters.notify_email_markdown', 'notify_email_markdown', ({(101, 8, 101, 84): '"""http://example.com/?token=<span class=\'placeholder\'>((token))</span>&key=1"""'}, {}), '(\n    "http://example.com/?token=<span class=\'placeholder\'>((token))</span>&key=1"\n    )', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((127, 11, 127, 37), 'notifications_utils.formatters.notify_email_markdown', 'notify_email_markdown', ({(127, 33, 127, 36): 'url'}, {}), '(url)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((189, 11, 189, 49), 'notifications_utils.formatters.unlink_govuk_escaped', 'unlink_govuk_escaped', ({(189, 32, 189, 48): 'template_content'}, {}), '(template_content)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((832, 11, 832, 33), 'notifications_utils.formatters.sms_encode', 'sms_encode', ({(832, 22, 832, 32): '"""aàá…"""'}, {}), "('aàá…')", False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((847, 11, 847, 42), 'notifications_utils.formatters.formatted_list', 'formatted_list', ({(847, 26, 847, 31): 'items'}, {}), '(items, **kwargs)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((851, 22, 851, 41), 'notifications_utils.formatters.formatted_list', 'formatted_list', ({(851, 37, 851, 40): '[0]'}, {}), '([0])', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((855, 11, 862, 5), 'notifications_utils.formatters.strip_dvla_markup', 'strip_dvla_markup', ({(857, 12, 860, 19): '"""some words & some more <words><cr><h1><h2><p><normal><op><np><bul><tab><CR><H1><H2><P><NORMAL><OP><NP><BUL><TAB><tAb>"""'}, {}), "(\n    'some words & some more <words><cr><h1><h2><p><normal><op><np><bul><tab><CR><H1><H2><P><NORMAL><OP><NP><BUL><TAB><tAb>'\n    )", False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((866, 11, 866, 32), 'notifications_utils.formatters.strip_pipes', 'strip_pipes', ({(866, 23, 866, 31): '"""|a|b|c"""'}, {}), "('|a|b|c')", False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((870, 11, 872, 5), 'notifications_utils.formatters.escape_html', 'escape_html', ({(871, 8, 871, 52): '"""<to cancel daily cat facts reply \'cancel\'>"""'}, {}), '("<to cancel daily cat facts reply \'cancel\'>")', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((896, 11, 896, 54), 'notifications_utils.formatters.remove_whitespace_before_punctuation', 'remove_whitespace_before_punctuation', ({(896, 48, 896, 53): 'dirty'}, {}), '(dirty)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((914, 11, 914, 54), 'notifications_utils.formatters.remove_whitespace_before_punctuation', 'remove_whitespace_before_punctuation', ({(914, 48, 914, 53): 'dirty'}, {}), '(dirty)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((932, 11, 932, 34), 'notifications_utils.formatters.make_quotes_smart', 'make_quotes_smart', ({(932, 29, 932, 33): 'dumb'}, {}), '(dumb)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((980, 11, 980, 48), 'notifications_utils.formatters.replace_hyphens_with_en_dashes', 'replace_hyphens_with_en_dashes', ({(980, 42, 980, 47): 'nasty'}, {}), '(nasty)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1013, 11, 1013, 41), 'notifications_utils.formatters.tweak_dvla_list_markup', 'tweak_dvla_list_markup', ({(1013, 34, 1013, 40): 'markup'}, {}), '(markup)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1017, 11, 1021, 5), 'notifications_utils.formatters.nl2li', 'nl2li', ({(1018, 8, 1020, 13): '"""a\nb\nc\n"""'}, {}), "('a\\nb\\nc\\n')", False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1039, 11, 1039, 34), 'notifications_utils.formatters.strip_whitespace', 'strip_whitespace', ({(1039, 28, 1039, 33): 'value'}, {}), '(value)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1048, 11, 1048, 53), 'notifications_utils.formatters.strip_and_remove_obscure_whitespace', 'strip_and_remove_obscure_whitespace', ({(1048, 47, 1048, 52): 'value'}, {}), '(value)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1053, 11, 1053, 56), 'notifications_utils.formatters.strip_and_remove_obscure_whitespace', 'strip_and_remove_obscure_whitespace', ({(1053, 47, 1053, 55): 'sentence'}, {}), '(sentence)', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1057, 11, 1061, 8), 'notifications_utils.formatters.remove_smart_quotes_from_email_addresses', 'remove_smart_quotes_from_email_addresses', ({(1057, 52, 1061, 7): '"""\n        line one’s quote\n        first.o’last@example.com is someone’s email address\n        line ‘three’\n    """'}, {}), '(\n    """\n        line one’s quote\n        first.o’last@example.com is someone’s email address\n        line ‘three’\n    """\n    )', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1069, 11, 1069, 65), 'notifications_utils.formatters.strip_unsupported_characters', 'strip_unsupported_characters', ({(1069, 40, 1069, 64): '"""line one\u2028line two"""'}, {}), "('line one\\u2028line two')", False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((1073, 11, 1073, 64), 'notifications_utils.formatters.normalise_whitespace', 'normalise_whitespace', ({(1073, 32, 1073, 63): '"""\u200c Your tax   is\ndue\n\n"""'}, {}), '("""\u200c Your tax   is\ndue\n\n""")', False, 'from notifications_utils.formatters import unlink_govuk_escaped, notify_email_markdown, notify_letter_preview_markdown, notify_plain_text_email_markdown, sms_encode, formatted_list, strip_dvla_markup, strip_pipes, escape_html, remove_whitespace_before_punctuation, make_quotes_smart, replace_hyphens_with_en_dashes, tweak_dvla_list_markup, nl2li, strip_whitespace, strip_and_remove_obscure_whitespace, remove_smart_quotes_from_email_addresses, strip_unsupported_characters, normalise_whitespace\n'), ((132, 44, 132, 94), 'notifications_utils.template.HTMLEmailTemplate', 'HTMLEmailTemplate', ({(132, 62, 132, 93): "{'content': url, 'subject': ''}"}, {}), "({'content': url, 'subject': ''})", False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((140, 13, 145, 22), 'notifications_utils.template.HTMLEmailTemplate', 'HTMLEmailTemplate', ({(140, 31, 145, 21): '{\'content\':\n    """You’ve been invited to a service. Click this link:\nhttps://service.example.com/accept_invite/a1b2c3d4\n\nThanks\n"""\n    , \'subject\': \'\'}'}, {}), '({\'content\':\n    """You’ve been invited to a service. Click this link:\nhttps://service.example.com/accept_invite/a1b2c3d4\n\nThanks\n"""\n    , \'subject\': \'\'})', False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((190, 27, 190, 95), 'notifications_utils.template.PlainTextEmailTemplate', 'PlainTextEmailTemplate', ({(190, 50, 190, 94): "{'content': template_content, 'subject': ''}"}, {}), "({'content': template_content, 'subject': ''})", False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((191, 27, 191, 90), 'notifications_utils.template.HTMLEmailTemplate', 'HTMLEmailTemplate', ({(191, 45, 191, 89): "{'content': template_content, 'subject': ''}"}, {}), "({'content': template_content, 'subject': ''})", False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((202, 23, 202, 77), 'notifications_utils.template.HTMLEmailTemplate', 'HTMLEmailTemplate', ({(202, 41, 202, 76): "{'content': '', 'subject': subject}"}, {}), "({'content': '', 'subject': subject})", False, 'from notifications_utils.template import HTMLEmailTemplate, PlainTextEmailTemplate, SMSMessageTemplate, SMSPreviewTemplate\n'), ((454, 13, 454, 53), 'pytest.mark.xfail', 'pytest.mark.xfail', (), '', False, 'import pytest\n')]