1## @file
2# This file contain unit test for DecParser
3#
4# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
5#
6# This program and the accompanying materials are licensed and made available
7# under the terms and conditions of the BSD License which accompanies this
8# distribution. The full text of the license may be found at
9# http://opensource.org/licenses/bsd-license.php
10#
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14import os
15import unittest
16from Logger.Log import FatalError
17
18from Parser.DecParser import \
19    Dec, \
20    _DecDefine, \
21    _DecLibraryclass, \
22    _DecPcd, \
23    _DecGuid, \
24    FileContent, \
25    _DecBase, \
26    CleanString
27
28from Object.Parser.DecObject import _DecComments
29
30#
31# Test CleanString
32#
33class CleanStringTestCase(unittest.TestCase):
34    def testCleanString(self):
35        Line, Comment = CleanString('')
36        self.assertEqual(Line, '')
37        self.assertEqual(Comment, '')
38
39        Line, Comment = CleanString('line without comment')
40        self.assertEqual(Line, 'line without comment')
41        self.assertEqual(Comment, '')
42
43        Line, Comment = CleanString('# pure comment')
44        self.assertEqual(Line, '')
45        self.assertEqual(Comment, '# pure comment')
46
47        Line, Comment = CleanString('line # and comment')
48        self.assertEqual(Line, 'line')
49        self.assertEqual(Comment, '# and comment')
50
51    def testCleanStringCpp(self):
52        Line, Comment = CleanString('line // and comment', AllowCppStyleComment = True)
53        self.assertEqual(Line, 'line')
54        self.assertEqual(Comment, '# and comment')
55
56#
57# Test _DecBase._MacroParser function
58#
59class MacroParserTestCase(unittest.TestCase):
60    def setUp(self):
61        self.dec = _DecBase(FileContent('dummy', []))
62
63    def testCorrectMacro(self):
64        self.dec._MacroParser('DEFINE MARCRO1 = test1')
65        self.failIf('MARCRO1' not in self.dec._LocalMacro)
66        self.assertEqual(self.dec._LocalMacro['MARCRO1'], 'test1')
67
68    def testErrorMacro1(self):
69        # Raise fatal error, macro name must be upper case letter
70        self.assertRaises(FatalError, self.dec._MacroParser, 'DEFINE not_upper_case = test2')
71
72    def testErrorMacro2(self):
73        # No macro name given
74        self.assertRaises(FatalError, self.dec._MacroParser, 'DEFINE ')
75
76#
77# Test _DecBase._TryBackSlash function
78#
79class TryBackSlashTestCase(unittest.TestCase):
80    def setUp(self):
81        Content = [
82            # Right case
83            'test no backslash',
84
85            'test with backslash \\',
86            'continue second line',
87
88            # Do not precede with whitespace
89            '\\',
90
91            # Empty line after backlash is not allowed
92            'line with backslash \\',
93            ''
94        ]
95        self.dec = _DecBase(FileContent('dummy', Content))
96
97    def testBackSlash(self):
98        #
99        # Right case, assert return values
100        #
101        ConcatLine, CommentList = self.dec._TryBackSlash(self.dec._RawData.GetNextLine(), [])
102        self.assertEqual(ConcatLine, 'test no backslash')
103        self.assertEqual(CommentList, [])
104
105        ConcatLine, CommentList = self.dec._TryBackSlash(self.dec._RawData.GetNextLine(), [])
106        self.assertEqual(CommentList, [])
107        self.assertEqual(ConcatLine, 'test with backslash continue second line')
108
109        #
110        # Error cases, assert raise exception
111        #
112        self.assertRaises(FatalError, self.dec._TryBackSlash, self.dec._RawData.GetNextLine(), [])
113        self.assertRaises(FatalError, self.dec._TryBackSlash, self.dec._RawData.GetNextLine(), [])
114
115#
116# Test _DecBase.Parse function
117#
118class DataItem(_DecComments):
119    def __init__(self):
120        _DecComments.__init__(self)
121        self.String = ''
122
123class Data(_DecComments):
124    def __init__(self):
125        _DecComments.__init__(self)
126        # List of DataItem
127        self.ItemList = []
128
129class TestInner(_DecBase):
130    def __init__(self, RawData):
131        _DecBase.__init__(self, RawData)
132        self.ItemObject = Data()
133
134    def _StopCurrentParsing(self, Line):
135        return Line == '[TOP]'
136
137    def _ParseItem(self):
138        Item = DataItem()
139        Item.String = self._RawData.CurrentLine
140        self.ItemObject.ItemList.append(Item)
141        return Item
142
143    def _TailCommentStrategy(self, Comment):
144        return Comment.find('@comment') != -1
145
146class TestTop(_DecBase):
147    def __init__(self, RawData):
148        _DecBase.__init__(self, RawData)
149        # List of Data
150        self.ItemObject = []
151
152    # Top parser
153    def _StopCurrentParsing(self, Line):
154        return False
155
156    def _ParseItem(self):
157        TestParser = TestInner(self._RawData)
158        TestParser.Parse()
159        self.ItemObject.append(TestParser.ItemObject)
160        return TestParser.ItemObject
161
162class ParseTestCase(unittest.TestCase):
163    def setUp(self):
164        pass
165
166    def testParse(self):
167        Content = \
168        '''# Top comment
169        [TOP]
170          # sub1 head comment
171          (test item has both head and tail comment) # sub1 tail comment
172          # sub2 head comment
173          (test item has head and special tail comment)
174          # @comment test TailCommentStrategy branch
175
176          (test item has no comment)
177
178        # test NextLine branch
179        [TOP]
180          sub-item
181        '''
182        dec = TestTop(FileContent('dummy', Content.splitlines()))
183        dec.Parse()
184
185        # Two sections
186        self.assertEqual(len(dec.ItemObject), 2)
187
188        data = dec.ItemObject[0]
189        self.assertEqual(data._HeadComment[0][0], '# Top comment')
190        self.assertEqual(data._HeadComment[0][1], 1)
191
192        # 3 subitems
193        self.assertEqual(len(data.ItemList), 3)
194
195        dataitem = data.ItemList[0]
196        self.assertEqual(dataitem.String, '(test item has both head and tail comment)')
197        # Comment content
198        self.assertEqual(dataitem._HeadComment[0][0], '# sub1 head comment')
199        self.assertEqual(dataitem._TailComment[0][0], '# sub1 tail comment')
200        # Comment line number
201        self.assertEqual(dataitem._HeadComment[0][1], 3)
202        self.assertEqual(dataitem._TailComment[0][1], 4)
203
204        dataitem = data.ItemList[1]
205        self.assertEqual(dataitem.String, '(test item has head and special tail comment)')
206        # Comment content
207        self.assertEqual(dataitem._HeadComment[0][0], '# sub2 head comment')
208        self.assertEqual(dataitem._TailComment[0][0], '# @comment test TailCommentStrategy branch')
209        # Comment line number
210        self.assertEqual(dataitem._HeadComment[0][1], 5)
211        self.assertEqual(dataitem._TailComment[0][1], 7)
212
213        dataitem = data.ItemList[2]
214        self.assertEqual(dataitem.String, '(test item has no comment)')
215        # Comment content
216        self.assertEqual(dataitem._HeadComment, [])
217        self.assertEqual(dataitem._TailComment, [])
218
219        data = dec.ItemObject[1]
220        self.assertEqual(data._HeadComment[0][0], '# test NextLine branch')
221        self.assertEqual(data._HeadComment[0][1], 11)
222
223        # 1 subitems
224        self.assertEqual(len(data.ItemList), 1)
225
226        dataitem = data.ItemList[0]
227        self.assertEqual(dataitem.String, 'sub-item')
228        self.assertEqual(dataitem._HeadComment, [])
229        self.assertEqual(dataitem._TailComment, [])
230
231#
232# Test _DecDefine._ParseItem
233#
234class DecDefineTestCase(unittest.TestCase):
235    def GetObj(self, Content):
236        Obj = _DecDefine(FileContent('dummy', Content.splitlines()))
237        Obj._RawData.CurrentLine = Obj._RawData.GetNextLine()
238        return Obj
239
240    def testDecDefine(self):
241        item = self.GetObj('PACKAGE_NAME = MdePkg')._ParseItem()
242        self.assertEqual(item.Key, 'PACKAGE_NAME')
243        self.assertEqual(item.Value, 'MdePkg')
244
245    def testDecDefine1(self):
246        obj = self.GetObj('PACKAGE_NAME')
247        self.assertRaises(FatalError, obj._ParseItem)
248
249    def testDecDefine2(self):
250        obj = self.GetObj('unknown_key = ')
251        self.assertRaises(FatalError, obj._ParseItem)
252
253    def testDecDefine3(self):
254        obj = self.GetObj('PACKAGE_NAME = ')
255        self.assertRaises(FatalError, obj._ParseItem)
256
257#
258# Test _DecLibraryclass._ParseItem
259#
260class DecLibraryTestCase(unittest.TestCase):
261    def GetObj(self, Content):
262        Obj = _DecLibraryclass(FileContent('dummy', Content.splitlines()))
263        Obj._RawData.CurrentLine = Obj._RawData.GetNextLine()
264        return Obj
265
266    def testNoInc(self):
267        obj = self.GetObj('UefiRuntimeLib')
268        self.assertRaises(FatalError, obj._ParseItem)
269
270    def testEmpty(self):
271        obj = self.GetObj(' | ')
272        self.assertRaises(FatalError, obj._ParseItem)
273
274    def testLibclassNaming(self):
275        obj = self.GetObj('lowercase_efiRuntimeLib|Include/Library/UefiRuntimeLib.h')
276        self.assertRaises(FatalError, obj._ParseItem)
277
278    def testLibclassExt(self):
279        obj = self.GetObj('RuntimeLib|Include/Library/UefiRuntimeLib.no_h')
280        self.assertRaises(FatalError, obj._ParseItem)
281
282    def testLibclassRelative(self):
283        obj = self.GetObj('RuntimeLib|Include/../UefiRuntimeLib.h')
284        self.assertRaises(FatalError, obj._ParseItem)
285
286#
287# Test _DecPcd._ParseItem
288#
289class DecPcdTestCase(unittest.TestCase):
290    def GetObj(self, Content):
291        Obj = _DecPcd(FileContent('dummy', Content.splitlines()))
292        Obj._RawData.CurrentLine = Obj._RawData.GetNextLine()
293        Obj._RawData.CurrentScope = [('PcdsFeatureFlag'.upper(), 'COMMON')]
294        return Obj
295
296    def testOK(self):
297        item = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE|BOOLEAN|0x0000000d')._ParseItem()
298        self.assertEqual(item.TokenSpaceGuidCName, 'gEfiMdePkgTokenSpaceGuid')
299        self.assertEqual(item.TokenCName, 'PcdComponentNameDisable')
300        self.assertEqual(item.DefaultValue, 'FALSE')
301        self.assertEqual(item.DatumType, 'BOOLEAN')
302        self.assertEqual(item.TokenValue, '0x0000000d')
303
304    def testNoCvar(self):
305        obj = self.GetObj('123ai.PcdComponentNameDisable|FALSE|BOOLEAN|0x0000000d')
306        self.assertRaises(FatalError, obj._ParseItem)
307
308    def testSplit(self):
309        obj = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable FALSE|BOOLEAN|0x0000000d')
310        self.assertRaises(FatalError, obj._ParseItem)
311
312        obj = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE|BOOLEAN|0x0000000d | abc')
313        self.assertRaises(FatalError, obj._ParseItem)
314
315    def testUnknownType(self):
316        obj = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE|unknown|0x0000000d')
317        self.assertRaises(FatalError, obj._ParseItem)
318
319    def testVoid(self):
320        obj = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|abc|VOID*|0x0000000d')
321        self.assertRaises(FatalError, obj._ParseItem)
322
323    def testUINT(self):
324        obj = self.GetObj('gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|0xabc|UINT8|0x0000000d')
325        self.assertRaises(FatalError, obj._ParseItem)
326
327#
328# Test _DecInclude._ParseItem
329#
330class DecIncludeTestCase(unittest.TestCase):
331    #
332    # Test code to be added
333    #
334    pass
335
336#
337# Test _DecGuid._ParseItem
338#
339class DecGuidTestCase(unittest.TestCase):
340    def GetObj(self, Content):
341        Obj = _DecGuid(FileContent('dummy', Content.splitlines()))
342        Obj._RawData.CurrentLine = Obj._RawData.GetNextLine()
343        Obj._RawData.CurrentScope = [('guids'.upper(), 'COMMON')]
344        return Obj
345
346    def testCValue(self):
347        item = self.GetObj('gEfiIpSecProtocolGuid={ 0xdfb386f7, 0xe100, 0x43ad,'
348                           ' {0x9c, 0x9a, 0xed, 0x90, 0xd0, 0x8a, 0x5e, 0x12 }}')._ParseItem()
349        self.assertEqual(item.GuidCName, 'gEfiIpSecProtocolGuid')
350        self.assertEqual(item.GuidCValue, '{ 0xdfb386f7, 0xe100, 0x43ad, {0x9c, 0x9a, 0xed, 0x90, 0xd0, 0x8a, 0x5e, 0x12 }}')
351
352    def testGuidString(self):
353        item = self.GetObj('gEfiIpSecProtocolGuid=1E73767F-8F52-4603-AEB4-F29B510B6766')._ParseItem()
354        self.assertEqual(item.GuidCName, 'gEfiIpSecProtocolGuid')
355        self.assertEqual(item.GuidCValue, '1E73767F-8F52-4603-AEB4-F29B510B6766')
356
357    def testNoValue1(self):
358        obj = self.GetObj('gEfiIpSecProtocolGuid')
359        self.assertRaises(FatalError, obj._ParseItem)
360
361    def testNoValue2(self):
362        obj = self.GetObj('gEfiIpSecProtocolGuid=')
363        self.assertRaises(FatalError, obj._ParseItem)
364
365    def testNoName(self):
366        obj = self.GetObj('=')
367        self.assertRaises(FatalError, obj._ParseItem)
368
369#
370# Test Dec.__init__
371#
372class DecDecInitTestCase(unittest.TestCase):
373    def testNoDecFile(self):
374        self.assertRaises(FatalError, Dec, 'No_Such_File')
375
376class TmpFile:
377    def __init__(self, File):
378        self.File = File
379
380    def Write(self, Content):
381        try:
382            FileObj = open(self.File, 'w')
383            FileObj.write(Content)
384            FileObj.close()
385        except:
386            pass
387
388    def Remove(self):
389        try:
390            os.remove(self.File)
391        except:
392            pass
393
394#
395# Test Dec._UserExtentionSectionParser
396#
397class DecUESectionTestCase(unittest.TestCase):
398    def setUp(self):
399        self.File = TmpFile('test.dec')
400        self.File.Write(
401'''[userextensions.intel."myid"]
402[userextensions.intel."myid".IA32]
403[userextensions.intel."myid".IA32,]
404[userextensions.intel."myid]
405'''
406        )
407
408    def tearDown(self):
409        self.File.Remove()
410
411    def testUserExtentionHeader(self):
412        dec = Dec('test.dec', False)
413
414        # OK: [userextensions.intel."myid"]
415        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
416        dec._UserExtentionSectionParser()
417        self.assertEqual(len(dec._RawData.CurrentScope), 1)
418        self.assertEqual(dec._RawData.CurrentScope[0][0], 'userextensions'.upper())
419        self.assertEqual(dec._RawData.CurrentScope[0][1], 'intel')
420        self.assertEqual(dec._RawData.CurrentScope[0][2], '"myid"')
421        self.assertEqual(dec._RawData.CurrentScope[0][3], 'COMMON')
422
423        # OK: [userextensions.intel."myid".IA32]
424        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
425        dec._UserExtentionSectionParser()
426        self.assertEqual(len(dec._RawData.CurrentScope), 1)
427        self.assertEqual(dec._RawData.CurrentScope[0][0], 'userextensions'.upper())
428        self.assertEqual(dec._RawData.CurrentScope[0][1], 'intel')
429        self.assertEqual(dec._RawData.CurrentScope[0][2], '"myid"')
430        self.assertEqual(dec._RawData.CurrentScope[0][3], 'IA32')
431
432        # Fail: [userextensions.intel."myid".IA32,]
433        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
434        self.assertRaises(FatalError, dec._UserExtentionSectionParser)
435
436        # Fail: [userextensions.intel."myid]
437        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
438        self.assertRaises(FatalError, dec._UserExtentionSectionParser)
439
440#
441# Test Dec._SectionHeaderParser
442#
443class DecSectionTestCase(unittest.TestCase):
444    def setUp(self):
445        self.File = TmpFile('test.dec')
446        self.File.Write(
447'''[no section start or end
448[,] # empty sub-section
449[unknow_section_name]
450[Includes.IA32.other] # no third one
451[PcdsFeatureFlag, PcdsFixedAtBuild] # feature flag PCD must not be in the same section of other types of PCD
452[Includes.IA32, Includes.IA32]
453[Includes, Includes.IA32] # common cannot be with other arch
454[Includes.IA32, PcdsFeatureFlag] # different section name
455'''     )
456
457    def tearDown(self):
458        self.File.Remove()
459
460    def testSectionHeader(self):
461        dec = Dec('test.dec', False)
462        # [no section start or end
463        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
464        self.assertRaises(FatalError, dec._SectionHeaderParser)
465
466        #[,] # empty sub-section
467        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
468        self.assertRaises(FatalError, dec._SectionHeaderParser)
469
470        # [unknow_section_name]
471        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
472        self.assertRaises(FatalError, dec._SectionHeaderParser)
473
474        # [Includes.IA32.other] # no third one
475        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
476        self.assertRaises(FatalError, dec._SectionHeaderParser)
477
478        # [PcdsFeatureFlag, PcdsFixedAtBuild]
479        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
480        self.assertRaises(FatalError, dec._SectionHeaderParser)
481
482        # [Includes.IA32, Includes.IA32]
483        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
484        dec._SectionHeaderParser()
485        self.assertEqual(len(dec._RawData.CurrentScope), 1)
486        self.assertEqual(dec._RawData.CurrentScope[0][0], 'Includes'.upper())
487        self.assertEqual(dec._RawData.CurrentScope[0][1], 'IA32')
488
489        # [Includes, Includes.IA32] # common cannot be with other arch
490        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
491        self.assertRaises(FatalError, dec._SectionHeaderParser)
492
493        # [Includes.IA32, PcdsFeatureFlag] # different section name not allowed
494        dec._RawData.CurrentLine = CleanString(dec._RawData.GetNextLine())[0]
495        self.assertRaises(FatalError, dec._SectionHeaderParser)
496
497#
498# Test Dec._ParseDecComment
499#
500class DecDecCommentTestCase(unittest.TestCase):
501    def testDecHeadComment(self):
502        File = TmpFile('test.dec')
503        File.Write(
504       '''# abc
505          ##''')
506        dec = Dec('test.dec', False)
507        dec.ParseDecComment()
508        self.assertEqual(len(dec._HeadComment), 2)
509        self.assertEqual(dec._HeadComment[0][0], '# abc')
510        self.assertEqual(dec._HeadComment[0][1], 1)
511        self.assertEqual(dec._HeadComment[1][0], '##')
512        self.assertEqual(dec._HeadComment[1][1], 2)
513        File.Remove()
514
515    def testNoDoubleComment(self):
516        File = TmpFile('test.dec')
517        File.Write(
518       '''# abc
519          #
520          [section_start]''')
521        dec = Dec('test.dec', False)
522        dec.ParseDecComment()
523        self.assertEqual(len(dec._HeadComment), 2)
524        self.assertEqual(dec._HeadComment[0][0], '# abc')
525        self.assertEqual(dec._HeadComment[0][1], 1)
526        self.assertEqual(dec._HeadComment[1][0], '#')
527        self.assertEqual(dec._HeadComment[1][1], 2)
528        File.Remove()
529
530if __name__ == '__main__':
531    import Logger.Logger
532    Logger.Logger.Initialize()
533    unittest.main()
534
535