mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-24 00:47:57 -05:00
instead of adding an extra CMakeLists in .ci/travis/code_layout to build API doc, astyle and run tests (indentation, spelling, sip, doc coverage), the top CMakeLists has been adapted to allow not building core libraries and possibly just the static code layout * astyle has been moved from /src/astyle to /lib/astyle (I would propose to move all external libraries, and possibly add git submodules)
127 lines
5.0 KiB
Python
127 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""QGIS Unit tests for SIP binding coverage.
|
|
|
|
.. note:: This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
"""
|
|
__author__ = 'Nyall Dawson'
|
|
__date__ = '15/10/2015'
|
|
__copyright__ = 'Copyright 2015, The QGIS Project'
|
|
# This will get replaced with a git SHA1 when you do a git archive
|
|
__revision__ = '$Format:%H$'
|
|
|
|
import os
|
|
from qgis.testing import unittest
|
|
|
|
from utilities import printImportant
|
|
from doxygen_parser import DoxygenParser
|
|
|
|
from termcolor import colored
|
|
|
|
# Import all the things!
|
|
from qgis.analysis import * # NOQA
|
|
from qgis.core import * # NOQA
|
|
from qgis.gui import * # NOQA
|
|
try:
|
|
from qgis.server import * # NOQA
|
|
except:
|
|
pass
|
|
|
|
|
|
class TestQgsSipCoverage(unittest.TestCase):
|
|
|
|
def testCoverage(self):
|
|
print('CTEST_FULL_OUTPUT')
|
|
prefixPath = os.environ['QGIS_PREFIX_PATH']
|
|
docPath = os.path.join(prefixPath, '..', 'doc', 'api', 'xml')
|
|
parser = DoxygenParser(docPath)
|
|
|
|
# first look for objects without any bindings
|
|
objects = set([m[0] for m in parser.bindable_members])
|
|
missing_objects = []
|
|
bound_objects = {}
|
|
for o in objects:
|
|
try:
|
|
if '::' in o:
|
|
bound_objects[o] = getattr(globals()[o.split('::')[0]], o.split('::')[1])
|
|
else:
|
|
bound_objects[o] = globals()[o]
|
|
except:
|
|
missing_objects.append(o)
|
|
|
|
missing_objects.sort()
|
|
|
|
# next check for individual members
|
|
parser.bindable_members.sort()
|
|
missing_members = []
|
|
for m in parser.bindable_members:
|
|
if m[0] in bound_objects:
|
|
obj = bound_objects[m[0]]
|
|
if "::" in m[0] and m[0].split("::")[1] == m[1]:
|
|
# skip constructors of nested classes
|
|
continue
|
|
|
|
# try two different methods of checking for member existence
|
|
try:
|
|
if hasattr(obj, m[1]):
|
|
continue
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
if m[1] in dir(obj):
|
|
continue
|
|
except:
|
|
printImportant("SIP coverage test: something strange happened in {}.{}, obj={}".format(m[0], m[1], obj))
|
|
|
|
missing_members.append('{}.{}'.format(m[0], m[1]))
|
|
|
|
missing_members.sort()
|
|
|
|
if missing_objects:
|
|
print("---------------------------------")
|
|
print((colored('Missing classes:', 'yellow')))
|
|
print((' ' + '\n '.join([colored(obj, 'yellow', attrs=['bold']) for obj in missing_objects])))
|
|
if missing_members:
|
|
print("---------------------------------")
|
|
print((colored('Missing members:', 'yellow')))
|
|
print((' ' + '\n '.join([colored(mem, 'yellow', attrs=['bold']) for mem in missing_members])))
|
|
|
|
# print summaries
|
|
missing_class_count = len(missing_objects)
|
|
present_count = len(objects) - missing_class_count
|
|
coverage = 100.0 * present_count / len(objects)
|
|
|
|
print("---------------------------------")
|
|
printImportant("{} total bindable classes".format(len(objects)))
|
|
printImportant("{} total have bindings".format(present_count))
|
|
printImportant("Binding coverage by classes {}%".format(coverage))
|
|
printImportant("---------------------------------")
|
|
printImportant("{} classes missing bindings".format(missing_class_count))
|
|
print("---------------------------------")
|
|
|
|
missing_member_count = len(missing_members)
|
|
present_count = len(parser.bindable_members) - missing_member_count
|
|
coverage = 100.0 * present_count / len(parser.bindable_members)
|
|
|
|
print("---------------------------------")
|
|
printImportant("{} total bindable members".format(len(parser.bindable_members)))
|
|
printImportant("{} total have bindings".format(present_count))
|
|
printImportant("Binding coverage by members {}%".format(coverage))
|
|
printImportant("---------------------------------")
|
|
printImportant("{} members missing bindings".format(missing_member_count))
|
|
|
|
self.assertEqual(missing_class_count, 0, """\n\nFAIL: new unbound classes have been introduced, please add SIP bindings for these classes
|
|
If these classes are not suitable for the Python bindings, please add the Doxygen tag
|
|
"@note not available in Python bindings" to the CLASS Doxygen comments""")
|
|
|
|
self.assertEqual(missing_member_count, 0, """\n\nFAIL: new unbound members have been introduced, please add SIP bindings for these members
|
|
If these members are not suitable for the Python bindings, please add the Doxygen tag
|
|
"@note not available in Python bindings" to the MEMBER Doxygen comments""")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|