File indexing completed on 2024-12-08 04:20:21
0001 # -*- coding: utf-8 -*- 0002 # Copyright 2008-9 Simon Edwards <simon@simonzone.com> 0003 # 0004 # This program is free software; you can redistribute it and/or modify 0005 # it under the terms of the GNU General Public License as published by 0006 # the Free Software Foundation; either version 2 of the License, or 0007 # (at your option) any later version. 0008 # 0009 # This program is distributed in the hope that it will be useful, 0010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 # GNU General Public License for more details. 0013 # 0014 # You should have received a copy of the GNU General Public License 0015 # along with this program; if not, write to the 0016 # Free Software Foundation, Inc., 0017 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 0019 # 0020 # Unit tests for the .sip file parser. 0021 # 0022 import unittest 0023 import sipparser 0024 import sipsymboldata 0025 import os 0026 import os.path 0027 import subprocess 0028 import re 0029 0030 def CleanWhitespace(code): 0031 return re.sub(r"\s+"," ",code).strip() 0032 0033 class TestSipParser(unittest.TestCase): 0034 def setUp(self): 0035 self.parser = sipparser.SipParser() 0036 self.syms = sipsymboldata.SymbolData() 0037 0038 def mirrorTest(self,code,debugLevel=0): 0039 scope = self.parser.parse(self.syms, code, debugLevel=debugLevel); 0040 new_code = scope.format() 0041 if CleanWhitespace(new_code)!=CleanWhitespace(code): 0042 self.fail("Output code doesn't match input code.\n---- Original:\n" + code + "\n---- Result:\n" + new_code) 0043 0044 def ioTest(self,incode,outcode,debugLevel=0): 0045 scope = self.parser.parse(self.syms, incode, debugLevel=debugLevel); 0046 new_code = scope.format() 0047 if CleanWhitespace(new_code)!=CleanWhitespace(outcode): 0048 self.fail("Output code doesn't match expected output code.\n---- Expected:\n" + outcode + "\n---- Result:\n" + new_code) 0049 0050 def strictMirrorTest(self,code,debugLevel=0): 0051 scope = self.parser.parse(self.syms, code, debugLevel=debugLevel); 0052 new_code = scope.format() 0053 if new_code!=code: 0054 self.fail("Output code doesn't match input code.\n---- Original:\n" + code + "\n---- Result:\n" + new_code) 0055 0056 def simpleParseTest(self,code,debugLevel=0): 0057 self.parser.parse(self.syms, code, debugLevel=debugLevel); 0058 0059 def testClass0(self): 0060 self.mirrorTest( 0061 """ 0062 class Foo { 0063 }; 0064 """) 0065 0066 def testClass1(self): 0067 self.mirrorTest( 0068 """ 0069 class Foo { 0070 Foo (); 0071 }; 0072 """) 0073 0074 def testClass3(self): 0075 self.mirrorTest( 0076 """ 0077 class Foo : Bar { 0078 };""") 0079 0080 def testClass5(self): 0081 self.mirrorTest( 0082 """ 0083 class Foo : Bar, Zyzz { 0084 };""") 0085 0086 def testClass6(self): 0087 self.mirrorTest( 0088 """ 0089 class Foo /Abstract/ { 0090 }; 0091 """) 0092 0093 def testClass7(self): 0094 self.mirrorTest( 0095 """ 0096 class Foo { 0097 Foo (int x); 0098 public: 0099 Foo (); 0100 }; 0101 """) 0102 def testClass8(self): 0103 self.mirrorTest( 0104 """ 0105 class ServiceBase : KShared { 0106 ServiceBase (ServiceBasePrivate*const d); 0107 }; 0108 """) 0109 0110 def testOpaqueClass(self): 0111 self.mirrorTest( 0112 """ 0113 class OpaqueFoo; 0114 """) 0115 0116 def testClassVariable(self): 0117 self.mirrorTest( 0118 """ 0119 class Foo { 0120 public: 0121 int public_x; 0122 private: 0123 int private_y; 0124 protected: 0125 int protected_z; 0126 };""") 0127 0128 def testClassVariable2(self): 0129 self.mirrorTest( 0130 """ 0131 class Foo { 0132 public: 0133 int x = 0; 0134 };""") 0135 0136 def testClassVariable3(self): 0137 self.mirrorTest( 0138 """ 0139 class Foo { 0140 static int x; 0141 const int y; 0142 };""") 0143 0144 def testClassConstructor2(self): 0145 self.mirrorTest( 0146 """ 0147 class Foo { 0148 Foo (int x, int y); 0149 };""") 0150 0151 def testClassConstructor3(self): 0152 self.mirrorTest( 0153 """ 0154 class Foo { 0155 explicit Foo (int x); 0156 };""") 0157 0158 def testClassDestructor1(self): 0159 self.mirrorTest( 0160 """ 0161 class Foo { 0162 ~Foo (); 0163 };""") 0164 0165 def testClassMethod(self): 0166 self.mirrorTest( 0167 """ 0168 class Foo { 0169 int getFooValue (int x); 0170 };""") 0171 0172 def testClassVirtualMethod(self): 0173 self.mirrorTest( 0174 """ 0175 class Foo { 0176 virtual int getFooValue (int x); 0177 };""") 0178 0179 def testClassPureVirtualMethod(self): 0180 self.mirrorTest( 0181 """ 0182 class Foo { 0183 virtual int getFooValue (int x)=0; 0184 };""") 0185 0186 def testFunctions(self): 0187 self.mirrorTest( 0188 """ 0189 int DoFoo (int x); 0190 void StopFoo (); 0191 """) 0192 0193 def testFunctions2(self): 0194 self.mirrorTest( 0195 """ 0196 const int* DoFoo (int x); 0197 """) 0198 0199 def testFunctions3(self): 0200 self.mirrorTest( 0201 """ 0202 QString& FooConst () const; 0203 """) 0204 0205 def testFunctions4(self): 0206 self.mirrorTest( 0207 """ 0208 void Foo (unsigned long x); 0209 """) 0210 0211 def testFunctions5(self): 0212 self.mirrorTest( 0213 """ 0214 void Foo (long x [5]); 0215 """) 0216 0217 def testFunctions6(self): 0218 self.mirrorTest( 0219 """ 0220 void* foo (int, double (*doublePtr)(float,QString*)); 0221 """) 0222 0223 def testFunctions7(self): 0224 self.mirrorTest( 0225 """ 0226 int DoFoo (int* x /Out/); 0227 """) 0228 0229 def testFunctions9(self): 0230 self.mirrorTest( 0231 """ 0232 KConfigGroup group (const QByteArray& group); 0233 const KConfigGroup group (const QByteArray& group); 0234 const KConfigGroup group (const QByteArray& group) const; 0235 """) 0236 0237 def testFunctions10(self): 0238 self.mirrorTest( 0239 """ 0240 TermPrivate QSharedDataPointer<Nepomuk::Query::TermPrivate>::clone (); 0241 """) 0242 0243 def testAccess(self): 0244 self.mirrorTest( 0245 """void PlainPreFunc (); 0246 class Foo { 0247 public: 0248 class Bar { 0249 void privateBar (); 0250 }; 0251 void publicFoo (); 0252 }; 0253 void PlainPostFunc (); 0254 """) 0255 0256 0257 def testFunctionIgnore(self): 0258 self.mirrorTest( 0259 """ 0260 void DontIgnoreThisFoo (); 0261 //ig int DoIgnoreMeFoo (int x); 0262 void DontIgnoreThisFoo2 (); 0263 """) 0264 0265 def testOpaqueClassIgnore(self): 0266 self.mirrorTest( 0267 """ 0268 //ig class Foo; 0269 """) 0270 0271 def testTypedefIgnore(self): 0272 self.mirrorTest( 0273 """ 0274 //ig typedef QList<KProtocolInfo::Ptr> List; 0275 static QStringList protocols (); 0276 """) 0277 0278 def testTypedefIgnore2(self): 0279 self.mirrorTest(""" 0280 class KLibrary : QLibrary 0281 { 0282 public: 0283 //ig typedef void (*void_function_ptr)(); 0284 }; 0285 """) 0286 0287 def testOperator1(self): 0288 self.mirrorTest( 0289 """ 0290 class Foo { 0291 bool operator == (int); 0292 }; 0293 """) 0294 0295 def testOperator2(self): 0296 self.mirrorTest( 0297 """ 0298 class Foo { 0299 virtual bool operator == (int); 0300 }; 0301 """) 0302 0303 def testOperator3(self): 0304 self.mirrorTest( 0305 """ 0306 class Foo { 0307 QVariant operator QVariant (); 0308 }; 0309 """,debugLevel=0) 0310 0311 def testNamespace(self): 0312 self.mirrorTest( 0313 """ 0314 namespace FooSpace { 0315 int DoFoo (int x); 0316 void StopFoo (); 0317 }; 0318 """) 0319 0320 def testEnum(self): 0321 self.mirrorTest( 0322 """ 0323 enum global { 0324 earth, 0325 orb, 0326 globe 0327 }; 0328 """) 0329 0330 def testEnum2(self): 0331 self.mirrorTest( 0332 """ 0333 enum global { 0334 earth, 0335 orb, 0336 globe, 0337 0338 universe 0339 }; 0340 """) 0341 0342 def testEnum3(self): 0343 self.mirrorTest( 0344 """ 0345 enum global { 0346 0347 // just a comment. 0348 earth, 0349 orb, 0350 0351 // Wierd stuff. 0352 globe, 0353 universe 0354 0355 // le fin 0356 }; 0357 """) 0358 0359 def testEnumAnonymous(self): 0360 self.mirrorTest( 0361 """ 0362 enum { 0363 earth, 0364 orb, 0365 globe 0366 }; 0367 """) 0368 0369 def testEnumSipIf(self): 0370 self.ioTest( 0371 """ 0372 enum { 0373 earth, 0374 // This is a comment 0375 %If (FOO -) 0376 orb, 0377 %End 0378 globe 0379 }; 0380 """,""" 0381 enum { 0382 earth, 0383 // This is a comment 0384 orb, 0385 globe 0386 }; 0387 """,debugLevel=0) 0388 0389 def testTypedef1(self): 0390 self.mirrorTest( 0391 """ 0392 typedef QString& stringref; 0393 """) 0394 0395 def testTypedef2(self): 0396 self.mirrorTest( 0397 """typedef QObject** objPtrPtr; 0398 """) 0399 0400 def testTypedef3(self): 0401 self.mirrorTest( 0402 """ 0403 typedef QFlags<KCrash::CrashFlag> CrashFlags; 0404 """) 0405 0406 def testTypedef4(self): 0407 self.mirrorTest( 0408 """ 0409 //ig typedef foo bar; 0410 """) 0411 0412 def testTypedef5(self): 0413 self.mirrorTest(""" 0414 //ig typedef void (*KdeCleanUpFunction)(); 0415 """) 0416 0417 def testSipDirective1(self): 0418 self.mirrorTest( 0419 """ 0420 class Foo { 0421 %TypeHeaderCode 0422 #include <kconfigbase.h> 0423 %End 0424 }; 0425 """) 0426 0427 def testMethodCode1(self): 0428 self.mirrorTest( 0429 """ 0430 int DoFoo (int x); 0431 %MethodCode 0432 // Method code is here. 0433 0434 // Ends here. 0435 %End 0436 """) 0437 0438 def testTemplate(self): 0439 self.mirrorTest( 0440 """ 0441 QList<int> intlist; 0442 """) 0443 0444 def testLineComment1(self): 0445 self.mirrorTest( 0446 """ 0447 // Just a line comment. 0448 """) 0449 0450 def testLineComment2(self): 0451 self.mirrorTest( 0452 """ 0453 /* Just a C comment. */ 0454 """) 0455 0456 def testBlankLine(self): 0457 self.mirrorTest( 0458 """ 0459 // Start, then blank 0460 0461 // End 0462 """) 0463 0464 def testBlankLine2(self): 0465 self.mirrorTest( 0466 """ 0467 class Foo { 0468 %ConvertToSubClassCode 0469 0470 // Subcode... 0471 // End. 0472 %End 0473 }; 0474 """) 0475 0476 def testTemplate(self): 0477 self.mirrorTest( 0478 """ 0479 template <Bar> 0480 class Foo { 0481 public: 0482 static QString deref (Bar i); 0483 }; 0484 """) 0485 0486 def testMappedType(self): 0487 self.mirrorTest( 0488 """ 0489 %MappedType QMap<Foo,Bar> 0490 { 0491 0492 }; 0493 0494 """) 0495 0496 def testMappedType2(self): 0497 self.mirrorTest( 0498 """ 0499 template <TYPE1,TYPE2> 0500 %MappedType QMap<TYPE1,TYPE2> 0501 { 0502 0503 }; 0504 0505 class Foo { 0506 0507 }; 0508 """) 0509 0510 def testMappedType3(self): 0511 0512 self.mirrorTest( 0513 """ 0514 %MappedType QChar /API=QString:2 - / 0515 { 0516 // Foo 0517 }; 0518 """,debugLevel=0) 0519 0520 def testNestedTemplate(self): 0521 self.mirrorTest( 0522 """ 0523 KBookmarkGroup addBookmarks (const QList<QPair<QString,QString>>& list); 0524 """) 0525 0526 def testCppSigs1(self): 0527 self.mirrorTest(""" 0528 class Foo { 0529 ItemDouble (const QString& _group, const QString& _key, double reference, double defaultValue = 0) [(const QString& _group, const QString& _key, double& reference, double defaultValue = 0)]; 0530 }; 0531 """) 0532 0533 def testCppSigs2(self): 0534 self.mirrorTest(""" 0535 class Foo { 0536 int itemDouble (const QString& _group, const QString& _key, double reference, double defaultValue = 0) [int (const QString& _group, const QString& _key, double& reference, double defaultValue = 0)]; 0537 }; 0538 """) 0539 def testCppSigs3(self): 0540 self.mirrorTest(""" 0541 class Foo 0542 { 0543 virtual SIP_PYOBJECT read (qint64 maxlen) /ReleaseGIL/ [qint64 (char* data, qint64 maxlen)]; 0544 %MethodCode 0545 // foo. 0546 %End 0547 }; 0548 """) 0549 0550 def testForce(self): 0551 self.mirrorTest(""" 0552 class Foo { 0553 public: 0554 Foo (); 0555 int bar (); 0556 //force 0557 int forceBar (); 0558 //end 0559 }; 0560 """) 0561 0562 def testForce2(self): 0563 self.mirrorTest(""" 0564 namespace Foo { 0565 int bar (); 0566 //force 0567 int forceBar (); 0568 //end 0569 int bar2 (); 0570 }; 0571 """) 0572 0573 def testArrowDefaults(self): 0574 self.mirrorTest(""" 0575 class Foo 0576 { 0577 QString label (const QString& language = KGlobal::locale()->language()); 0578 }; 0579 """) 0580 0581 def testCTSCC(self): 0582 self.mirrorTest(""" 0583 class Foo { 0584 //force 0585 %ConvertToSubClassCode 0586 // Custom %ConvertToSubClassCode 0587 %End 0588 //end 0589 }; 0590 """) 0591 0592 def testTemplateBlocks(self): 0593 text =""" 0594 // 0595 0596 %ModuleHeaderCode 0597 #include <kaccelgen.h> 0598 %End 0599 0600 namespace KAccelGen 0601 { 0602 0603 template <Iter> 0604 class Deref 0605 { 0606 %TypeHeaderCode 0607 #include <kaccelgen.h> 0608 %End 0609 0610 0611 public: 0612 static QString deref (Iter i); 0613 }; 0614 // Deref 0615 0616 0617 template <Iter> 0618 class Deref_Key 0619 { 0620 %TypeHeaderCode 0621 #include <kaccelgen.h> 0622 %End 0623 0624 0625 public: 0626 static QString deref (Iter i); 0627 }; 0628 // Deref_Key 0629 0630 bool isLegalAccelerator (const QString& str, int index); 0631 void generate (const QStringList& source, QStringList& target); 0632 }; 0633 // KAccelGen 0634 0635 %ModuleHeaderCode 0636 #include <kaccelgen.h> 0637 %End 0638 """ 0639 0640 self.mirrorTest(text) 0641 0642 # scope = self.parser.parse(self.syms, text, debugLevel=0); 0643 # for item in scope[5]: 0644 # print(repr(item)) 0645 # print("-----------------------------" + item.format()) 0646 0647 0648 def testStrict0(self): 0649 self.strictMirrorTest( 0650 """// Foo 0651 0652 // bar 0653 0654 %ModuleHeaderCode 0655 //ctscc 0656 dsfd 0657 %End 0658 0659 0660 class KUrl : QUrl 0661 { 0662 }; 0663 """) 0664 0665 def testSuperClassQueries(self): 0666 scope = self.parser.parse(self.syms, """ 0667 class Bar {}; 0668 class Zyzz : Bar {}; 0669 class Foo : Zyzz { 0670 0671 }; 0672 """) 0673 bar = self.syms.lookupType("Bar",scope) 0674 self.assertTrue(bar is not None) 0675 self.assertTrue(bar.allSuperClassNames() is not None) 0676 self.assertTrue(len(bar.allSuperClassNames())==0) 0677 foo = self.syms.lookupType("Foo",scope) 0678 self.assertTrue(foo is not None) 0679 fooBases = foo.allSuperClassNames() 0680 self.assertTrue(fooBases is not None) 0681 self.assertTrue(len(fooBases)==2) 0682 0683 def testSipStmt(self): 0684 scope = self.parser.parse(self.syms, """ 0685 template<TYPE1, TYPE2> 0686 %MappedType QHash<TYPE1, TYPE2> /DocType="dict-of-TYPE1-TYPE2"/ 0687 { 0688 0689 }; 0690 0691 """,debugLevel=0) 0692 0693 def testModule(self): 0694 self.mirrorTest(""" 0695 %Module PyKDE4.kdecore 0696 """) 0697 0698 def testModule2(self): 0699 self.mirrorTest(""" 0700 %Module(name=PyQt4.QtCore, keyword_arguments="Optional") 0701 0702 %Timeline {Qt_4_1_1 Qt_4_1_2}""") 0703 0704 def testAPI(self): 0705 self.simpleParseTest(""" 0706 %API(name=QDate, version=2) 0707 """) 0708 0709 def testInclude(self): 0710 self.simpleParseTest(""" 0711 %Include(name=staticplugins.sip, optional=True) 0712 """) 0713 0714 def testGetter(self): 0715 # This just has to go through the parser. PyKDE doesn't need the info which is read in. 0716 self.simpleParseTest(""" 0717 class Foo { 0718 public: 0719 static const QMetaObject staticMetaObject { 0720 %GetCode 0721 sipPy = qpycore_qobject_staticmetaobject(sipPyType); 0722 %End 0723 }; 0724 }; 0725 """) 0726 0727 def testQListSubclass(self): 0728 self.simpleParseTest(""" 0729 class AddresseeList : QList<Addressee> 0730 { 0731 }; 0732 """) 0733 0734 def testEnumAnnotation(self): 0735 self.simpleParseTest("""enum Command 0736 { 0737 None /PyName=None_/, 0738 SetTransferMode, 0739 SetProxy, 0740 ConnectToHost 0741 }; 0742 """) 0743 0744 0745 0746 def xtestQtCoremod(self): 0747 with open("/usr/share/sip/PyQt4/QtCore/QtCoremod.sip") as fhandle: 0748 text = fhandle.read() 0749 scope = self.parser.parse(self.syms, text) 0750 print(scope.format()) 0751 0752 def xtestFullCompare(self): 0753 sipdir = "/home/sbe/devel/svn/kde/branches/KDE/4.4/kdebindings/python/pykde4/sip/kdeui/" 0754 #sipdir = "/usr/share/sip/PyQt4/QtGui/" 0755 for filename in os.listdir(sipdir): 0756 print(filename) 0757 if filename.endswith(".sip"): 0758 filepath = os.path.join(sipdir,filename) 0759 with open(filepath) as fhandle: 0760 text = fhandle.read() 0761 self.syms = sipsymboldata.SymbolData() 0762 scope = self.parser.parse(self.syms, text) 0763 0764 output = scope.format() 0765 if CleanWhitespace(text)!=CleanWhitespace(output): 0766 with open(filename+".v2",'w') as outhandle: 0767 outhandle.write(scope.format()) 0768 subprocess.call(['diff','-durb',filepath,filename+".v2"]) 0769 0770 # self.parser = sipparser.SipParser() 0771 0772 # def parse(self,text): 0773 # self.parser.parse(self.symbol_data, self.state_info, text,2 if debug else 1) 0774 ''' 0775 def testEmpty(self): 0776 self.parse("") 0777 0778 def testCComments(self): 0779 self.parse(""" 0780 0781 0782 /* A C style comment */ 0783 0784 /* 0785 Multiline 0786 */ 0787 0788 0789 // single 0790 /* 0791 muliple 0792 */ 0793 """) 0794 0795 def testMappedTypeConstType(self): 0796 self.parse(""" 0797 %MappedType QList<const Soprano::Backend*> 0798 { 0799 %TypeHeaderCode 0800 #include <qlist.h> 0801 %End 0802 0803 %ConvertFromTypeCode 0804 // Create the list. 0805 %End 0806 0807 %ConvertToTypeCode 0808 // Check the type if that is all that is required. 0809 0810 %End 0811 }; 0812 0813 """) 0814 0815 ''' 0816 if __name__ == '__main__': 0817 unittest.main()