MoinMoin/_tests/test_wikiutil.py
author Thomas Waldmann <tw AT waldmann-edv DOT de>
Wed, 11 Feb 2009 02:34:33 +0100
changeset 4569 3caaa8c74c41
parent 4566 2eaf4b42b400
child 4607 d8e5e9cfadf1
permissions -rw-r--r--
wikiutil: replace moin's cgi/urllib wrappers by calls to werkzeug.utils code
     1 # -*- coding: iso-8859-1 -*-
     2 """
     3     MoinMoin - MoinMoin.wikiutil Tests
     4 
     5     @copyright: 2003-2004 by Juergen Hermann <jh@web.de>,
     6                 2007 by MoinMoin:ThomasWaldmann
     7     @license: GNU GPL, see COPYING for details.
     8 """
     9 
    10 import py
    11 
    12 from MoinMoin import config, wikiutil
    13 
    14 from werkzeug.utils import MultiDict
    15 
    16 
    17 class TestQueryStringSupport:
    18     tests = [
    19         ('', {}, {}),
    20         ('key1=value1', {'key1': 'value1'}, {'key1': u'value1'}),
    21         ('key1=value1&key2=value2', {'key1': 'value1', 'key2': 'value2'}, {'key1': u'value1', 'key2': u'value2'}),
    22         ('rc_de=Aktuelle%C3%84nderungen', {'rc_de': 'Aktuelle\xc3\x84nderungen'}, {'rc_de': u'Aktuelle\xc4nderungen'}),
    23     ]
    24     def testParseQueryString(self):
    25         for qstr, expected_str, expected_unicode in self.tests:
    26             assert wikiutil.parseQueryString(qstr) == MultiDict(expected_unicode)
    27             assert wikiutil.parseQueryString(unicode(qstr)) == MultiDict(expected_unicode)
    28 
    29     def testMakeQueryString(self):
    30         for qstr, in_str, in_unicode in self.tests:
    31             assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_unicode)) == MultiDict(in_unicode)
    32             assert wikiutil.parseQueryString(wikiutil.makeQueryString(in_str)) == MultiDict(in_unicode)
    33 
    34 
    35 class TestTickets:
    36     def testTickets(self):
    37         from MoinMoin.Page import Page
    38         # page name with double quotes
    39         self.request.page = Page(self.request, u'bla"bla')
    40         ticket1 = wikiutil.createTicket(self.request)
    41         assert wikiutil.checkTicket(self.request, ticket1)
    42         # page name with non-ASCII chars
    43         self.request.page = Page(self.request, u'\xc4rger')
    44         ticket2 = wikiutil.createTicket(self.request)
    45         assert wikiutil.checkTicket(self.request, ticket2)
    46         # same page with another action
    47         self.request.page = Page(self.request, u'\xc4rger')
    48         self.request.action = 'another'
    49         ticket3 = wikiutil.createTicket(self.request)
    50         assert wikiutil.checkTicket(self.request, ticket3)
    51 
    52         assert ticket1 != ticket2
    53         assert ticket2 != ticket3
    54 
    55 
    56 class TestCleanInput:
    57     def testCleanInput(self):
    58         tests = [(u"", u""), # empty
    59                  (u"aaa\r\n\tbbb", u"aaa   bbb"), # ws chars -> blanks
    60                  (u"aaa\x00\x01bbb", u"aaabbb"), # strip weird chars
    61                  (u"a"*500, u""), # too long
    62                 ]
    63         for instr, outstr in tests:
    64             assert wikiutil.clean_input(instr) == outstr
    65 
    66 
    67 class TestInterWiki:
    68     def testSplitWiki(self):
    69         tests = [('SomePage', ('Self', 'SomePage')),
    70                  ('OtherWiki:OtherPage', ('OtherWiki', 'OtherPage')),
    71                  (':OtherPage', ('', 'OtherPage')),
    72                  # broken ('/OtherPage', ('Self', '/OtherPage')),
    73                  # wrong interpretation ('MainPage/OtherPage', ('Self', 'MainPage/OtherPage')),
    74                 ]
    75         for markup, (wikiname, pagename) in tests:
    76             assert wikiutil.split_wiki(markup) == (wikiname, pagename)
    77 
    78     def testJoinWiki(self):
    79         tests = [(('http://example.org/', u'SomePage'), 'http://example.org/SomePage'),
    80                  (('http://example.org/?page=$PAGE&action=show', u'SomePage'), 'http://example.org/?page=SomePage&action=show'),
    81                  (('http://example.org/', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen'),
    82                  (('http://example.org/$PAGE/show', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen/show'),
    83                 ]
    84         for (baseurl, pagename), url in tests:
    85             assert wikiutil.join_wiki(baseurl, pagename) == url
    86 
    87 
    88 class TestSystemPagesGroup:
    89     def testSystemPagesGroupNotEmpty(self):
    90         assert self.request.dicts.members('SystemPagesGroup')
    91 
    92 class TestSystemPage:
    93     systemPages = (
    94         # First level, on SystemPagesGroup
    95         'SystemPagesInEnglishGroup',
    96         # Second level, on one of the pages above
    97         'RecentChanges',
    98         'TitleIndex',
    99         )
   100     notSystemPages = (
   101         'NoSuchPageYetAndWillNeverBe',
   102         )
   103 
   104     def testSystemPage(self):
   105         """wikiutil: good system page names accepted, bad rejected"""
   106         for name in self.systemPages:
   107             assert wikiutil.isSystemPage(self.request, name)
   108         for name in self.notSystemPages:
   109             assert not  wikiutil.isSystemPage(self.request, name)
   110 
   111 
   112 class TestTemplatePage:
   113     good = (
   114         'aTemplate',
   115         'MyTemplate',
   116     )
   117     bad = (
   118         'Template',
   119         'I want a Template',
   120         'TemplateInFront',
   121         'xTemplateInFront',
   122         'XTemplateInFront',
   123     )
   124 
   125     def testTemplatePage(self):
   126         """wikiutil: good template names accepted, bad rejected"""
   127         for name in self.good:
   128             assert  wikiutil.isTemplatePage(self.request, name)
   129         for name in self.bad:
   130             assert not wikiutil.isTemplatePage(self.request, name)
   131 
   132 
   133 class TestParmeterParser:
   134 
   135     def testParameterParser(self):
   136         tests = [
   137             # trivial
   138             ('', '', 0, {}),
   139 
   140             # fixed
   141             ('%s%i%f%b', '"test",42,23.0,True', 4, {0: 'test', 1: 42, 2: 23.0, 3: True}),
   142 
   143             # fixed and named
   144             ('%s%(x)i%(y)i', '"test"', 1, {0: 'test', 'x': None, 'y': None}),
   145             ('%s%(x)i%(y)i', '"test",1', 1, {0: 'test', 'x': 1, 'y': None}),
   146             ('%s%(x)i%(y)i', '"test",1,2', 1, {0: 'test', 'x': 1, 'y': 2}),
   147             ('%s%(x)i%(y)i', '"test",x=1', 1, {0: 'test', 'x': 1, 'y': None}),
   148             ('%s%(x)i%(y)i', '"test",x=1,y=2', 1, {0: 'test', 'x': 1, 'y': 2}),
   149             ('%s%(x)i%(y)i', '"test",y=2', 1, {0: 'test', 'x': None, 'y': 2}),
   150 
   151             # test mixed acceptance
   152             ("%ifs", '100', 1, {0: 100}),
   153             ("%ifs", '100.0', 1, {0: 100.0}),
   154             ("%ifs", '"100"', 1, {0: "100"}),
   155 
   156             # boolean
   157             ("%(t)b%(f)b", '', 0, {'t': None, 'f': None}),
   158             ("%(t)b%(f)b", 't=1', 0, {'t': True, 'f': None}),
   159             ("%(t)b%(f)b", 'f=False', 0, {'t': None, 'f': False}),
   160             ("%(t)b%(f)b", 't=True, f=0', 0, {'t': True, 'f': False}),
   161 
   162             # integer
   163             ("%(width)i%(height)i", '', 0, {'width': None, 'height': None}),
   164             ("%(width)i%(height)i", 'width=100', 0, {'width': 100, 'height': None}),
   165             ("%(width)i%(height)i", 'height=200', 0, {'width': None, 'height': 200}),
   166             ("%(width)i%(height)i", 'width=100, height=200', 0, {'width': 100, 'height': 200}),
   167 
   168             # float
   169             ("%(width)f%(height)f", '', 0, {'width': None, 'height': None}),
   170             ("%(width)f%(height)f", 'width=100.0', 0, {'width': 100.0, 'height': None}),
   171             ("%(width)f%(height)f", 'height=2.0E2', 0, {'width': None, 'height': 200.0}),
   172             ("%(width)f%(height)f", 'width=1000.0E-1, height=200.0', 0, {'width': 100.0, 'height': 200.0}),
   173 
   174             # string
   175             ("%(width)s%(height)s", '', 0, {'width': None, 'height': None}),
   176             ("%(width)s%(height)s", 'width="really wide"', 0, {'width': 'really wide', 'height': None}),
   177             ("%(width)s%(height)s", 'height="not too high"', 0, {'width': None, 'height': 'not too high'}),
   178             ("%(width)s%(height)s", 'width="really wide", height="not too high"', 0, {'width': 'really wide', 'height': 'not too high'}),
   179             # conversion from given type to expected type
   180             ("%(width)s%(height)s", 'width=100', 0, {'width': '100', 'height': None}),
   181             ("%(width)s%(height)s", 'width=100, height=200', 0, {'width': '100', 'height': '200'}),
   182 
   183             # complex test
   184             ("%i%sf%s%ifs%(a)s|%(b)s", ' 4,"DI\'NG", b=retry, a="DING"', 2, {0: 4, 1: "DI'NG", 'a': 'DING', 'b': 'retry'}),
   185 
   186             ]
   187         for format, args, expected_fixed_count, expected_dict in tests:
   188             argParser = wikiutil.ParameterParser(format)
   189             fixed_count, arg_dict = argParser.parse_parameters(args)
   190             assert (fixed_count, arg_dict) == (expected_fixed_count, expected_dict)
   191 
   192     def testTooMuchWantedArguments(self):
   193         args = 'width=100, height=200, alt=Example'
   194         argParser = wikiutil.ParameterParser("%(width)s%(height)s")
   195         py.test.raises(ValueError, argParser.parse_parameters, args)
   196 
   197     def testMalformedArguments(self):
   198         args = '='
   199         argParser = wikiutil.ParameterParser("%(width)s%(height)s")
   200         py.test.raises(ValueError, argParser.parse_parameters, args)
   201 
   202     def testWrongTypeFixedPosArgument(self):
   203         args = '0.0'
   204         argParser = wikiutil.ParameterParser("%b")
   205         py.test.raises(ValueError, argParser.parse_parameters, args)
   206 
   207     def testWrongTypeNamedArgument(self):
   208         args = 'flag=0.0'
   209         argParser = wikiutil.ParameterParser("%(flag)b")
   210         py.test.raises(ValueError, argParser.parse_parameters, args)
   211 
   212 
   213 class TestParamParsing:
   214     def testMacroArgs(self):
   215         abcd = [u'a', u'b', u'c', u'd']
   216         abcd_dict = {u'a': u'1', u'b': u'2', u'c': u'3', u'd': u'4'}
   217         tests = [
   218                   # regular and quoting tests
   219                   (u'd = 4,c=3,b=2,a= 1 ',    ([], abcd_dict, [])),
   220                   (u'a,b,c,d',                (abcd, {}, [])),
   221                   (u' a , b , c , d ',        (abcd, {}, [])),
   222                   (u'   a   ',                ([u'a'], {}, [])),
   223                   (u'"  a  "',                ([u'  a  '], {}, [])),
   224                   (u'a,b,c,d, "a,b,c,d"',     (abcd+[u'a,b,c,d'], {}, [])),
   225                   (u'quote " :), b',          ([u'quote " :)', u'b'], {}, [])),
   226                   (u'"quote "" :)", b',       ([u'quote " :)', u'b'], {}, [])),
   227                   (u'=7',                     ([], {u'': u'7'}, [])),
   228                   (u',,',                     ([None, None, None], {}, [])),
   229                   (u',"",',                   ([None, u'', None], {}, [])),
   230                   (u',"", ""',                ([None, u'', u''], {}, [])),
   231                   (u'  ""  ,"", ""',          ([u'', u'', u''], {}, [])),
   232                   # some name=value test
   233                   (u'd = 4,c=3,b=2,a= 1 ',    ([], abcd_dict, [])),
   234                   (u'd=d,e="a,b,c,d"',        ([], {u'd': u'd',
   235                                                     u'e': u'a,b,c,d'}, [])),
   236                   (u'd = d,e = "a,b,c,d"',    ([], {u'd': u'd',
   237                                                     u'e': u'a,b,c,d'}, [])),
   238                   (u'd = d, e = "a,b,c,d"',   ([], {u'd': u'd',
   239                                                     u'e': u'a,b,c,d'}, [])),
   240                   (u'd = , e = "a,b,c,d"',    ([], {u'd': None,
   241                                                     u'e': u'a,b,c,d'}, [])),
   242                   (u'd = "", e = "a,b,c,d"',  ([], {u'd': u'',
   243                                                     u'e': u'a,b,c,d'}, [])),
   244                   (u'd = "", e = ',           ([], {u'd': u'', u'e': None},
   245                                                [])),
   246                   (u'd=""',                   ([], {u'd': u''}, [])),
   247                   (u'd = "", e = ""',         ([], {u'd': u'', u'e': u''},
   248                                                [])),
   249                   # no, None as key isn't accepted
   250                   (u' = "",  e = ""',         ([], {u'': u'', u'e': u''},
   251                                                [])),
   252                   # can quote both name and value:
   253                   (u'd = d," e "= "a,b,c,d"', ([], {u'd': u'd',
   254                                                     u' e ': u'a,b,c,d'}, [])),
   255                   # trailing args
   256                   (u'1,2,a=b,3,4',            ([u'1', u'2'], {u'a': u'b'},
   257                                                [u'3', u'4'])),
   258                   # can quote quotes:
   259                   (u'd = """d"',              ([], {u'd': u'"d'}, [])),
   260                   (u'd = """d"""',            ([], {u'd': u'"d"'}, [])),
   261                   (u'd = "d"" ", e=7',        ([], {u'd': u'd" ', u'e': u'7'},
   262                                                [])),
   263                   (u'd = "d""", e=8',         ([], {u'd': u'd"', u'e': u'8'},
   264                                                [])),
   265                 ]
   266         for args, expected in tests:
   267             result = wikiutil.parse_quoted_separated(args)
   268             assert expected == result
   269             for val in result[0]:
   270                 assert val is None or isinstance(val, unicode)
   271             for val in result[1].keys():
   272                 assert val is None or isinstance(val, unicode)
   273             for val in result[1].values():
   274                 assert val is None or isinstance(val, unicode)
   275             for val in result[2]:
   276                 assert val is None or isinstance(val, unicode)
   277 
   278     def testLimited(self):
   279         tests = [
   280                   # regular and quoting tests
   281                   (u'd = 4,c=3,b=2,a= 1 ',    ([], {u'd': u'4',
   282                                                     u'c': u'3,b=2,a= 1'}, [])),
   283                   (u'a,b,c,d',                ([u'a', u'b,c,d'], {}, [])),
   284                   (u'a=b,b,c,d',              ([], {u'a': u'b'}, [u'b,c,d'])),
   285                 ]
   286         for args, expected in tests:
   287             result = wikiutil.parse_quoted_separated(args, seplimit=1)
   288             assert expected == result
   289             for val in result[0]:
   290                 assert val is None or isinstance(val, unicode)
   291             for val in result[1].keys():
   292                 assert val is None or isinstance(val, unicode)
   293             for val in result[1].values():
   294                 assert val is None or isinstance(val, unicode)
   295             for val in result[2]:
   296                 assert val is None or isinstance(val, unicode)
   297 
   298     def testDoubleNameValueSeparator(self):
   299         tests = [
   300                   # regular and quoting tests
   301                   (u'd==4,=3 ',    ([], {u'd': u'=4', u'': u'3'}, [])),
   302                   (u'===a,b,c,d',  ([], {u'': u'==a'}, [u'b', u'c', u'd'])),
   303                   (u'a,b,===,c,d', ([u'a', u'b'], {u'': u'=='}, [u'c', u'd'])),
   304                 ]
   305 
   306         def _check(a, e):
   307             r = wikiutil.parse_quoted_separated(a)
   308             assert r == e
   309 
   310         for args, expected in tests:
   311             yield _check, args, expected
   312 
   313     def testNoNameValue(self):
   314         abcd = [u'a', u'b', u'c', u'd']
   315         tests = [
   316                   # regular and quoting tests
   317                   (u'd = 4,c=3,b=2,a= 1 ',    [u'd = 4', u'c=3',
   318                                                u'b=2', u'a= 1']),
   319                   (u'a,b,c,d',                abcd),
   320                   (u' a , b , c , d ',        abcd),
   321                   (u'   a   ',                [u'a']),
   322                   (u'"  a  "',                [u'  a  ']),
   323                   (u'a,b,c,d, "a,b,c,d"',     abcd + [u'a,b,c,d']),
   324                   (u'quote " :), b',          [u'quote " :)', u'b']),
   325                   (u'"quote "" :)", b',       [u'quote " :)', u'b']),
   326                   (u'"unended quote',         [u'"unended quote']),
   327                   (u'"',                      [u'"']),
   328                   (u'd=d,e="a,b,c,d"',        [u'd=d', u'e="a', u'b',
   329                                                u'c', u'd"']),
   330                 ]
   331         for args, expected in tests:
   332             result = wikiutil.parse_quoted_separated(args, name_value=False)
   333             assert expected == result
   334             for val in result:
   335                 assert val is None or isinstance(val, unicode)
   336 
   337     def testUnitArgument(self):
   338         result = wikiutil.UnitArgument('7mm', float, ['%', 'mm'])
   339         assert result.get_default() ==  (7.0, 'mm')
   340         assert result.parse_argument('8%') == (8.0, '%')
   341         py.test.raises(ValueError, result.parse_argument,  u'7m')
   342         py.test.raises(ValueError, result.parse_argument,  u'7')
   343         py.test.raises(ValueError, result.parse_argument,  u'mm')
   344 
   345     def testExtendedParser(self):
   346         tests = [
   347             (u'"a", "b", "c"', u',', None, [u'a', u'b', u'c']),
   348             (u'a:b, b:c, c:d', u',', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   349             (u'a:b, b:c, c:d', u',', None, [u'a:b', u'b:c', u'c:d']),
   350             (u'a=b, b=c, c=d', u',', None, [u'a=b', u'b=c', u'c=d']),
   351             (u'a=b, b=c, c=d', u',', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   352             (u'"a"; "b"; "c"', u';', None, [u'a', u'b', u'c']),
   353             (u'a:b; b:c; c:d', u';', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   354             (u'a:b; b:c; c:d', u';', None, [u'a:b', u'b:c', u'c:d']),
   355             (u'a=b; b=c; c=d', u';', None, [u'a=b', u'b=c', u'c=d']),
   356             (u'a=b; b=c; c=d', u';', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   357             (u'"a" "b" "c"', None, None, [u'a', u'b', u'c']),
   358             (u'" a " "b" "c"', None, None, [u' a ', u'b', u'c']),
   359             (u'"a  " "b" "c"', None, None, [u'a  ', u'b', u'c']),
   360             (u'"  a" "b" "c"', None, None, [u'  a', u'b', u'c']),
   361             (u'"  a" "b" "c"', None, u':', [u'  a', u'b', u'c']),
   362             (u'"a:a" "b:b" "c:b"', None, u':', [u'a:a', u'b:b', u'c:b']),
   363             (u'   a:a  ', None, u':', [None, None, None, (u'a', u'a'), None, None]),
   364             (u'a a: a', None, u':', [u'a', (u'a', None), u'a']),
   365             (u'a a:"b c d" a', None, u':', [u'a', (u'a', u'b c d'), u'a']),
   366             (u'a a:"b "" d" a', None, u':', [u'a', (u'a', u'b " d'), u'a']),
   367             (u'title:Help* dog cat', None, u':', [(u'title', u'Help*'), u'dog', u'cat']),
   368             (u'title:Help* "dog cat"', None, u':', [(u'title', u'Help*'), u'dog cat']),
   369             (u'a:b:c d:e:f', None, u':', [(u'a', u'b:c'), (u'd', 'e:f')]),
   370             (u'a:b:c:d', None, u':', [(u'a', u'b:c:d')]),
   371         ]
   372 
   373         def _check(args, sep, kwsep, expected):
   374             res = wikiutil.parse_quoted_separated_ext(args, sep, kwsep)
   375             assert res == expected
   376 
   377         for test in tests:
   378             yield [_check] + list(test)
   379 
   380     def testExtendedParserBracketing(self):
   381         tests = [
   382             (u'"a", "b", "c"', u',', None, [u'a', u'b', u'c']),
   383             (u'("a", "b", "c")', u',', None, [[u'(', u'a', u'b', u'c']]),
   384             (u'("a"("b", "c"))', u',', None, [[u'(', u'a', [u'(', u'b', u'c']]]),
   385             (u'("a"("b)))", "c"))', u',', None, [[u'(', u'a', [u'(', u'b)))', u'c']]]),
   386             (u'("a"("b>>> ( ab )>", "c"))', u',', None, [[u'(', u'a', [u'(', u'b>>> ( ab )>', u'c']]]),
   387             (u'("a" ("b" "c"))', None, None, [[u'(', u'a', [u'(', u'b', u'c']]]),
   388             (u'("a"("b", "c") ) ', u',', None, [[u'(', u'a', [u'(', u'b', u'c']]]),
   389             (u'("a", <"b", ("c")>)', u',', None, [[u'(', u'a', [u'<', u'b', [u'(', u'c']]]]),
   390             (u',,,(a, b, c)', u',', None, [None, None, None, [u'(', u'a', u'b', u'c']]),
   391         ]
   392 
   393         def _check(args, sep, kwsep, expected):
   394             res = wikiutil.parse_quoted_separated_ext(args, sep, kwsep, brackets=(u'<>', u'()'))
   395             assert res == expected
   396 
   397         for test in tests:
   398             yield [_check] + list(test)
   399 
   400     def testExtendedParserQuoting(self):
   401         tests = [
   402             (u'"a b" -a b-', u'"', [u'a b', u'-a', u'b-']),
   403             (u'"a b" -a b-', u"-", [u'"a', u'b"', u'a b']),
   404             (u'"a b" -a b-', u'"-', [u'a b', u'a b']),
   405             (u'"a- b" -a b-', u'"-', [u'a- b', u'a b']),
   406             (u'"a- b" -a" b-', u'"-', [u'a- b', u'a" b']),
   407         ]
   408 
   409         def _check(args, quotes, expected):
   410             res = wikiutil.parse_quoted_separated_ext(args, quotes=quotes)
   411             assert res == expected
   412 
   413         for test in tests:
   414             yield [_check] + list(test)
   415 
   416     def testExtendedParserMultikey(self):
   417         tests = [
   418             (u'"a", "b", "c"', u',', None, [u'a', u'b', u'c']),
   419             (u'a:b, b:c, c:d', u',', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   420             (u'a:b, b:c, c:d', u',', None, [u'a:b', u'b:c', u'c:d']),
   421             (u'a=b, b=c, c=d', u',', None, [u'a=b', u'b=c', u'c=d']),
   422             (u'a=b, b=c, c=d', u',', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   423             (u'"a"; "b"; "c"', u';', None, [u'a', u'b', u'c']),
   424             (u'a:b; b:c; c:d', u';', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   425             (u'a:b; b:c; c:d', u';', None, [u'a:b', u'b:c', u'c:d']),
   426             (u'a=b; b=c; c=d', u';', None, [u'a=b', u'b=c', u'c=d']),
   427             (u'a=b; b=c; c=d', u';', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   428             (u'"a" "b" "c"', None, None, [u'a', u'b', u'c']),
   429             (u'" a " "b" "c"', None, None, [u' a ', u'b', u'c']),
   430             (u'"a  " "b" "c"', None, None, [u'a  ', u'b', u'c']),
   431             (u'"  a" "b" "c"', None, None, [u'  a', u'b', u'c']),
   432             (u'"  a" "b" "c"', None, u':', [u'  a', u'b', u'c']),
   433             (u'"a:a" "b:b" "c:b"', None, u':', [u'a:a', u'b:b', u'c:b']),
   434             (u'   a:a  ', None, u':', [None, None, None, (u'a', u'a'), None, None]),
   435             (u'a a: a', None, u':', [u'a', (u'a', None), u'a']),
   436             (u'a a:"b c d" a', None, u':', [u'a', (u'a', u'b c d'), u'a']),
   437             (u'a a:"b "" d" a', None, u':', [u'a', (u'a', u'b " d'), u'a']),
   438             (u'title:Help* dog cat', None, u':', [(u'title', u'Help*'), u'dog', u'cat']),
   439             (u'title:Help* "dog cat"', None, u':', [(u'title', u'Help*'), u'dog cat']),
   440             (u'a:b:c d:e:f', None, u':', [(u'a', u'b', u'c'), (u'd', 'e', u'f')]),
   441             (u'a:b:c:d', None, u':', [(u'a', u'b', u'c', u'd')]),
   442             (u'a:"b:c":d', None, u':', [(u'a', u'b:c', u'd')]),
   443         ]
   444 
   445         def _check(args, sep, kwsep, expected):
   446             res = wikiutil.parse_quoted_separated_ext(args, sep, kwsep, multikey=True)
   447             assert res == expected
   448 
   449         for test in tests:
   450             yield [_check] + list(test)
   451 
   452     def testExtendedParserPrefix(self):
   453         P = wikiutil.ParserPrefix('+')
   454         M = wikiutil.ParserPrefix('-')
   455         tests = [
   456             (u'"a", "b", "c"', u',', None, [u'a', u'b', u'c']),
   457             (u'a:b, b:c, c:d', u',', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   458             (u'a:b, b:c, c:d', u',', None, [u'a:b', u'b:c', u'c:d']),
   459             (u'a=b, b=c, c=d', u',', None, [u'a=b', u'b=c', u'c=d']),
   460             (u'a=b, b=c, c=d', u',', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   461             (u'"a"; "b"; "c"', u';', None, [u'a', u'b', u'c']),
   462             (u'a:b; b:c; c:d', u';', u':', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   463             (u'a:b; b:c; c:d', u';', None, [u'a:b', u'b:c', u'c:d']),
   464             (u'a=b; b=c; c=d', u';', None, [u'a=b', u'b=c', u'c=d']),
   465             (u'a=b; b=c; c=d', u';', u'=', [(u'a', u'b'), (u'b', u'c'), (u'c', u'd')]),
   466             (u'"a" "b" "c"', None, None, [u'a', u'b', u'c']),
   467             (u'" a " "b" "c"', None, None, [u' a ', u'b', u'c']),
   468             (u'"a  " "b" "c"', None, None, [u'a  ', u'b', u'c']),
   469             (u'"  a" "b" "c"', None, None, [u'  a', u'b', u'c']),
   470             (u'"  a" "b" "c"', None, u':', [u'  a', u'b', u'c']),
   471             (u'"a:a" "b:b" "c:b"', None, u':', [u'a:a', u'b:b', u'c:b']),
   472             (u'   a:a  ', None, u':', [None, None, None, (u'a', u'a'), None, None]),
   473             (u'a a: a', None, u':', [u'a', (u'a', None), u'a']),
   474             (u'a a:"b c d" a', None, u':', [u'a', (u'a', u'b c d'), u'a']),
   475             (u'a a:"b "" d" a', None, u':', [u'a', (u'a', u'b " d'), u'a']),
   476             (u'title:Help* dog cat', None, u':', [(u'title', u'Help*'), u'dog', u'cat']),
   477             (u'title:Help* "dog cat"', None, u':', [(u'title', u'Help*'), u'dog cat']),
   478             (u'a:b:c d:e:f', None, u':', [(u'a', u'b', u'c'), (u'd', 'e', u'f')]),
   479             (u'a:b:c:d', None, u':', [(u'a', u'b', u'c', u'd')]),
   480             (u'a:"b:c":d', None, u':', [(u'a', u'b:c', u'd')]),
   481 
   482             (u'-a:b:d', None, u':', [(M, u'a', u'b', u'd')]),
   483             (u'"-a:b:d"', None, u':', [(u'-a:b:d')]),
   484             (u'-"a:b:d"', None, u':', [(M, u'a:b:d')]),
   485             (u'-a:"b:c":"d e f g"', None, u':', [(M, u'a', u'b:c', u'd e f g')]),
   486             (u'+-a:b:d', None, u':', [(P, u'-a', u'b', u'd')]),
   487             (u'-"+a:b:d"', None, u':', [(M, u'+a:b:d')]),
   488             # bit of a weird case...
   489             (u'-+"a:b:d"', None, u':', [(M, u'+"a', u'b', u'd"')]),
   490             (u'-a:"b:c" a +b', None, u':', [(M, u'a', u'b:c'), u'a', (P, u'b')]),
   491         ]
   492 
   493         def _check(args, sep, kwsep, expected):
   494             res = wikiutil.parse_quoted_separated_ext(args, sep, kwsep, multikey=True, prefixes='-+')
   495             assert res == expected
   496 
   497         for test in tests:
   498             yield [_check] + list(test)
   499 
   500     def testExtendedParserBracketingErrors(self):
   501         UCE = wikiutil.BracketUnexpectedCloseError
   502         MCE = wikiutil.BracketMissingCloseError
   503         tests = [
   504             (u'("a", "b", "c"', u',', None, MCE),
   505             (u'("a"("b", "c")', u',', None, MCE),
   506             (u'("a"<"b", "c")>', u',', None, UCE),
   507             (u')("a" ("b" "c"))', None, None, UCE),
   508             (u'("a", ("b", "c">))', u',', None, UCE),
   509             (u'("a", ("b", <"c">>))', u',', None, UCE),
   510             (u'(<(<)>)>', u',', None, UCE),
   511         ]
   512 
   513         def _check(args, sep, kwsep, err):
   514             py.test.raises(err,
   515                            wikiutil.parse_quoted_separated_ext,
   516                            args, sep, kwsep,
   517                            brackets=(u'<>', u'()'))
   518 
   519         for test in tests:
   520             yield [_check] + list(test)
   521 
   522 class TestArgGetters:
   523     def testGetBoolean(self):
   524         tests = [
   525             # default testing for None value
   526             (None, None, None, None),
   527             (None, None, False, False),
   528             (None, None, True, True),
   529 
   530             # some real values
   531             (u'0', None, None, False),
   532             (u'1', None, None, True),
   533             (u'false', None, None, False),
   534             (u'true', None, None, True),
   535             (u'FALSE', None, None, False),
   536             (u'TRUE', None, None, True),
   537             (u'no', None, None, False),
   538             (u'yes', None, None, True),
   539             (u'NO', None, None, False),
   540             (u'YES', None, None, True),
   541         ]
   542         for arg, name, default, expected in tests:
   543             assert wikiutil.get_bool(self.request, arg, name, default) == expected
   544 
   545     def testGetBooleanRaising(self):
   546         # wrong default type
   547         py.test.raises(AssertionError, wikiutil.get_bool, self.request, None, None, 42)
   548 
   549         # anything except None or unicode raises TypeError
   550         py.test.raises(TypeError, wikiutil.get_bool, self.request, True)
   551         py.test.raises(TypeError, wikiutil.get_bool, self.request, 42)
   552         py.test.raises(TypeError, wikiutil.get_bool, self.request, 42.0)
   553         py.test.raises(TypeError, wikiutil.get_bool, self.request, '')
   554         py.test.raises(TypeError, wikiutil.get_bool, self.request, tuple())
   555         py.test.raises(TypeError, wikiutil.get_bool, self.request, [])
   556         py.test.raises(TypeError, wikiutil.get_bool, self.request, {})
   557 
   558         # any value not convertable to boolean raises ValueError
   559         py.test.raises(ValueError, wikiutil.get_bool, self.request, u'')
   560         py.test.raises(ValueError, wikiutil.get_bool, self.request, u'42')
   561         py.test.raises(ValueError, wikiutil.get_bool, self.request, u'wrong')
   562         py.test.raises(ValueError, wikiutil.get_bool, self.request, u'"True"') # must not be quoted!
   563 
   564     def testGetInt(self):
   565         tests = [
   566             # default testing for None value
   567             (None, None, None, None),
   568             (None, None, -23, -23),
   569             (None, None, 42, 42),
   570 
   571             # some real values
   572             (u'0', None, None, 0),
   573             (u'42', None, None, 42),
   574             (u'-23', None, None, -23),
   575         ]
   576         for arg, name, default, expected in tests:
   577             assert wikiutil.get_int(self.request, arg, name, default) == expected
   578 
   579     def testGetIntRaising(self):
   580         # wrong default type
   581         py.test.raises(AssertionError, wikiutil.get_int, self.request, None, None, 42.23)
   582 
   583         # anything except None or unicode raises TypeError
   584         py.test.raises(TypeError, wikiutil.get_int, self.request, True)
   585         py.test.raises(TypeError, wikiutil.get_int, self.request, 42)
   586         py.test.raises(TypeError, wikiutil.get_int, self.request, 42.0)
   587         py.test.raises(TypeError, wikiutil.get_int, self.request, '')
   588         py.test.raises(TypeError, wikiutil.get_int, self.request, tuple())
   589         py.test.raises(TypeError, wikiutil.get_int, self.request, [])
   590         py.test.raises(TypeError, wikiutil.get_int, self.request, {})
   591 
   592         # any value not convertable to int raises ValueError
   593         py.test.raises(ValueError, wikiutil.get_int, self.request, u'')
   594         py.test.raises(ValueError, wikiutil.get_int, self.request, u'23.42')
   595         py.test.raises(ValueError, wikiutil.get_int, self.request, u'wrong')
   596         py.test.raises(ValueError, wikiutil.get_int, self.request, u'"4711"') # must not be quoted!
   597 
   598     def testGetFloat(self):
   599         tests = [
   600             # default testing for None value
   601             (None, None, None, None),
   602             (None, None, -23.42, -23.42),
   603             (None, None, 42.23, 42.23),
   604 
   605             # some real values
   606             (u'0', None, None, 0),
   607             (u'42.23', None, None, 42.23),
   608             (u'-23.42', None, None, -23.42),
   609             (u'-23.42E3', None, None, -23.42E3),
   610             (u'23.42E-3', None, None, 23.42E-3),
   611         ]
   612         for arg, name, default, expected in tests:
   613             assert wikiutil.get_float(self.request, arg, name, default) == expected
   614 
   615     def testGetFloatRaising(self):
   616         # wrong default type
   617         py.test.raises(AssertionError, wikiutil.get_float, self.request, None, None, u'42')
   618 
   619         # anything except None or unicode raises TypeError
   620         py.test.raises(TypeError, wikiutil.get_float, self.request, True)
   621         py.test.raises(TypeError, wikiutil.get_float, self.request, 42)
   622         py.test.raises(TypeError, wikiutil.get_float, self.request, 42.0)
   623         py.test.raises(TypeError, wikiutil.get_float, self.request, '')
   624         py.test.raises(TypeError, wikiutil.get_float, self.request, tuple())
   625         py.test.raises(TypeError, wikiutil.get_float, self.request, [])
   626         py.test.raises(TypeError, wikiutil.get_float, self.request, {})
   627 
   628         # any value not convertable to int raises ValueError
   629         py.test.raises(ValueError, wikiutil.get_float, self.request, u'')
   630         py.test.raises(ValueError, wikiutil.get_float, self.request, u'wrong')
   631         py.test.raises(ValueError, wikiutil.get_float, self.request, u'"47.11"') # must not be quoted!
   632 
   633     def testGetComplex(self):
   634         tests = [
   635             # default testing for None value
   636             (None, None, None, None),
   637             (None, None, -23.42, -23.42),
   638             (None, None, 42.23, 42.23),
   639 
   640             # some real values
   641             (u'0', None, None, 0),
   642             (u'42.23', None, None, 42.23),
   643             (u'-23.42', None, None, -23.42),
   644             (u'-23.42E3', None, None, -23.42E3),
   645             (u'23.42E-3', None, None, 23.42E-3),
   646             (u'23.42E-3+3.04j', None, None, 23.42E-3+3.04j),
   647             (u'3.04j', None, None, 3.04j),
   648             (u'-3.04j', None, None, -3.04j),
   649             (u'23.42E-3+3.04i', None, None, 23.42E-3+3.04j),
   650             (u'3.04i', None, None, 3.04j),
   651             (u'-3.04i', None, None, -3.04j),
   652             (u'-3', None, None, -3L),
   653             (u'-300000000000000000000', None, None, -300000000000000000000L),
   654         ]
   655         for arg, name, default, expected in tests:
   656             assert wikiutil.get_complex(self.request, arg, name, default) == expected
   657 
   658     def testGetComplexRaising(self):
   659         # wrong default type
   660         py.test.raises(AssertionError, wikiutil.get_complex, self.request, None, None, u'42')
   661 
   662         # anything except None or unicode raises TypeError
   663         py.test.raises(TypeError, wikiutil.get_complex, self.request, True)
   664         py.test.raises(TypeError, wikiutil.get_complex, self.request, 42)
   665         py.test.raises(TypeError, wikiutil.get_complex, self.request, 42.0)
   666         py.test.raises(TypeError, wikiutil.get_complex, self.request, 3j)
   667         py.test.raises(TypeError, wikiutil.get_complex, self.request, '')
   668         py.test.raises(TypeError, wikiutil.get_complex, self.request, tuple())
   669         py.test.raises(TypeError, wikiutil.get_complex, self.request, [])
   670         py.test.raises(TypeError, wikiutil.get_complex, self.request, {})
   671 
   672         # any value not convertable to int raises ValueError
   673         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'')
   674         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'3jj')
   675         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'3Ij')
   676         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'3i-3i')
   677         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'wrong')
   678         py.test.raises(ValueError, wikiutil.get_complex, self.request, u'"47.11"') # must not be quoted!
   679 
   680     def testGetUnicode(self):
   681         tests = [
   682             # default testing for None value
   683             (None, None, None, None),
   684             (None, None, u'', u''),
   685             (None, None, u'abc', u'abc'),
   686 
   687             # some real values
   688             (u'', None, None, u''),
   689             (u'abc', None, None, u'abc'),
   690             (u'"abc"', None, None, u'"abc"'),
   691         ]
   692         for arg, name, default, expected in tests:
   693             assert wikiutil.get_unicode(self.request, arg, name, default) == expected
   694 
   695     def testGetUnicodeRaising(self):
   696         # wrong default type
   697         py.test.raises(AssertionError, wikiutil.get_unicode, self.request, None, None, 42)
   698 
   699         # anything except None or unicode raises TypeError
   700         py.test.raises(TypeError, wikiutil.get_unicode, self.request, True)
   701         py.test.raises(TypeError, wikiutil.get_unicode, self.request, 42)
   702         py.test.raises(TypeError, wikiutil.get_unicode, self.request, 42.0)
   703         py.test.raises(TypeError, wikiutil.get_unicode, self.request, '')
   704         py.test.raises(TypeError, wikiutil.get_unicode, self.request, tuple())
   705         py.test.raises(TypeError, wikiutil.get_unicode, self.request, [])
   706         py.test.raises(TypeError, wikiutil.get_unicode, self.request, {})
   707 
   708 
   709 class TestExtensionInvoking:
   710     def _test_invoke_bool(self, b=bool):
   711         assert b is False
   712 
   713     def _test_invoke_bool_def(self, v=bool, b=False):
   714         assert b == v
   715         assert isinstance(b, bool)
   716         assert isinstance(v, bool)
   717 
   718     def _test_invoke_int_None(self, i=int):
   719         assert i == 1 or i is None
   720 
   721     def _test_invoke_float_None(self, i=float):
   722         assert i == 1.4 or i is None
   723 
   724     def _test_invoke_float_required(self, i=wikiutil.required_arg(float)):
   725         assert i == 1.4
   726 
   727     def _test_invoke_choice(self, a, choice=[u'a', u'b', u'c']):
   728         assert a == 7
   729         assert choice == u'a'
   730 
   731     def _test_invoke_choicet(self, a, choice=(u'a', u'b', u'c')):
   732         assert a == 7
   733         assert choice == u'a'
   734 
   735     def _test_invoke_choice_required(self, i=wikiutil.required_arg((u'b', u'a'))):
   736         assert i == u'a'
   737 
   738     def _test_trailing(self, a, _trailing_args=[]):
   739         assert _trailing_args == [u'a']
   740 
   741     def _test_arbitrary_kw(self, expect, _kwargs={}):
   742         assert _kwargs == expect
   743 
   744     def testInvoke(self):
   745         def _test_invoke_int(i=int):
   746             assert i == 1
   747 
   748         def _test_invoke_int_fixed(a, b, i=int):
   749             assert a == 7
   750             assert b == 8
   751             assert i == 1 or i is None
   752 
   753         ief = wikiutil.invoke_extension_function
   754         ief(self.request, self._test_invoke_bool, u'False')
   755         ief(self.request, self._test_invoke_bool, u'b=False')
   756         ief(self.request, _test_invoke_int, u'1')
   757         ief(self.request, _test_invoke_int, u'i=1')
   758         ief(self.request, self._test_invoke_bool_def, u'False, False')
   759         ief(self.request, self._test_invoke_bool_def, u'b=False, v=False')
   760         ief(self.request, self._test_invoke_bool_def, u'False')
   761         ief(self.request, self._test_invoke_int_None, u'i=1')
   762         ief(self.request, self._test_invoke_int_None, u'i=')
   763         ief(self.request, self._test_invoke_int_None, u'')
   764         py.test.raises(ValueError, ief, self.request,
   765                        self._test_invoke_int_None, u'x')
   766         py.test.raises(ValueError, ief, self.request,
   767                        self._test_invoke_int_None, u'""')
   768         py.test.raises(ValueError, ief, self.request,
   769                        self._test_invoke_int_None, u'i=""')
   770         py.test.raises(ValueError, ief, self.request,
   771                        _test_invoke_int_fixed, u'a=7', [7, 8])
   772         ief(self.request, _test_invoke_int_fixed, u'i=1', [7, 8])
   773         py.test.raises(ValueError, ief, self.request,
   774                        _test_invoke_int_fixed, u'i=""', [7, 8])
   775         ief(self.request, _test_invoke_int_fixed, u'i=', [7, 8])
   776 
   777         for choicefn in (self._test_invoke_choice, self._test_invoke_choicet):
   778             ief(self.request, choicefn, u'', [7])
   779             ief(self.request, choicefn, u'choice=a', [7])
   780             ief(self.request, choicefn, u'choice=', [7])
   781             ief(self.request, choicefn, u'choice="a"', [7])
   782             py.test.raises(ValueError, ief, self.request,
   783                            choicefn, u'x', [7])
   784             py.test.raises(ValueError, ief, self.request,
   785                            choicefn, u'choice=x', [7])
   786 
   787         ief(self.request, self._test_invoke_float_None, u'i=1.4')
   788         ief(self.request, self._test_invoke_float_None, u'i=')
   789         ief(self.request, self._test_invoke_float_None, u'')
   790         ief(self.request, self._test_invoke_float_None, u'1.4')
   791         py.test.raises(ValueError, ief, self.request,
   792                        self._test_invoke_float_None, u'x')
   793         py.test.raises(ValueError, ief, self.request,
   794                        self._test_invoke_float_None, u'""')
   795         py.test.raises(ValueError, ief, self.request,
   796                        self._test_invoke_float_None, u'i=""')
   797         ief(self.request, self._test_trailing, u'a=7, a')
   798         ief(self.request, self._test_trailing, u'7, a')
   799         ief(self.request, self._test_arbitrary_kw, u'test=x, \xc3=test',
   800             [{u'\xc3': 'test', 'test': u'x'}])
   801         ief(self.request, self._test_arbitrary_kw, u'test=x, "\xc3"=test',
   802             [{u'\xc3': 'test', 'test': u'x'}])
   803         ief(self.request, self._test_arbitrary_kw, u'test=x, "7 \xc3"=test',
   804             [{u'7 \xc3': 'test', 'test': u'x'}])
   805         ief(self.request, self._test_arbitrary_kw, u'test=x, 7 \xc3=test',
   806             [{u'7 \xc3': 'test', 'test': u'x'}])
   807         ief(self.request, self._test_arbitrary_kw, u'7 \xc3=test, test= x ',
   808             [{u'7 \xc3': 'test', 'test': u'x'}])
   809         py.test.raises(ValueError, ief, self.request,
   810                        self._test_invoke_float_required, u'')
   811         ief(self.request, self._test_invoke_float_required, u'1.4')
   812         ief(self.request, self._test_invoke_float_required, u'i=1.4')
   813         py.test.raises(ValueError, ief, self.request,
   814                        self._test_invoke_choice_required, u'')
   815         ief(self.request, self._test_invoke_choice_required, u'a')
   816         ief(self.request, self._test_invoke_choice_required, u'i=a')
   817         py.test.raises(ValueError, ief, self.request,
   818                        self._test_invoke_float_required, u',')
   819 
   820     def testConstructors(self):
   821         ief = wikiutil.invoke_extension_function
   822 
   823         # new style class
   824         class TEST1(object):
   825             def __init__(self, a=int):
   826                 self.constructed = True
   827                 assert a == 7
   828 
   829         class TEST2(TEST1):
   830             pass
   831 
   832         obj = ief(self.request, TEST1, u'a=7')
   833         assert isinstance(obj, TEST1)
   834         assert obj.constructed
   835         py.test.raises(ValueError, ief, self.request, TEST1, u'b')
   836 
   837         obj = ief(self.request, TEST2, u'a=7')
   838         assert isinstance(obj, TEST1)
   839         assert isinstance(obj, TEST2)
   840         assert obj.constructed
   841         py.test.raises(ValueError, ief, self.request, TEST2, u'b')
   842 
   843         # old style class
   844         class TEST3:
   845             def __init__(self, a=int):
   846                 self.constructed = True
   847                 assert a == 7
   848 
   849         class TEST4(TEST3):
   850             pass
   851 
   852         obj = ief(self.request, TEST3, u'a=7')
   853         assert isinstance(obj, TEST3)
   854         assert obj.constructed
   855         py.test.raises(ValueError, ief, self.request, TEST3, u'b')
   856 
   857         obj = ief(self.request, TEST4, u'a=7')
   858         assert isinstance(obj, TEST3)
   859         assert isinstance(obj, TEST4)
   860         assert obj.constructed
   861         py.test.raises(ValueError, ief, self.request, TEST4, u'b')
   862 
   863     def testFailing(self):
   864         ief = wikiutil.invoke_extension_function
   865 
   866         py.test.raises(TypeError, ief, self.request, hex, u'15')
   867         py.test.raises(TypeError, ief, self.request, cmp, u'15')
   868         py.test.raises(AttributeError, ief, self.request, unicode, u'15')
   869 
   870     def testAllDefault(self):
   871         ief = wikiutil.invoke_extension_function
   872 
   873         def has_many_defaults(a=1, b=2, c=3, d=4):
   874             assert a == 1
   875             assert b == 2
   876             assert c == 3
   877             assert d == 4
   878             return True
   879 
   880         assert ief(self.request, has_many_defaults, u'1, 2, 3, 4')
   881         assert ief(self.request, has_many_defaults, u'2, 3, 4', [1])
   882         assert ief(self.request, has_many_defaults, u'3, 4', [1, 2])
   883         assert ief(self.request, has_many_defaults, u'4', [1, 2, 3])
   884         assert ief(self.request, has_many_defaults, u'', [1, 2, 3, 4])
   885         assert ief(self.request, has_many_defaults, u'd=4,c=3,b=2,a=1')
   886         assert ief(self.request, has_many_defaults, u'd=4,c=3,b=2', [1])
   887         assert ief(self.request, has_many_defaults, u'd=4,c=3', [1, 2])
   888         assert ief(self.request, has_many_defaults, u'd=4', [1, 2, 3])
   889 
   890     def testInvokeComplex(self):
   891         ief = wikiutil.invoke_extension_function
   892 
   893         def has_complex(a=complex, b=complex):
   894             assert a == b
   895             return True
   896 
   897         assert ief(self.request, has_complex, u'3-3i, 3-3j')
   898         assert ief(self.request, has_complex, u'2i, 2j')
   899         assert ief(self.request, has_complex, u'b=2i, a=2j')
   900         assert ief(self.request, has_complex, u'2.007, 2.007')
   901         assert ief(self.request, has_complex, u'2.007', [2.007])
   902         assert ief(self.request, has_complex, u'b=2.007', [2.007])
   903 
   904 
   905 class TestAnchorNames:
   906     def test_anchor_name_encoding(self):
   907         tests = [
   908             # text                    expected output
   909             (u'\xf6\xf6ll\xdf\xdf',   'A.2BAPYA9g-ll.2BAN8A3w-'),
   910             (u'level 2',              'level_2'),
   911             (u'level_2',              'level_2'),
   912             (u'',                     'A'),
   913             (u'123',                  'A123'),
   914             # make sure that a valid anchor is not modified:
   915             (u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:_.-',
   916              u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:_.-')
   917         ]
   918         for text, expected in tests:
   919             yield self._check, text, expected
   920 
   921     def _check(self, text, expected):
   922         encoded = wikiutil.anchor_name_from_text(text)
   923         assert expected == encoded
   924 
   925 class TestPageLinkMarkup:
   926     def test_pagelinkmarkup(self):
   927         tests = [
   928             # pagename (no link text), expected markup
   929             (('SomePage', ), 'SomePage'),
   930             (('Somepage', ), '[[Somepage]]'),
   931             (('somepage', ), '[[somepage]]'),
   932             (('Some Page', ), '[[Some Page]]'),
   933             # with link text
   934             (('SomePage', 'SomePage'), 'SomePage'),
   935             (('SomePage', 'some page'), '[[SomePage|some page]]'),
   936             (('Some Page', 'Some Page'), '[[Some Page]]'),
   937             (('Some Page', 'some Page'), '[[Some Page|some Page]]'),
   938         ]
   939         for params, expected in tests:
   940             yield self._check, params, expected
   941 
   942     def _check(self, params, expected):
   943         assert expected == wikiutil.pagelinkmarkup(*params)
   944 
   945 class TestRelativeTools:
   946     tests = [
   947         # test                      expected output
   948         # CHILD_PREFIX
   949         (('MainPage', '/SubPage1'), 'MainPage/SubPage1'),
   950         (('MainPage', '/SubPage1/SubPage2'), 'MainPage/SubPage1/SubPage2'),
   951         (('MainPage/SubPage1', '/SubPage2/SubPage3'), 'MainPage/SubPage1/SubPage2/SubPage3'),
   952         (('', '/OtherMainPage'), 'OtherMainPage'), # strange
   953         # PARENT_PREFIX
   954         (('MainPage/SubPage', '../SisterPage'), 'MainPage/SisterPage'),
   955         (('MainPage/SubPage1/SubPage2', '../SisterPage'), 'MainPage/SubPage1/SisterPage'),
   956         (('MainPage/SubPage1/SubPage2', '../../SisterPage'), 'MainPage/SisterPage'),
   957         (('MainPage', '../SisterPage'), 'SisterPage'), # strange
   958     ]
   959     def test_abs_pagename(self):
   960         for (current_page, relative_page), absolute_page in self.tests:
   961             yield self._check_abs_pagename, current_page, relative_page, absolute_page
   962 
   963     def _check_abs_pagename(self, current_page, relative_page, absolute_page):
   964         assert absolute_page == wikiutil.AbsPageName(current_page, relative_page)
   965 
   966     def test_rel_pagename(self):
   967         for (current_page, relative_page), absolute_page in self.tests:
   968             yield self._check_rel_pagename, current_page, absolute_page, relative_page
   969 
   970     def _check_rel_pagename(self, current_page, absolute_page, relative_page):
   971         assert relative_page == wikiutil.RelPageName(current_page, absolute_page)
   972 
   973 
   974 class TestNormalizePagename(object):
   975 
   976     def testPageInvalidChars(self):
   977         """ request: normalize pagename: remove invalid unicode chars
   978 
   979         Assume the default setting
   980         """
   981         test = u'\u0000\u202a\u202b\u202c\u202d\u202e'
   982         expected = u''
   983         result = wikiutil.normalize_pagename(test, self.request.cfg)
   984         assert result == expected
   985 
   986     def testNormalizeSlashes(self):
   987         """ request: normalize pagename: normalize slashes """
   988         cases = (
   989             (u'/////', u''),
   990             (u'/a', u'a'),
   991             (u'a/', u'a'),
   992             (u'a/////b/////c', u'a/b/c'),
   993             (u'a b/////c d/////e f', u'a b/c d/e f'),
   994             )
   995         for test, expected in cases:
   996             result = wikiutil.normalize_pagename(test, self.request.cfg)
   997             assert result == expected
   998 
   999     def testNormalizeWhitespace(self):
  1000         """ request: normalize pagename: normalize whitespace """
  1001         cases = (
  1002             (u'         ', u''),
  1003             (u'    a', u'a'),
  1004             (u'a    ', u'a'),
  1005             (u'a     b     c', u'a b c'),
  1006             (u'a   b  /  c    d  /  e   f', u'a b/c d/e f'),
  1007             # All 30 unicode spaces
  1008             (config.chars_spaces, u''),
  1009             )
  1010         for test, expected in cases:
  1011             result = wikiutil.normalize_pagename(test, self.request.cfg)
  1012             assert result == expected
  1013 
  1014     def testUnderscoreTestCase(self):
  1015         """ request: normalize pagename: underscore convert to spaces and normalized
  1016 
  1017         Underscores should convert to spaces, then spaces should be
  1018         normalized, order is important!
  1019         """
  1020         cases = (
  1021             (u'         ', u''),
  1022             (u'  a', u'a'),
  1023             (u'a  ', u'a'),
  1024             (u'a  b  c', u'a b c'),
  1025             (u'a  b  /  c  d  /  e  f', u'a b/c d/e f'),
  1026             )
  1027         for test, expected in cases:
  1028             result = wikiutil.normalize_pagename(test, self.request.cfg)
  1029             assert result == expected
  1030 
  1031 class TestGroupPages(object):
  1032 
  1033     def testNormalizeGroupName(self):
  1034         """ request: normalize pagename: restrict groups to alpha numeric Unicode
  1035 
  1036         Spaces should normalize after invalid chars removed!
  1037         """
  1038         cases = (
  1039             # current acl chars
  1040             (u'Name,:Group', u'NameGroup'),
  1041             # remove than normalize spaces
  1042             (u'Name ! @ # $ % ^ & * ( ) + Group', u'Name Group'),
  1043             )
  1044         for test, expected in cases:
  1045             # validate we are testing valid group names
  1046             if wikiutil.isGroupPage(test, self.request.cfg):
  1047                 result = wikiutil.normalize_pagename(test, self.request.cfg)
  1048                 assert result == expected
  1049 
  1050 coverage_modules = ['MoinMoin.wikiutil']