Package libxyz :: Package parser :: Module tests |
[hide private]
[frames] | no frames]

# Source Code for Module libxyz.parser.tests

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <mek@mek.uz.ua> 2008-2009
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  # Parsers tests
     18
     19  import re
     20  import unittest
     21  import locale
     22  import gettext
     23  import __builtin__
     24  from nose.tools import raises
     25
     26  from libxyz.parser import BlockParser, MultiParser, FlatParser, RegexpParser
     27  from libxyz.exceptions import ParseError, XYZValueError
     28
     29  __builtin__.__dict__["xyzenc"] = locale.getpreferredencoding()
     30
     31 -def setup():
     32      gettext.install("xyzcmd")
     33
     34 -class TestBlock(object):
     35 -    def setUp(self):
     36          self.p = BlockParser()
     37
     38      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     39
     40      @raises(XYZValueError)
     41 -    def testOptType(self):
     42          """
     43          Raise error on wrong opt type
     44          """
     45
     46          BlockParser(1)
     47
     48      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     49
     50      @raises(ParseError)
     51 -    def testQuote(self):
     52          """
     53          Parsing should raise ParseError on unterminated quotes
     54          """
     55
     56          ParseError(self.p.parse("block {a = \"string\n}"))
     57
     58      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     59
     60 -    def testXQuote(self):
     61          """
     62          Test extended quotes
     63          """
     64
     65          assert len(self.p.parse(
     66              "block { x = ''' ssaf \t \n ; \" ' '' ; & }''' }"))
     67
     68      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     69
     70 -    def testEmptyQuote(self):
     71          """
     72          Test parsing empty string value: ""
     73          """
     74
     75          assert len(self.p.parse('block { x = "" }'))
     76
     77      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     78
     79 -    def testEmptyXQuote(self):
     80          """
     81          Test parsing empty x-quote
     82          """
     83
     84          assert len(self.p.parse("block { x = '''''' }"))
     85
     86      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     87
     88 -    def testComments(self):
     89          """
     90          Test proper commenting
     91          """
     92
     93          assert len(self.p.parse(
     94              "# \tComment 1\n#Comment 2 ''' = }{\n block {}")) == 0
     95
     96      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     97
     98      @raises(ParseError)
     99 -    def testInit(self):
    100          """
    101          In STATE_INIT state only keyword is acceptable
    102          """
    103
    104          self.p.parse("anything")
    105
    106      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    107
    108      @raises(ParseError)
    109 -    def testUnknownVar(self):
    110          """
    111          Variable not in valid list is not allowed
    112          """
    113
    114          _opt = {"validvars": ("a",)}
    115          BlockParser(_opt).parse("block {b = 1}")
    116
    117      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    118
    119      @raises(ParseError)
    120 -    def testValidVar(self):
    121          """
    122          Invalid variable name should raise exception
    123          """
    124
    125          self.p.parse("block {a+-; = 1}")
    126
    127      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    128
    129 -    def testAssignChar1(self):
    130          """
    131          Test for assign character
    132          """
    133
    134          _opt = {"assignchar": ":"}
    135          _p = BlockParser(_opt)
    136          assert len(_p.parse("block {a: 1}"))
    137
    138      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    139
    140 -    def testAssignChar2(self):
    141          """
    142          Test for assign character
    143          """
    144
    145          _opt = {"assignchar": ":"}
    146          _p = BlockParser(_opt)
    147          assert len(_p.parse("block {a: 1}"))
    148
    149      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    150
    151      @raises(ParseError)
    152 -    def testDelimiter1(self):
    153          """
    154          Correct delimiter should be supplied
    155          """
    156
    157          _opt = {"delimiter": ";"}
    158          _p = BlockParser(_opt)
    159          _p.parse("block {a = 1\nb = 2\n}")
    160
    161      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    162
    163 -    def testDelimiter2(self):
    164          """
    165          Correct delimiter should be supplied
    166          """
    167
    168          _opt = {"delimiter": ";"}
    169          _p = BlockParser(_opt)
    170          assert len(_p.parse("block {a = 1;b = 2} block2 {x=y;y=x}"))
    171
    172      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    173
    174      @raises(ParseError)
    175 -    def testCompleteQuote(self):
    176          """
    177          Check for unclosed quote upon EOF
    178          """
    179
    180          self.p.parse("block {a = \"string")
    181
    182      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    183
    184      @raises(ParseError)
    185 -    def testCompleteBlock(self):
    186          """
    187          Check for unclosed block upon EOF
    188          """
    189
    190          self.p.parse("block {a = value\n")
    191
    192      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    193
    194      @raises(ParseError)
    195 -    def testValueValidator1(self):
    196          """
    197          Check if value_validator raises exception1
    198          """
    199
    200          def _f(block, var, val):
    201              if val != "CORRECT_VALUE":
    202                  raise XYZValueError("Incorrect value %s!" % val)
    203
    204              return val
    205
    206          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    207
    208          _opt = {"value_validator": _f}
    209          _p = BlockParser(_opt)
    210          _p.parse("block { a = INCORRECT_VALUE }")
    211
    212      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    213
    214      @raises(ParseError)
    215 -    def testMacroValueValidator1(self):
    216          """
    217          Check if value_validator raises exception on macro
    218          """
    219
    220          def _f(block, var, val):
    221              if val != "CORRECT_VALUE":
    222                  raise XYZValueError("Incorrect value %s!" % val)
    223
    224              return val
    225
    226          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    227
    228          _opt = {"value_validator": _f}
    229          _p = BlockParser(_opt)
    230          _p.parse("block { &m = INCORRECT_VALUE\n test = &m }")
    231
    232      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    233
    234      @raises(ParseError)
    235 -    def testVarTransformation1(self):
    236          """
    237          Check for correct var transformation
    238          """
    239
    240          def _f(a):
    241              raise XYZValueError(a)
    242
    243          _opt = {"var_transform": _f}
    244          _p = BlockParser(_opt)
    245
    246          _p.parse("block { a = VALUE }")
    247
    248      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    249
    250 -    def testValueValidator2(self):
    251          """
    252          Check for value_validator correct value
    253          """
    254
    255          def _f(block, var, val):
    256              if val != "CORRECT_VALUE":
    257                  raise XYZValueError("Incorrect value %s!" % val)
    258
    259              # Returning modified value
    260              return 1
    261
    262          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    263
    264          _opt = {"value_validator": _f}
    265          _p = BlockParser(_opt)
    266
    267          assert len(_p.parse("block { a = CORRECT_VALUE }"))
    268
    269      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    270
    271 -    def testMacroValueValidator2(self):
    272          """
    273          Check for value_validator correct value on macro
    274          """
    275
    276          def _f(block, var, val):
    277              if val != "CORRECT_VALUE":
    278                  raise XYZValueError("Incorrect value %s!" % val)
    279
    280              # Returning modified value
    281              return 1
    282
    283          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    284
    285          _opt = {"value_validator": _f}
    286          _p = BlockParser(_opt)
    287
    288          len(_p.parse("block { &m = CORRECT_VALUE\n a = &m }"))
    289
    290      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    291
    292 -    def testVarTransformation2(self):
    293          """
    294          Check for correct var transformation
    295          """
    296
    297          _opt = {"var_transform": lambda x: x * 3}
    298
    299          _p = BlockParser(_opt)
    300          _data = _p.parse("block { X = 1 }")
    301
    302          assert "XXX" in _data["block"]
    303
    304      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    305
    306 -    def testEscaping(self):
    307          """
    308          Check for proper escaping
    309          """
    310
    311          assert len(self.p.parse("block { var = a\\ b\\ c }"))
    312
    313      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    314
    315 -    def testListValue(self):
    316          """
    317          Check for proper list values parsing
    318          """
    319
    320          _src = "block { var = l, i, s ,t }"
    321
    322          _r = self.p.parse(_src)
    323          assert isinstance(_r["block"]["var"], tuple)
    324
    325      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    326
    327      @raises(ParseError)
    328 -    def testUndefinedMacro(self):
    329          """
    330          Check for undefined macro
    331          """
    332
    333          self.p.parse("block { a = &undef }")
    334
    335  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    336
    337 -class TestMulti(object):
    338      @raises(XYZValueError)
    339 -    def testArgs(self):
    340          """
    341          Check if raises on invalid arg type
    342          """
    343
    344          MultiParser("WRONG")
    345
    346      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    347
    348      @raises(ParseError)
    349 -    def testUnknownKeyword(self):
    350          """
    351          Test for unknown keyword
    352          """
    353
    354          MultiParser({}).parse("keyword")
    355
    356      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    357
    358 -    def testParsing(self):
    359          """
    360          Try to parse some dummy config file
    361          """
    362
    363          src = """\
    364  AUTHOR: "Max E. Kuznecov <syhpoon@syhpoon.name>"
    365  VERSION: "0.1"
    366  DESCRIPTION: "Default XYZ skin"
    367
    368  fs.type {
    369          file = LIGHT_GRAY
    370          dir = WHITE
    371          block = DARK_MAGENTA
    372          char = LIGHT_MAGENTA
    373          link = LIGHT_CYAN
    374          fifo = DARK_CYAN
    375          socket = DARK_RED
    376  }
    377
    378  fs.regexp {
    379          '''.+\.core$''' = DARK_RED
    380          '''\.+''' = LIGHT_GREY
    381  }
    382
    383  ui.block1 {
    384      a = 1
    385      b = 2
    386  }
    387
    388  ui.block2 {
    389      c = 1
    390      d = 2
    391  }
    392
    393  """
    394          _opt = {"count": 1}
    395
    396          _type = BlockParser(_opt)
    397          _flat = FlatParser(_opt)
    398          _ui = BlockParser(_opt)
    399          _opt["varre"] = re.compile(".+")
    400          _regexp = BlockParser(_opt)
    401
    402          _parsers = {"fs.type": _type,
    403                      "fs.regexp": _regexp,
    404                      ("AUTHOR", "VERSION", "DESCRIPTION"): _flat,
    405                      re.compile("^ui\.(\w+)$"): _ui,
    406                      }
    407
    408          _opt2 = {"tokens": (":",)}
    409
    410          multi = MultiParser(_parsers, _opt2)
    411
    412          data = multi.parse(src)
    413          assert data
    414
    415  #++++++++++++++++++++++++++++++++++++++++++++++++
    416
    417 -class TestFlat(object):
    418 -    def setUp(self):
    419          self.p = FlatParser()
    420
    421      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    422
    423 -    def testComments(self):
    424          """
    425          Test for source type
    426          """
    427
    428          _opt = {"comment": "*"}
    429          _p = FlatParser(_opt)
    430
    431          assert len(_p.parse("* \tComment 1\n*Comment 2 ''' = }{\n A: B"))
    432
    433      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    434
    435      @raises(ParseError)
    436 -    def testAssignChar(self):
    437          """
    438          Test for assign character
    439          """
    440
    441          self.p.parse("X = Y")
    442
    443      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    444
    445      @raises(ParseError)
    446 -    def testDelimChar1(self):
    447          """
    448          Test for delimiter character
    449          """
    450
    451          self.p.parse("X = Y; Y = X")
    452
    453      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    454
    455 -    def testDelimChar2(self):
    456          """
    457          Test for delimiter character
    458          """
    459
    460          _p = FlatParser({"delimiter": ";"})
    461          assert len(_p.parse("X: Y; Y: X"))
    462
    463      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    464
    465      @raises(ParseError)
    466 -    def testComplete(self):
    467          """
    468          Check for complete expression
    469          """
    470
    471          self.p.parse("X:")
    472
    473      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    474
    475      @raises(ParseError)
    476 -    def testUnknownVar1(self):
    477          """
    478          Variable not in valid list is not allowed
    479          """
    480
    481          _opt = {"validvars": ("A",)}
    482          FlatParser(_opt).parse("X: Y")
    483
    484      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    485
    486 -    def testUnknownVar2(self):
    487          """
    488          Variable in valid list is allowed
    489          """
    490
    491          _opt = {"validvars": ("A",)}
    492          assert FlatParser(_opt).parse("A: Y")
    493
    494      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    495
    496      @raises(ParseError)
    497 -    def testValueValidator1(self):
    498          """
    499          Check if value_validator raises exception 2
    500          """
    501
    502          def _f(var, val):
    503              if val != "CORRECT_VALUE":
    504                  raise XYZValueError("Incorrect value %s!" % val)
    505
    506              return val
    507
    508          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    509
    510          _opt = {"value_validator": _f}
    511          _p = FlatParser(_opt)
    512
    513          _p.parse("A: INCORRECT_VALUE")
    514
    515      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    516
    517 -    def testValueValidator2(self):
    518          """
    519          Check if value_validator accepts correct value
    520          """
    521
    522          def _f(var, val):
    523              if val != "CORRECT_VALUE":
    524                  raise XYZValueError("Incorrect value %s!" % val)
    525
    526              return val
    527
    528          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    529
    530          _opt = {"value_validator": _f}
    531          _p = FlatParser(_opt)
    532
    533          assert self.p.parse("A: CORRECT_VALUE")
    534
    535      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    536
    537 -    def testListValue(self):
    538          """
    539          Check for proper list values parsing
    540          """
    541
    542          _p = FlatParser()
    543          _src = "var : l, i, s ,t"
    544
    545          _r = _p.parse(_src)
    546          assert isinstance(_r["var"], tuple)
    547
    548  #++++++++++++++++++++++++++++++++++++++++++++++++
    549
    550 -class TestRegexp(unittest.TestCase):
    551      res = False
    552
    553      @raises(ParseError)
    554 -    def testCBFailure(self):
    555          """
    556          Test for callback raising exceptions
    557          """
    558
    559          def cb(mo):
    560              raise XYZValueError(u"Test error")
    561
    562          _p = RegexpParser({re.compile("^test line$"): cb})
    563          _src = "test line"
    564
    565          _p.parse(_src)
    566
    567      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    568
    569 -    def testCBSuccess(self):
    570          """
    571          Test for callback success
    572          """
    573
    574          self.res = False
    575
    576          def cb(mo):
    577              self.res = True
    578
    579          _p = RegexpParser({re.compile("^test line$"): cb})
    580          _src = "test line"
    581
    582          _p.parse(_src)
    583
    584          assert self.res
    585
    586      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    587
    588      @raises(ParseError)
    589 -    def testUnmatched(self):
    590          """
    591          Test for umatched line
    592          """
    593
    594          def cb(mo):
    595              return
    596
    597          _p = RegexpParser({re.compile("^test line$"): cb})
    598          _src = "NOT a test line"
    599
    600          _p.parse(_src)
    601