"Fossies" - the Fresh Open Source Software Archive

Member "roundup-2.0.0/test/test_templating.py" (29 Feb 2020, 30041 Bytes) of package /linux/www/roundup-2.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_templating.py": 1.6.1_vs_2.0.0.

    1 from __future__ import print_function
    2 import unittest
    3 from cgi import FieldStorage, MiniFieldStorage
    4 
    5 from roundup.cgi.templating import *
    6 from .test_actions import MockNull, true
    7 
    8 
    9 import pytest
   10 from .pytest_patcher import mark_class
   11 
   12 if ReStructuredText:
   13     skip_rst = lambda func, *args, **kwargs: func
   14 else:
   15     skip_rst = mark_class(pytest.mark.skip(
   16         reason='ReStructuredText not available'))
   17 
   18 if StructuredText:
   19     skip_stext = lambda func, *args, **kwargs: func
   20 else:
   21     skip_stext = mark_class(pytest.mark.skip(
   22         reason='StructuredText not available'))
   23 
   24 import roundup.cgi.templating
   25 if roundup.cgi.templating._import_mistune():
   26     skip_mistune = lambda func, *args, **kwargs: func
   27 else:
   28     skip_mistune = mark_class(pytest.mark.skip(
   29         reason='mistune not available'))
   30 
   31 if roundup.cgi.templating._import_markdown2():
   32     skip_markdown2 = lambda func, *args, **kwargs: func
   33 else:
   34     skip_markdown2 = mark_class(pytest.mark.skip(
   35         reason='markdown2 not available'))
   36 
   37 if roundup.cgi.templating._import_markdown():
   38     skip_markdown = lambda func, *args, **kwargs: func
   39 else:
   40     skip_markdown = mark_class(pytest.mark.skip(
   41         reason='markdown not available'))
   42 
   43 from roundup.anypy.strings import u2s, s2u
   44 
   45 class MockDatabase(MockNull):
   46     def getclass(self, name):
   47         return self.classes[name]
   48 
   49     # setup for csrf testing of otks database api
   50     storage = {}
   51     def set(self, key, **props):
   52         MockDatabase.storage[key] = {}
   53         MockDatabase.storage[key].update(props)
   54 
   55     def get(self, key, field, default=None):
   56         if key not in MockDatabase.storage:
   57             return default
   58         return MockDatabase.storage[key][field]
   59 
   60     def exists(self,key):
   61         return key in MockDatabase.storage
   62 
   63     def getOTKManager(self):
   64         return MockDatabase()
   65 
   66 class TemplatingTestCase(unittest.TestCase):
   67     def setUp(self):
   68         self.form = FieldStorage()
   69         self.client = MockNull()
   70         self.client.db = db = MockDatabase()
   71         db.security.hasPermission = lambda *args, **kw: True
   72         self.client.form = self.form
   73 
   74         # add client props for testing anti_csrf_nonce
   75         self.client.session_api = MockNull(_sid="1234567890")
   76         self.client.db.getuid = lambda : 10
   77         self.client.db.config = {'WEB_CSRF_TOKEN_LIFETIME': 10 }
   78 
   79 class HTMLDatabaseTestCase(TemplatingTestCase):
   80     def test_HTMLDatabase___getitem__(self):
   81         db = HTMLDatabase(self.client)
   82         self.assertTrue(isinstance(db['issue'], HTMLClass))
   83         # following assertions are invalid
   84         # since roundup/cgi/templating.py r1.173.
   85         # HTMLItem is function, not class,
   86         # but HTMLUserClass and HTMLUser are passed on.
   87         # these classes are no more.  they have ceased to be.
   88         #self.assertTrue(isinstance(db['user'], HTMLUserClass))
   89         #self.assertTrue(isinstance(db['issue1'], HTMLItem))
   90         #self.assertTrue(isinstance(db['user1'], HTMLUser))
   91 
   92     def test_HTMLDatabase___getattr__(self):
   93         db = HTMLDatabase(self.client)
   94         self.assertTrue(isinstance(db.issue, HTMLClass))
   95         # see comment in test_HTMLDatabase___getitem__
   96         #self.assertTrue(isinstance(db.user, HTMLUserClass))
   97         #self.assertTrue(isinstance(db.issue1, HTMLItem))
   98         #self.assertTrue(isinstance(db.user1, HTMLUser))
   99 
  100     def test_HTMLDatabase_classes(self):
  101         db = HTMLDatabase(self.client)
  102         db._db.classes = {'issue':MockNull(), 'user': MockNull()}
  103         db.classes()
  104 
  105 class FunctionsTestCase(TemplatingTestCase):
  106     def test_lookupIds(self):
  107         db = HTMLDatabase(self.client)
  108         def lookup(key):
  109             if key == 'ok':
  110                 return '1'
  111             if key == 'fail':
  112                 raise KeyError('fail')
  113             return key
  114         db._db.classes = {'issue': MockNull(lookup=lookup)}
  115         prop = MockNull(classname='issue')
  116         self.assertEqual(lookupIds(db._db, prop, ['1','2']), ['1','2'])
  117         self.assertEqual(lookupIds(db._db, prop, ['ok','2']), ['1','2'])
  118         self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail'], 1),
  119             ['1', 'fail'])
  120         self.assertEqual(lookupIds(db._db, prop, ['ok', 'fail']), ['1'])
  121 
  122     def test_lookupKeys(self):
  123         db = HTMLDatabase(self.client)
  124         def get(entry, key):
  125             return {'1': 'green', '2': 'eggs'}.get(entry, entry)
  126         shrubbery = MockNull(get=get)
  127         db._db.classes = {'shrubbery': shrubbery}
  128         self.assertEqual(lookupKeys(shrubbery, 'spam', ['1','2']),
  129             ['green', 'eggs'])
  130         self.assertEqual(lookupKeys(shrubbery, 'spam', ['ok','2']), ['ok',
  131             'eggs'])
  132 
  133 class HTMLClassTestCase(TemplatingTestCase) :
  134 
  135     def test_link(self):
  136         """Make sure lookup of a Link property works even in the
  137         presence of multiple values in the form."""
  138         def lookup(key) :
  139             self.assertEqual(key, key.strip())
  140             return "Status%s"%key
  141         self.form.list.append(MiniFieldStorage("status", "1"))
  142         self.form.list.append(MiniFieldStorage("status", "2"))
  143         status = hyperdb.Link("status")
  144         self.client.db.classes = dict \
  145             ( issue = MockNull(getprops = lambda : dict(status = status))
  146             , status  = MockNull(get = lambda id, name : id, lookup = lookup)
  147             )
  148         cls = HTMLClass(self.client, "issue")
  149         cls["status"]
  150 
  151     def test_multilink(self):
  152         """`lookup` of an item will fail if leading or trailing whitespace
  153            has not been stripped.
  154         """
  155         def lookup(key) :
  156             self.assertEqual(key, key.strip())
  157             return "User%s"%key
  158         self.form.list.append(MiniFieldStorage("nosy", "1, 2"))
  159         nosy = hyperdb.Multilink("user")
  160         self.client.db.classes = dict \
  161             ( issue = MockNull(getprops = lambda : dict(nosy = nosy))
  162             , user  = MockNull(get = lambda id, name : id, lookup = lookup)
  163             )
  164         cls = HTMLClass(self.client, "issue")
  165         cls["nosy"]
  166 
  167     def test_anti_csrf_nonce(self):
  168         '''call the csrf creation function and do basic length test
  169 
  170            Store the data in a mock db with the same api as the otk
  171            db. Make sure nonce is 64 chars long. Lookup the nonce in
  172            db and retrieve data. Verify that the nonce lifetime is
  173            correct (within 1 second of 1 week - lifetime), the uid is
  174            correct (1), the dummy sid is correct.
  175 
  176            Consider three cases:
  177              * create nonce via module function setting lifetime
  178              * create nonce via TemplatingUtils method setting lifetime
  179              * create nonce via module function with default lifetime
  180 
  181         '''
  182 
  183         # the value below is number of seconds in a week.
  184         week_seconds = 604800
  185 
  186         otks=self.client.db.getOTKManager()
  187 
  188         for test in [ 'module', 'template', 'default_time' ]:
  189             print("Testing:", test)
  190             
  191             if test == 'module':
  192                 # test the module function
  193                 nonce1 = anti_csrf_nonce(self.client, lifetime=1)
  194                 # lifetime * 60 is the offset
  195                 greater_than = week_seconds - 1 * 60
  196             elif test == 'template':
  197                 # call the function through the TemplatingUtils class
  198                 cls = TemplatingUtils(self.client)
  199                 nonce1 = cls.anti_csrf_nonce(lifetime=5)
  200                 greater_than = week_seconds - 5 * 60
  201             elif test == 'default_time':
  202                 # use the module function but with no lifetime
  203                 nonce1 = anti_csrf_nonce(self.client)
  204                 # see above for web nonce lifetime.
  205                 greater_than = week_seconds - 10 * 60
  206 
  207             self.assertEqual(len(nonce1), 64)
  208 
  209             uid = otks.get(nonce1, 'uid', default=None)
  210             sid = otks.get(nonce1, 'sid', default=None)
  211             timestamp = otks.get(nonce1, '__timestamp', default=None)
  212 
  213             self.assertEqual(uid, 10) 
  214             self.assertEqual(sid, self.client.session_api._sid)
  215 
  216             now = time.time()
  217 
  218             print("now, timestamp, greater, difference",
  219                   now, timestamp, greater_than, now - timestamp)
  220 
  221         
  222             # lower bound of the difference is above. Upper bound
  223             # of difference is run time between time.time() in
  224             # the call to anti_csrf_nonce and the time.time() call
  225             # that assigns ts above. I declare that difference
  226             # to be less than 1 second for this to pass.
  227             self.assertEqual(True,
  228                        greater_than <= now - timestamp < (greater_than + 1) )
  229 
  230     def test_string_url_quote(self):
  231         ''' test that urlquote quotes the string '''
  232         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'test string< foo@bar')
  233         self.assertEqual(p.url_quote(), 'test%20string%3C%20foo%40bar')
  234 
  235     def test_string_email(self):
  236         ''' test that email obscures the email '''
  237         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'rouilj@foo.example.com')
  238         self.assertEqual(p.email(), 'rouilj at foo example ...')
  239 
  240     def test_string_plain_or_hyperlinked(self):
  241         ''' test that email obscures the email '''
  242         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'A string <b> with rouilj@example.com embedded &lt; html</b>')
  243         self.assertEqual(p.plain(), 'A string <b> with rouilj@example.com embedded &lt; html</b>')
  244         self.assertEqual(p.plain(escape=1), 'A string &lt;b&gt; with rouilj@example.com embedded &amp;lt; html&lt;/b&gt;')
  245         self.assertEqual(p.plain(hyperlink=1), 'A string &lt;b&gt; with <a href="mailto:rouilj@example.com">rouilj@example.com</a> embedded &amp;lt; html&lt;/b&gt;')
  246         self.assertEqual(p.plain(escape=1, hyperlink=1), 'A string &lt;b&gt; with <a href="mailto:rouilj@example.com">rouilj@example.com</a> embedded &amp;lt; html&lt;/b&gt;')
  247 
  248         self.assertEqual(p.hyperlinked(), 'A string &lt;b&gt; with <a href="mailto:rouilj@example.com">rouilj@example.com</a> embedded &amp;lt; html&lt;/b&gt;')
  249 
  250     @skip_rst
  251     def test_string_rst(self):
  252         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df'))
  253 
  254         # test case to make sure include directive is disabled
  255         q = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'\n\n.. include:: XyZrMt.html\n\n<badtag>\n\n'))
  256         q_result=u'''<div class="document">
  257 <div class="system-message">
  258 <p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">&lt;string&gt;</tt>, line 3)</p>
  259 <p>&quot;include&quot; directive disabled.</p>
  260 <pre class="literal-block">
  261 .. include:: XyZrMt.html
  262 
  263 </pre>
  264 </div>
  265 <p>&lt;badtag&gt;</p>
  266 </div>
  267 '''
  268 
  269         # test case to make sure raw directive is disabled
  270         r =  StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'\n\n.. raw:: html\n\n   <badtag>\n\n'))
  271         r_result='''<div class="document">
  272 <div class="system-message">
  273 <p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">&lt;string&gt;</tt>, line 3)</p>
  274 <p>&quot;raw&quot; directive disabled.</p>
  275 <pre class="literal-block">
  276 .. raw:: html
  277 
  278    &lt;badtag&gt;
  279 
  280 </pre>
  281 </div>
  282 </div>
  283 '''
  284     # test case to make sure javascript url's aren't turned into links
  285         s = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'<badtag>\njavascript:badcode'))
  286         s_result = '<div class="document">\n<p>&lt;badtag&gt;\njavascript:badcode</p>\n</div>\n'
  287 
  288         self.assertEqual(p.rst(), u2s(u'<div class="document">\n<p>A string with <a class="reference external" href="mailto:cmeerw&#64;example.com">cmeerw&#64;example.com</a> <em>embedded</em> \u00df</p>\n</div>\n'))
  289         self.assertEqual(q.rst(), u2s(q_result))
  290         self.assertEqual(r.rst(), u2s(r_result))
  291         self.assertEqual(s.rst(), u2s(s_result))
  292 
  293     @skip_stext
  294     def test_string_stext(self):
  295         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df'))
  296         self.assertEqual(p.stext(), u2s(u'<p>A string with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> <em>embedded</em> \u00df</p>\n'))
  297 
  298     def test_string_field(self):
  299         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'A string <b> with rouilj@example.com embedded &lt; html</b>')
  300         self.assertEqual(p.field(), '<input name="test1@test" size="30" type="text" value="A string &lt;b&gt; with rouilj@example.com embedded &amp;lt; html&lt;/b&gt;">')
  301 
  302     def test_string_multiline(self):
  303         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'A string <b> with rouilj@example.com embedded &lt; html</b>')
  304         self.assertEqual(p.multiline(), '<textarea  name="test1@test" id="test1@test" rows="5" cols="40">A string &lt;b&gt; with rouilj@example.com embedded &amp;lt; html&lt;/b&gt;</textarea>')
  305         self.assertEqual(p.multiline(rows=300, cols=100, **{'class':'css_class'}), '<textarea class="css_class" name="test1@test" id="test1@test" rows="300" cols="100">A string &lt;b&gt; with rouilj@example.com embedded &amp;lt; html&lt;/b&gt;</textarea>')
  306 
  307     def test_url_match(self):
  308         '''Test the URL regular expression in StringHTMLProperty.
  309         '''
  310         def t(s, nothing=False, **groups):
  311             m = StringHTMLProperty.hyper_re.search(s)
  312             if nothing:
  313                 if m:
  314                     self.assertEqual(m, None, '%r matched (%r)'%(s, m.groupdict()))
  315                 return
  316             else:
  317                 self.assertNotEqual(m, None, '%r did not match'%s)
  318             d = m.groupdict()
  319             for g in groups:
  320                 self.assertEqual(d[g], groups[g], '%s %r != %r in %r'%(g, d[g],
  321                     groups[g], s))
  322 
  323         #t('123.321.123.321', 'url')
  324         t('http://localhost/', url='http://localhost/')
  325         t('http://roundup.net/', url='http://roundup.net/')
  326         t('http://richard@localhost/', url='http://richard@localhost/')
  327         t('http://richard:sekrit@localhost/',
  328             url='http://richard:sekrit@localhost/')
  329         t('<HTTP://roundup.net/>', url='HTTP://roundup.net/')
  330         t('www.a.ex', url='www.a.ex')
  331         t('foo.a.ex', nothing=True)
  332         t('StDevValidTimeSeries.GetObservation', nothing=True)
  333         t('http://a.ex', url='http://a.ex')
  334         t('http://a.ex/?foo&bar=baz\\.@!$%()qwerty',
  335             url='http://a.ex/?foo&bar=baz\\.@!$%()qwerty')
  336         t('www.foo.net', url='www.foo.net')
  337         t('richard@com.example', email='richard@com.example')
  338         t('r@a.com', email='r@a.com')
  339         t('i1', **{'class':'i', 'id':'1'})
  340         t('item123', **{'class':'item', 'id':'123'})
  341         t('www.user:pass@host.net', email='pass@host.net')
  342         t('user:pass@www.host.net', url='user:pass@www.host.net')
  343         t('123.35', nothing=True)
  344         t('-.3535', nothing=True)
  345 
  346     def test_url_replace(self):
  347         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', '')
  348         def t(s): return p.hyper_re.sub(p._hyper_repl, s)
  349         ae = self.assertEqual
  350         ae(t('item123123123123'), 'item123123123123')
  351         ae(t('http://roundup.net/'),
  352            '<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>')
  353         ae(t('&lt;HTTP://roundup.net/&gt;'),
  354            '&lt;<a href="HTTP://roundup.net/" rel="nofollow noopener">HTTP://roundup.net/</a>&gt;')
  355         ae(t('&lt;http://roundup.net/&gt;.'),
  356             '&lt;<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>&gt;.')
  357         ae(t('&lt;www.roundup.net&gt;'),
  358            '&lt;<a href="http://www.roundup.net" rel="nofollow noopener">www.roundup.net</a>&gt;')
  359         ae(t('(www.roundup.net)'),
  360            '(<a href="http://www.roundup.net" rel="nofollow noopener">www.roundup.net</a>)')
  361         ae(t('foo http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx bar'),
  362            'foo <a href="http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx" rel="nofollow noopener">'
  363            'http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx</a> bar')
  364         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))'),
  365            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
  366            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)')
  367         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language)).'),
  368            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
  369            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>).')
  370         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language))&gt;.'),
  371            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language)" rel="nofollow noopener">'
  372            'http://en.wikipedia.org/wiki/Python_(programming_language)</a>)&gt;.')
  373         ae(t('(e.g. http://en.wikipedia.org/wiki/Python_(programming_language&gt;)).'),
  374            '(e.g. <a href="http://en.wikipedia.org/wiki/Python_(programming_language" rel="nofollow noopener">'
  375            'http://en.wikipedia.org/wiki/Python_(programming_language</a>&gt;)).')
  376         for c in '.,;:!':
  377             # trailing punctuation is not included
  378             ae(t('http://roundup.net/%c ' % c),
  379                '<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>%c ' % c)
  380             # but it's included if it's part of the URL
  381             ae(t('http://roundup.net/%c/' % c),
  382                '<a href="http://roundup.net/%c/" rel="nofollow noopener">http://roundup.net/%c/</a>' % (c, c))
  383 
  384     def test_input_html4(self):
  385         # boolean attributes are just the attribute name
  386         # indicate with attr=None or attr="attr"
  387         #   e.g. disabled
  388 
  389         input=input_html4(required=None, size=30)
  390         self.assertEqual(input, '<input required size="30" type="text">')
  391 
  392         input=input_html4(required="required", size=30)
  393         self.assertEqual(input, '<input required="required" size="30" type="text">')
  394 
  395         attrs={"required": None, "class": "required", "size": 30}
  396         input=input_html4(**attrs)
  397         self.assertEqual(input, '<input class="required" required size="30" type="text">')
  398 
  399         attrs={"disabled": "disabled", "class": "required", "size": 30}
  400         input=input_html4(**attrs)
  401         self.assertEqual(input, '<input class="required" disabled="disabled" size="30" type="text">')
  402 
  403     def test_input_xhtml(self):
  404         # boolean attributes are attribute name="attribute name"
  405         # indicate with attr=None or attr="attr"
  406         #    e.g. disabled="disabled"
  407         input=input_xhtml(required=None, size=30)
  408         self.assertEqual(input, '<input required="required" size="30" type="text"/>')
  409 
  410         input=input_xhtml(required="required", size=30)
  411         self.assertEqual(input, '<input required="required" size="30" type="text"/>')
  412 
  413         attrs={"required": None, "class": "required", "size": 30}
  414         input=input_xhtml(**attrs)
  415         self.assertEqual(input, '<input class="required" required="required" size="30" type="text"/>')
  416 
  417         attrs={"disabled": "disabled", "class": "required", "size": 30}
  418         input=input_xhtml(**attrs)
  419         self.assertEqual(input, '<input class="required" disabled="disabled" size="30" type="text"/>')
  420 
  421 # common markdown test cases
  422 class MarkdownTests:
  423     def test_string_markdown(self):
  424         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with <br> *embedded* \u00df'))
  425         self.assertEqual(p.markdown().strip(), u2s(u'<p>A string with &lt;br&gt; <em>embedded</em> \u00df</p>'))
  426 
  427     def test_string_markdown_link(self):
  428         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A link <http://localhost>'))
  429         self.assertEqual(p.markdown().strip(), u2s(u'<p>A link <a href="http://localhost">http://localhost</a></p>'))
  430 
  431     def test_string_markdown_link(self):
  432         # markdown2 and markdown escape the email address
  433         try:
  434             from html import unescape as html_unescape
  435         except ImportError:
  436             from HTMLParser import HTMLParser
  437             html_unescape = HTMLParser().unescape
  438 
  439         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A link <cmeerw@example.com>'))
  440         self.assertEqual(html_unescape(p.markdown().strip()), u2s(u'<p>A link <a href="mailto:cmeerw@example.com">cmeerw@example.com</a></p>'))
  441 
  442     def test_string_markdown_javascript_link(self):
  443         # make sure we don't get a "javascript:" link
  444         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'<javascript:alert(1)>'))
  445         self.assertTrue(p.markdown().find('href="javascript:') == -1)
  446 
  447         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'[link](javascript:alert(1))'))
  448         self.assertTrue(p.markdown().find('href="javascript:') == -1)
  449 
  450     def test_string_markdown_code_block(self):
  451         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'embedded code block\n\n```\nline 1\nline 2\n```\n\nnew paragraph'))
  452         self.assertEqual(p.markdown().strip().replace('\n\n', '\n'), u2s(u'<p>embedded code block</p>\n<pre><code>line 1\nline 2\n</code></pre>\n<p>new paragraph</p>'))
  453 
  454 @skip_mistune
  455 class MistuneTestCase(TemplatingTestCase, MarkdownTests) :
  456     def setUp(self):
  457         TemplatingTestCase.setUp(self)
  458 
  459         from roundup.cgi import templating
  460         self.__markdown = templating.markdown
  461         templating.markdown = templating._import_mistune()
  462 
  463     def tearDown(self):
  464         from roundup.cgi import templating
  465         templating.markdown = self.__markdown
  466 
  467 @skip_markdown2
  468 class Markdown2TestCase(TemplatingTestCase, MarkdownTests) :
  469     def setUp(self):
  470         TemplatingTestCase.setUp(self)
  471 
  472         from roundup.cgi import templating
  473         self.__markdown = templating.markdown
  474         templating.markdown = templating._import_markdown2()
  475 
  476     def tearDown(self):
  477         from roundup.cgi import templating
  478         templating.markdown = self.__markdown
  479 
  480 @skip_markdown
  481 class MarkdownTestCase(TemplatingTestCase, MarkdownTests) :
  482     def setUp(self):
  483         TemplatingTestCase.setUp(self)
  484 
  485         from roundup.cgi import templating
  486         self.__markdown = templating.markdown
  487         templating.markdown = templating._import_markdown()
  488 
  489     def tearDown(self):
  490         from roundup.cgi import templating
  491         templating.markdown = self.__markdown
  492 
  493 
  494 class NoMarkdownTestCase(TemplatingTestCase) :
  495     def setUp(self):
  496         TemplatingTestCase.setUp(self)
  497 
  498         from roundup.cgi import templating
  499         self.__markdown = templating.markdown
  500         templating.markdown = None
  501 
  502     def tearDown(self):
  503         from roundup.cgi import templating
  504         templating.markdown = self.__markdown
  505 
  506     def test_string_markdown(self):
  507         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string http://localhost with cmeerw@example.com <br> *embedded* \u00df'))
  508         self.assertEqual(p.markdown(), u2s(u'A string <a href="http://localhost" rel="nofollow noopener">http://localhost</a> with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> &lt;br&gt; *embedded* \u00df'))
  509 
  510 class NoRstTestCase(TemplatingTestCase) :
  511     def setUp(self):
  512         TemplatingTestCase.setUp(self)
  513 
  514         from roundup.cgi import templating
  515         self.__ReStructuredText = templating.ReStructuredText
  516         templating.ReStructuredText = None
  517 
  518     def tearDown(self):
  519         from roundup.cgi import templating
  520         templating.ReStructuredText = self.__ReStructuredText
  521 
  522     def test_string_rst(self):
  523         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df'))
  524         self.assertEqual(p.rst(), u2s(u'A string with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> *embedded* \u00df'))
  525 
  526 class NoStextTestCase(TemplatingTestCase) :
  527     def setUp(self):
  528         TemplatingTestCase.setUp(self)
  529 
  530         from roundup.cgi import templating
  531         self.__StructuredText = templating.StructuredText
  532         templating.StructuredText = None
  533 
  534     def tearDown(self):
  535         from roundup.cgi import templating
  536         templating.StructuredText = self.__StructuredText
  537 
  538     def test_string_stext(self):
  539         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with cmeerw@example.com *embedded* \u00df'))
  540         self.assertEqual(p.stext(), u2s(u'A string with <a href="mailto:cmeerw@example.com">cmeerw@example.com</a> *embedded* \u00df'))
  541 
  542 
  543 r'''
  544 class HTMLPermissions:
  545     def is_edit_ok(self):
  546     def is_view_ok(self):
  547     def is_only_view_ok(self):
  548     def view_check(self):
  549     def edit_check(self):
  550 
  551 def input_html4(**attrs):
  552 def input_xhtml(**attrs):
  553 
  554 class HTMLInputMixin:
  555     def __init__(self):
  556 
  557 class HTMLClass(HTMLInputMixin, HTMLPermissions):
  558     def __init__(self, client, classname, anonymous=0):
  559     def __repr__(self):
  560     def __getitem__(self, item):
  561     def __getattr__(self, attr):
  562     def designator(self):
  563     def getItem(self, itemid, num_re=re.compile(r'-?\d+')):
  564     def properties(self, sort=1, cansearch=True):
  565     def list(self, sort_on=None):
  566     def csv(self):
  567     def propnames(self):
  568     def filter(self, request=None, filterspec={}, sort=(None,None),
  569     def classhelp(self, properties=None, label='(list)', width='500',
  570     def submit(self, label="Submit New Entry"):
  571     def history(self):
  572     def renderWith(self, name, **kwargs):
  573 
  574 class HTMLItem(HTMLInputMixin, HTMLPermissions):
  575     def __init__(self, client, classname, nodeid, anonymous=0):
  576     def __repr__(self):
  577     def __getitem__(self, item):
  578     def __getattr__(self, attr):
  579     def designator(self):
  580     def is_retired(self):
  581     def submit(self, label="Submit Changes"):
  582     def journal(self, direction='descending'):
  583     def history(self, direction='descending', dre=re.compile('\d+')):
  584     def renderQueryForm(self):
  585 
  586 class HTMLUserPermission:
  587     def is_edit_ok(self):
  588     def is_view_ok(self):
  589     def _user_perm_check(self, type):
  590 
  591 class HTMLUserClass(HTMLUserPermission, HTMLClass):
  592 
  593 class HTMLUser(HTMLUserPermission, HTMLItem):
  594     def __init__(self, client, classname, nodeid, anonymous=0):
  595     def hasPermission(self, permission, classname=_marker):
  596 
  597 class HTMLProperty(HTMLInputMixin, HTMLPermissions):
  598     def __init__(self, client, classname, nodeid, prop, name, value,
  599     def __repr__(self):
  600     def __str__(self):
  601     def __lt__(self, other):
  602     def __le__(self, other):
  603     def __eq__(self, other):
  604     def __ne__(self, other):
  605     def __gt__(self, other):
  606     def __ge__(self, other):
  607     def is_edit_ok(self):
  608     def is_view_ok(self):
  609 
  610 class StringHTMLProperty(HTMLProperty):
  611     def _hyper_repl(self, match):
  612     def hyperlinked(self):
  613     def plain(self, escape=0, hyperlink=0):
  614     def stext(self, escape=0):
  615     def field(self, size = 30):
  616     def multiline(self, escape=0, rows=5, cols=40):
  617     def email(self, escape=1):
  618 
  619 class PasswordHTMLProperty(HTMLProperty):
  620     def plain(self):
  621     def field(self, size = 30):
  622     def confirm(self, size = 30):
  623 
  624 class NumberHTMLProperty(HTMLProperty):
  625     def plain(self):
  626     def field(self, size = 30):
  627     def __int__(self):
  628     def __float__(self):
  629 
  630 class IntegerHTMLProperty(HTMLProperty):
  631     def plain(self):
  632     def field(self, size = 30):
  633     def __int__(self):
  634 
  635 class BooleanHTMLProperty(HTMLProperty):
  636     def plain(self):
  637     def field(self):
  638 
  639 class DateHTMLProperty(HTMLProperty):
  640     def plain(self):
  641     def now(self):
  642     def field(self, size = 30):
  643     def reldate(self, pretty=1):
  644     def pretty(self, format=_marker):
  645     def local(self, offset):
  646 
  647 class IntervalHTMLProperty(HTMLProperty):
  648     def plain(self):
  649     def pretty(self):
  650     def field(self, size = 30):
  651 
  652 class LinkHTMLProperty(HTMLProperty):
  653     def __init__(self, *args, **kw):
  654     def __getattr__(self, attr):
  655     def plain(self, escape=0):
  656     def field(self, showid=0, size=None):
  657     def menu(self, size=None, height=None, showid=0, additional=[],
  658 
  659 class MultilinkHTMLProperty(HTMLProperty):
  660     def __init__(self, *args, **kwargs):
  661     def __len__(self):
  662     def __getattr__(self, attr):
  663     def __getitem__(self, num):
  664     def __contains__(self, value):
  665     def reverse(self):
  666     def sorted(self, property, reverse=False):
  667     def plain(self, escape=0):
  668     def field(self, size=30, showid=0):
  669     def menu(self, size=None, height=None, showid=0, additional=[],
  670 
  671 def make_key_function(db, classname, sort_on=None):
  672     def keyfunc(a):
  673 
  674 def find_sort_key(linkcl):
  675 
  676 def handleListCGIValue(value):
  677 
  678 class ShowDict:
  679     def __init__(self, columns):
  680     def __getitem__(self, name):
  681 
  682 class HTMLRequest(HTMLInputMixin):
  683     def __init__(self, client):
  684     def _post_init(self):
  685     def updateFromURL(self, url):
  686     def update(self, kwargs):
  687     def description(self):
  688     def __str__(self):
  689     def indexargs_form(self, columns=1, sort=1, group=1, filter=1,
  690     def indexargs_url(self, url, args):
  691     def base_javascript(self):
  692     def batch(self):
  693 
  694 class Batch(ZTUtils.Batch):
  695     def __init__(self, client, sequence, size, start, end=0, orphan=0,
  696     def __getitem__(self, index):
  697     def propchanged(self, property):
  698     def previous(self):
  699     def next(self):
  700 
  701 #class TemplatingUtils:
  702 #    def __init__(self, client):
  703 #    def Batch(self, sequence, size, start, end=0, orphan=0, overlap=0):
  704 
  705 class NoTemplate(Exception):
  706 class Unauthorised(Exception):
  707     def __init__(self, action, klass):
  708     def __str__(self):
  709 
  710 class Loader:
  711     def __init__(self, dir):
  712     def precompileTemplates(self):
  713     def load(self, name, extension=None):
  714     def __getitem__(self, name):
  715 
  716 class RoundupPageTemplate(PageTemplate.PageTemplate):
  717     def getContext(self, client, classname, request):
  718     def render(self, client, classname, request, **options):
  719     def __repr__(self):
  720 '''
  721 
  722 # vim: set et sts=4 sw=4 :