from __future__ import print_function
import unittest
import time
from roundup.anypy.cgi_ import FieldStorage, MiniFieldStorage
from roundup.cgi.templating import *
from roundup.cgi.ZTUtils.Iterator import Iterator
from roundup.test import memorydb
from .test_actions import MockNull, true
from .html_norm import NormalizingHtmlParser
import pytest
from .pytest_patcher import mark_class
try:
from markdown2 import __version_info__ as md2__version_info__
except ImportError:
md2__version_info__ = (0,0,0)
if ReStructuredText:
skip_rst = lambda func, *args, **kwargs: func
else:
skip_rst = mark_class(pytest.mark.skip(
reason='ReStructuredText not available'))
import roundup.cgi.templating
if roundup.cgi.templating._import_mistune():
skip_mistune = lambda func, *args, **kwargs: func
else:
skip_mistune = mark_class(pytest.mark.skip(
reason='mistune not available'))
if roundup.cgi.templating._import_markdown2():
skip_markdown2 = lambda func, *args, **kwargs: func
else:
skip_markdown2 = mark_class(pytest.mark.skip(
reason='markdown2 not available'))
if roundup.cgi.templating._import_markdown():
skip_markdown = lambda func, *args, **kwargs: func
else:
skip_markdown = mark_class(pytest.mark.skip(
reason='markdown not available'))
from roundup.anypy.strings import u2s, s2u
from roundup.backends.sessions_common import SessionCommon
class MockConfig(dict):
def __getattr__(self, name):
try:
return self[name]
except KeyError as err:
raise AttributeError(err)
class MockDatabase(MockNull, SessionCommon):
def getclass(self, name):
# limit class names
if name not in [ 'issue', 'user', 'status' ]:
raise KeyError('There is no class called "%s"' % name)
# Class returned must have hasnode(id) method that returns true
# otherwise designators like 'issue1' can't be hyperlinked.
self.classes[name].hasnode = lambda id: True if int(id) < 10 else False
return self.classes[name]
# setup for csrf testing of otks database api
storage = {}
def set(self, key, **props):
MockDatabase.storage[key] = {}
if '__timestamp' not in props:
props['__timestamp'] = time.time() - 7*24*3600
MockDatabase.storage[key].update(props)
def get(self, key, field, default=None):
if key not in MockDatabase.storage:
return default
return MockDatabase.storage[key][field]
def getall(self, key):
if key not in MockDatabase.storage:
return default
return MockDatabase.storage[key]
def exists(self,key):
return key in MockDatabase.storage
def getOTKManager(self):
return MockDatabase()
def lifetime(self, seconds):
return time.time() - 7*24*3600 + seconds
class TemplatingTestCase(unittest.TestCase):
def setUp(self):
self.form = FieldStorage()
self.client = MockNull()
self.client.db = db = MockDatabase()
db.security.hasPermission = lambda *args, **kw: True
self.client.form = self.form
# add client props for testing anti_csrf_nonce
self.client.session_api = MockNull(_sid="1234567890")
self.client.db.getuid = lambda : 10
self.client.db.config = MockConfig (
{'WEB_CSRF_TOKEN_LIFETIME': 10,
'MARKDOWN_BREAK_ON_NEWLINE': False })
class HTMLDatabaseTestCase(TemplatingTestCase):
def test_HTMLDatabase___getitem__(self):
db = HTMLDatabase(self.client)
self.assertTrue(isinstance(db['issue'], HTMLClass))
# following assertions are invalid
# since roundup/cgi/templating.py r1.173.
# HTMLItem is function, not class,
# but HTMLUserClass and HTMLUser are passed on.
# these classes are no more. they have ceased to be.
#self.assertTrue(isinstance(db['user'], HTMLUserClass))
#self.assertTrue(isinstance(db['issue1'], HTMLItem))
#self.assertTrue(isinstance(db['user1'], HTMLUser))
def test_HTMLDatabase___getattr__(self):
db = HTMLDatabase(self.client)
self.assertTrue(isinstance(db.issue, HTMLClass))
# see comment in test_HTMLDatabase___getitem__
#self.assertTrue(isinstance(db.user, HTMLUserClass))
#self.assertTrue(isinstance(db.issue1, HTMLItem))
#self.assertTrue(isinstance(db.user1, HTMLUser))
def test_HTMLDatabase_classes(self):
db = HTMLDatabase(self.client)
db._db.classes = {'issue':MockNull(), 'user': MockNull()}
db.classes()
def test_HTMLDatabase_list(self):
# The list method used to produce a traceback when a None value
# for an order attribute of a class was encountered. This
# happens when the 'get' of the order attribute for a numeric
# id produced a None value. So we put '23' as a key into the
# list and set things up that a None value is returned on 'get'.
# This keeps db.issue static, otherwise it changes for each call
db = MockNull(issue = HTMLDatabase(self.client).issue)
db.issue._klass.list = lambda : ['23', 'a', 'b']
# Make db.getclass return something that has a sensible 'get' method
def get(x, y, allow_abort=True):
return None
mock = MockNull(get = get)
db.issue._db.getclass = lambda x : mock
l = db.issue.list()
class FunctionsTestCase(TemplatingTestCase):
def test_lookupIds(self):
db = HTMLDatabase(self.client)
def lookup(key):
if key == 'ok':
return '1'
if key == 'fail':
raise KeyError('fail')
if key == '@current_user':
raise KeyError('@current_user')
return key
db._db.classes = {'issue': MockNull(lookup=lookup)}
prop = MockNull(classname='issue')
self.assertEqual(lookupIds(db._db, prop, ['1','2']), ['1','2'])
self.assertEqual(lookupIds(db._db, prop, ['ok','2']), ['1','2'])
self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail'], 1),
['1', 'fail'])
self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail']), ['1'])
self.assertEqual(lookupIds(db._db, prop, ['ok', '@current_user']),
['1'])
def test_lookupKeys(self):
db = HTMLDatabase(self.client)
def get(entry, key, allow_abort=True):
return {'1': 'green', '2': 'eggs'}.get(entry, entry)
shrubbery = MockNull(get=get)
db._db.classes = {'shrubbery': shrubbery}
self.assertEqual(lookupKeys(shrubbery, 'spam', ['1','2']),
['green', 'eggs'])
self.assertEqual(lookupKeys(shrubbery, 'spam', ['ok','2']), ['ok',
'eggs'])
class HTMLClassTestCase(TemplatingTestCase) :
def test_link(self):
"""Make sure lookup of a Link property works even in the
presence of multiple values in the form."""
def lookup(key) :
self.assertEqual(key, key.strip())
return "Status%s"%key
self.form.list.append(MiniFieldStorage("issue@status", "1"))
self.form.list.append(MiniFieldStorage("issue@status", "2"))
status = hyperdb.Link("status")
self.client.db.classes = dict \
( issue = MockNull(getprops = lambda : dict(status = status))
, status = MockNull(get = lambda id, name : id, lookup = lookup)
)
self.client.form = self.form
cls = HTMLClass(self.client, "issue")
s = cls["status"]
self.assertEqual(s._value, '1')
def test_link_default(self):
"""Make sure default value for link is returned
if new item and no value in form."""
def lookup(key) :
self.assertEqual(key, key.strip())
return "Status%s"%key
status = hyperdb.Link("status")
# set default_value
status.__dict__['_Type__default_value'] = "4"
self.client.db.classes = dict \
( issue = MockNull(getprops = lambda : dict(status = status))
, status = MockNull(get = lambda id, name : id, lookup = lookup, get_default_value = lambda: 4)
)
self.client.form = self.form
cls = HTMLClass(self.client, "issue")
s = cls["status"]
self.assertEqual(s._value, '4')
def test_link_with_value_and_default(self):
"""Make sure default value is not used if there
is a value in the form."""
def lookup(key) :
self.assertEqual(key, key.strip())
return "Status%s"%key
self.form.list.append(MiniFieldStorage("issue@status", "2"))
self.form.list.append(MiniFieldStorage("issue@status", "1"))
status = hyperdb.Link("status")
# set default_value
status.__dict__['_Type__default_value'] = "4"
self.client.db.classes = dict \
( issue = MockNull(getprops = lambda : dict(status = status))
, status = MockNull(get = lambda id, name : id, lookup = lookup, get_default_value = lambda: 4)
)
self.client.form = self.form
cls = HTMLClass(self.client, "issue")
s = cls["status"]
self.assertEqual(s._value, '2')
def test_multilink(self):
"""`lookup` of an item will fail if leading or trailing whitespace
has not been stripped.
"""
def lookup(key) :
self.assertEqual(key, key.strip())
return "User%s"%key
self.form.list.append(MiniFieldStorage("nosy", "1, 2"))
nosy = hyperdb.Multilink("user")
self.client.db.classes = dict \
( issue = MockNull(getprops = lambda : dict(nosy = nosy))
, user = MockNull(get = lambda id, name : id, lookup = lookup)
)
cls = HTMLClass(self.client, "issue")
cls["nosy"]
def test_anti_csrf_nonce(self):
'''call the csrf creation function and do basic length test
Store the data in a mock db with the same api as the otk
db. Make sure nonce is 54 chars long. Lookup the nonce in
db and retrieve data. Verify that the nonce lifetime is
correct (within 1 second of 1 week - lifetime), the uid is
correct (1), the dummy sid is correct.
Consider three cases:
* create nonce via module function setting lifetime
* create nonce via TemplatingUtils method setting lifetime
* create nonce via module function with default lifetime
'''
# the value below is number of seconds in a week.
week_seconds = 604800
otks=self.client.db.getOTKManager()
for test in [ 'module', 'template', 'default_time' ]:
print("Testing:", test)
if test == 'module':
# test the module function
nonce1 = anti_csrf_nonce(self.client, lifetime=1)
# lifetime * 60 is the offset
greater_than = week_seconds - 1 * 60
elif test == 'template':
# call the function through the TemplatingUtils class
cls = TemplatingUtils(self.client)
nonce1 = cls.anti_csrf_nonce(lifetime=5)
greater_than = week_seconds - 5 * 60
elif test == 'default_time':
# use the module function but with no lifetime
nonce1 = anti_csrf_nonce(self.client)
# see above for web nonce lifetime.
greater_than = week_seconds - 10 * 60
self.assertEqual(len(nonce1), 54)
uid = otks.get(nonce1, 'uid', default=None)
sid = otks.get(nonce1, 'sid', default=None)
timestamp = otks.get(nonce1, '__timestamp', default=None)
self.assertEqual(uid, 10)
self.assertEqual(sid, self.client.session_api._sid)
now = time.time()
print("now, timestamp, greater, difference",
now, timestamp, greater_than, now - timestamp)
# lower bound of the difference is above. Upper bound
# of difference is run time between time.time() in
# the call to anti_csrf_nonce and the time.time() call
# that assigns ts above. I declare that difference
# to be less than 1 second for this to pass.
self.assertEqual(True,
greater_than <= now - timestamp < (greater_than + 1) )
def test_number__int__(self):
# test with number
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
2345678.2345678)
self.assertEqual(p.__int__(), 2345678)
property = MockNull(get_default_value = lambda: None)
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
'test', None)
with self.assertRaises(TypeError) as e:
p.__int__()
def test_number__float__(self):
# test with number
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
2345678.2345678)
self.assertEqual(p.__float__(), 2345678.2345678)
property = MockNull(get_default_value = lambda: None)
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
'test', None)
with self.assertRaises(TypeError) as e:
p.__float__()
def test_number_field(self):
import sys
_py3 = sys.version_info[0] > 2
# python2 truncates while python3 rounds. Sigh.
if _py3:
expected_val = 2345678.2345678
else:
expected_val = 2345678.23457
# test with number
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
2345678.2345678)
self.client.db.config['WEB_USE_BROWSER_NUMBER_INPUT'] = False
self.assertEqual(p.field(),
('')%expected_val)
self.client.db.config['WEB_USE_BROWSER_NUMBER_INPUT'] = True
self.assertEqual(p.field(),
('')%expected_val)
self.assertEqual(p.field(size=10),
('')%expected_val)
self.assertEqual(p.field(size=10, dataprop="foo", dataprop2=5),
(''%expected_val))
self.assertEqual(p.field(size=10, klass="class1",
**{ "class": "class2 class3",
"data-prop": "foo",
"data-prop2": 5}),
('')%expected_val)
# get plain representation if user can't edit
p.is_edit_ok = lambda: False
self.assertEqual(p.field(), p.plain())
# test with string which is wrong type
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
"234567e.2345678")
self.assertEqual(p.field(),
(''))
# test with None value, pretend property.__default_value = Null which
# is the default. It would be returned by get_default_value
# which I mock.
property = MockNull(get_default_value = lambda: None)
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
'test', None)
self.assertEqual(p.field(),
(''))
def test_number_plain(self):
import sys
_py3 = sys.version_info[0] > 2
# python2 truncates while python3 rounds. Sigh.
if _py3:
expected_val = 2345678.2345678
else:
expected_val = 2345678.23457
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
2345678.2345678)
self.assertEqual(p.plain(), "%s"%expected_val)
def test_number_pretty(self):
# test with number
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
2345678.2345678)
self.assertEqual(p.pretty(), "2345678.235")
# test with string which is wrong type
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
"2345678.2345678")
self.assertEqual(p.pretty(), "2345678.2345678")
# test with boolean
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
True)
self.assertEqual(p.pretty(), "1.000")
# test with None value, pretend property.__default_value = Null which
# is the default. It would be returned by get_default_value
# which I mock.
property = MockNull(get_default_value = lambda: None)
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
'test', None)
self.assertEqual(p.pretty(), '')
with self.assertRaises(ValueError) as e:
p.pretty('%0.3')
def test_string_url_quote(self):
''' test that urlquote quotes the string '''
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'test string< foo@bar')
self.assertEqual(p.url_quote(), 'test%20string%3C%20foo%40bar')
def test_string_email(self):
''' test that email obscures the email '''
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'rouilj@foo.example.com')
self.assertEqual(p.email(), 'rouilj at foo example ...')
def test_string_wrapped(self):
test_string = ('A long string that needs to be wrapped to'
' 80 characters and no more. Put in a link issue1.'
' Put in to be escaped. Put in a'
' https://example.com/link as well. Let us see if'
' it will wrap properly.' )
test_result_wrap = {}
test_result_wrap[80] = ('A long string that needs to be wrapped to 80'
' characters and no more. Put in a\n'
'link issue1. Put in'
' <html> to be escaped. Put in a '
'https://example.com/link as\n'
'well. Let us see if it will wrap properly.')
test_result_wrap[20] = (
'A long string that\n'
'needs to be wrapped\n'
'to 80 characters and\n'
'no more. Put in a\nlink issue1. Put in\n'
'<html> to be\n'
'escaped. Put in a\n'
'https://example.com/link\n'
'as well. Let us see\n'
'if it will wrap\n'
'properly.')
test_result_wrap[100] = (
'A long string that needs to be wrapped to 80 characters and no more. Put in a link issue1. Put in\n'
'<html> to be escaped. Put in a https://example.com/link as well. Let us see if it will wrap\n'
'properly.')
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
test_string)
for i in [80, 20, 100]:
wrapped = p.wrapped(columns=i)
print(wrapped)
self.assertEqual(wrapped, test_result_wrap[i])
def test_string_plain_or_hyperlinked(self):
''' test that email obscures the email '''
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'A string with rouilj@example.com embedded < html')
self.assertEqual(p.plain(), 'A string with rouilj@example.com embedded < html')
self.assertEqual(p.plain(escape=1), 'A string <b> with rouilj@example.com embedded < html</b>')
self.assertEqual(p.plain(hyperlink=1), 'A string <b> with rouilj@example.com embedded < html</b>')
self.assertEqual(p.plain(escape=1, hyperlink=1), 'A string <b> with rouilj@example.com embedded < html</b>')
self.assertEqual(p.hyperlinked(), 'A string <b> with rouilj@example.com embedded < html</b>')
# check designators
for designator in [ "issue1", "issue 1" ]:
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', designator)
self.assertEqual(p.hyperlinked(),
'%s'%designator)
# issue 100 > 10 which is a magic number for the mocked hasnode
# If id number is greater than 10 hasnode reports it does not have
# the node.
for designator in ['issue100', 'issue 100']:
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
designator)
self.assertEqual(p.hyperlinked(), designator)
# zoom class does not exist
for designator in ['zoom1', 'zoom100', 'zoom 1']:
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
designator)
self.assertEqual(p.hyperlinked(), designator)
@skip_rst
def test_string_rst(self):
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df'))
# test case to make sure include directive is disabled
q = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'\n\n.. include:: XyZrMt.html\n\n\n\n'))
q_result=u'''
System Message: WARNING/2 (<string>, line 3)
"include" directive disabled.
.. include:: XyZrMt.html
<badtag>
'''
# test case to make sure raw directive is disabled
r = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'\n\n.. raw:: html\n\n \n\n'))
r_result='''
System Message: WARNING/2 (<string>, line 3)
"raw" directive disabled.
.. raw:: html
<badtag>
'''
# test case to make sure javascript and data url's aren't turned
# into links
s = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'\njavascript:badcode data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=='))
s_result = '
\n'
# test url recognition
t = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'link is https://example.com/link for testing.'))
t_result = '
\n'
# test text that doesn't need to be processed
u = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'Just a plain old string here. Nothig to process.'))
u_result = '
'), m)
def test_string_markdown_link_item(self):
""" The link formats for the different markdown engines changes.
Order of attributes, value for rel (noopener, nofollow etc)
is different. So most tests check for a substring that indicates
success rather than the entire returned string.
"""
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An issue1 link'))
self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
# just verify that plain linking is working
self.assertIn( u2s(u'href="issue1"'), p.plain(hyperlink=1))
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issue1](issue1) link'))
self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
# just verify that plain linking is working
self.assertIn( u2s(u'href="issue1"'), p.plain(hyperlink=1))
p = StringHTMLProperty(
self.client, 'test', '1', None, 'test',
u2s(u'An [issue1](https://example.com/issue1) link'))
self.assertIn( u2s(u'href="https://example.com/issue1"'),
p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issu1](#example) link'))
self.assertIn( u2s(u'href="#example"'), p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issu1](/example) link'))
self.assertIn( u2s(u'href="http://hg.code.sf.net/example"'), p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issu1](./example) link'))
self.assertIn( u2s(u'href="./example"'), p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issu1](../example) link'))
self.assertIn( u2s(u'href="../example"'), p.markdown().strip())
p = StringHTMLProperty(
self.client, 'test', '1', None, 'test',
u2s(u'A [wuarchive_ftp](ftp://www.wustl.gov/file) link'))
self.assertIn( u2s(u'href="ftp://www.wustl.gov/file"'),
p.markdown().strip())
p = StringHTMLProperty(
self.client, 'test', '1', None, 'test',
u2s(u'An [issue1] (https://example.com/issue1) link'))
self.assertIn( u2s(u'href="issue1"'), p.markdown().strip())
if type(self) == MistuneTestCase:
# mistune makes the https url into a real link
self.assertIn( u2s(u'href="https://example.com/issue1"'),
p.markdown().strip())
else:
# the other two engines leave the parenthesized url as is.
self.assertIn( u2s(u' (https://example.com/issue1) link'),
p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'An [issu1](.../example) link'))
if (isinstance(self, Markdown2TestCase) and
md2__version_info__ > (2, 4, 9)):
# markdown2 > 2.4.9 handles this differently
self.assertIn( u2s(u'href="#"'), p.markdown().strip())
else:
self.assertIn( u2s(u'href=".../example"'), p.markdown().strip())
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'A [phone](tel:0016175555555) link'))
if (isinstance(self, Markdown2TestCase) and
md2__version_info__ > (2, 4, 9)):
self.assertIn(u2s(u'href="#"'), p.markdown().strip())
else:
self.assertIn( u2s(u'href="tel:0016175555555"'),
p.markdown().strip())
def test_string_email_markdown_link(self):
# markdown2 and markdown escape the email address
try:
from html import unescape as html_unescape
except ImportError:
from HTMLParser import HTMLParser
html_unescape = HTMLParser().unescape
p = StringHTMLProperty(self.client, 'test', '1', None, 'test',
u2s(u'A link '))
m = html_unescape(p.markdown().strip())
m = self.mangleMarkdown2(m)
self.assertEqual(m, u2s(u'
'))
p = StringHTMLProperty(
self.client, 'test', '1', None, 'test',
u2s(u'An bare email baduser@daemons.com link'))
m = self.mangleMarkdown2(html_unescape(p.markdown().strip()))
self.assertIn( u2s(u'href="mailto:baduser@daemons.com"'),
m)
p = StringHTMLProperty(
self.client, 'test', '1', None, 'test',
u2s(u'An [email_url](mailto:baduser@daemons.com) link'))
m = self.mangleMarkdown2(html_unescape(p.markdown().strip()))
if isinstance(self, MistuneTestCase):
self.assertIn('email_url', m)
else:
self.assertIn('email_url', m)
def test_string_markdown_javascript_link(self):
# make sure we don't get a "javascript:" link
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u''))
self.assertTrue(p.markdown().find('href="javascript:') == -1)
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'[link](javascript:alert(1))'))
self.assertTrue(p.markdown().find('href="javascript:') == -1)
def test_string_markdown_data_link(self):
# make sure we don't get a "data:" link
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u''))
print(p.markdown())
self.assertTrue(p.markdown().find('href="data:') == -1)
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'[data link](data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==)'))
print(p.markdown())
self.assertTrue(p.markdown().find('href="data:') == -1)
def test_string_markdown_forced_line_break(self):
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'This is a set of text \n:that should have a break \n:at newlines. Each \n:colon should be the start of an html line'))
# sigh different backends render this differently:
# of text
# of text
# etc.
# Rather than using a different result for each
# renderer, look for ' \n\n```\nline 1\nline 2\n```\n\nnew paragraph'))
self.assertEqual(p.markdown().strip().replace('\n\n', '\n'), u2s(u'
embedded code block <pre>
\n
line 1\nline 2\n
\n
new </pre> paragraph
'))
def test_string_markdown_code_block_attribute(self):
parser = NormalizingHtmlParser()
''' also verify that embedded html is escaped '''
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'embedded code block
\n\n``` python\nline 1\nline 2\n```\n\nnew
paragraph'))
m = parser.normalize(p.markdown())
parser.reset()
print(m)
if type(self) == MistuneTestCase:
self.assertEqual(m, parser.normalize('
')
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'[label](http://example.com/ "a title")'))
m = p.markdown(hyperlink=1)
m = self.mangleMarkdown2(m)
self.assertEqual(m.rstrip('\n'), '