2015-10-15 18:31:17 +11:00
# -*- 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 utilities import ( TestCase ,
unittest ,
printImportant ,
DoxygenParser )
from PyQt4 . QtCore import qDebug
2015-12-11 00:06:51 +01:00
# Import all the things!
2015-10-15 18:31:17 +11:00
from qgis . analysis import *
from qgis . core import *
from qgis . gui import *
from qgis . networkanalysis import *
try :
from qgis . server import *
except :
pass
# BINDING THRESHOLD
#
# The minimum number of unbound functions in QGIS api
#
# DON'T RAISE THIS THRESHOLD!!!
# (changes which lower this threshold are welcomed though!)
2015-12-17 13:03:17 +01:00
ACCEPTABLE_MISSING_CLASSES = 69
2015-12-13 14:17:41 +11:00
ACCEPTABLE_MISSING_MEMBERS = 264
2015-10-15 18:31:17 +11:00
class TestQgsSipCoverage ( 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 )
2015-12-11 00:06:51 +01:00
# first look for objects without any bindings
2015-10-15 18:31:17 +11:00
objects = set ( [ m [ 0 ] for m in parser . bindable_members ] )
missing_objects = [ ]
bound_objects = { }
for o in objects :
try :
2015-11-09 21:29:50 +11:00
if ' :: ' in o :
bound_objects [ o ] = getattr ( globals ( ) [ o . split ( ' :: ' ) [ 0 ] ] , o . split ( ' :: ' ) [ 1 ] )
else :
bound_objects [ o ] = globals ( ) [ o ]
2015-10-15 18:31:17 +11:00
except :
missing_objects . append ( o )
missing_objects . sort ( )
2015-12-11 00:06:51 +01:00
# next check for individual members
2015-10-15 18:31:17 +11:00
parser . bindable_members . sort ( )
missing_members = [ ]
for m in parser . bindable_members :
if m [ 0 ] in bound_objects :
obj = bound_objects [ m [ 0 ] ]
2015-11-09 21:29:50 +11:00
2015-12-11 00:06:51 +01:00
# try two different methods of checking for member existence
2015-11-09 21:29:50 +11:00
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 ] ) )
2015-10-15 18:31:17 +11:00
missing_members . sort ( )
2015-11-09 21:28:23 +11:00
print " --------------------------------- "
print ' Missing classes: \n {} ' . format ( ' \n ' . join ( missing_objects ) )
print " --------------------------------- "
print ' Missing members: \n {} ' . format ( ' \n ' . join ( missing_members ) )
2015-12-11 00:06:51 +01:00
# print summaries
2015-11-09 21:28:23 +11:00
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, out of {} allowed " . format ( missing_class_count , ACCEPTABLE_MISSING_CLASSES ) )
print " --------------------------------- "
missing_member_count = len ( missing_members )
present_count = len ( parser . bindable_members ) - missing_member_count
2015-10-15 18:31:17 +11:00
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 ( " --------------------------------- " )
2015-11-09 21:28:23 +11:00
printImportant ( " {} members missing bindings, out of {} allowed " . format ( missing_member_count , ACCEPTABLE_MISSING_MEMBERS ) )
assert missing_class_count < = ACCEPTABLE_MISSING_CLASSES , """ \n \n FAIL: 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 """
2015-10-15 18:31:17 +11:00
2015-11-09 21:28:23 +11:00
assert missing_member_count < = ACCEPTABLE_MISSING_MEMBERS , """ \n \n FAIL: new unbound members have been introduced, please add SIP bindings for these members
2015-10-15 18:31:17 +11:00
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__ ' :
2015-11-08 19:18:00 +00:00
if " MISSING_SIP_CLASSES " in os . environ :
2015-11-09 09:13:10 +11:00
ACCEPTABLE_MISSING_CLASSES + = int ( os . environ [ ' MISSING_SIP_CLASSES ' ] )
2015-11-08 19:18:00 +00:00
if " MISSING_SIP_MEMBERS " in os . environ :
2015-11-09 09:13:10 +11:00
ACCEPTABLE_MISSING_MEMBERS + = int ( os . environ [ ' MISSING_SIP_MEMBERS ' ] )
2015-11-08 19:18:00 +00:00
2015-10-15 18:31:17 +11:00
unittest . main ( )