1# mode: run 2# tag: coverage,trace 3 4""" 5PYTHON -c "import shutil; shutil.copy('pkg/coverage_test_pyx.pyx', 'pkg/coverage_test_pyx.pxi')" 6PYTHON setup.py build_ext -i 7PYTHON coverage_test.py 8""" 9 10######## setup.py ######## 11 12from distutils.core import setup 13from Cython.Build import cythonize 14 15setup(ext_modules = cythonize([ 16 'coverage_test_*.py*', 17 'pkg/coverage_test_*.py*', 18 'Package2/CoverageTest_*.py*' 19])) 20 21 22######## .coveragerc ######## 23[run] 24plugins = Cython.Coverage 25 26 27######## pkg/__init__.py ######## 28 29######## pkg/coverage_test_py.py ######## 30# cython: linetrace=True 31# distutils: define_macros=CYTHON_TRACE=1 32 33def func1(a, b): 34 x = 1 # 5 35 c = func2(a) + b # 6 36 return x + c # 7 37 38 39def func2(a): 40 return a * 2 # 11 41 42 43######## pkg/coverage_test_pyx.pyx ######## 44# cython: linetrace=True 45# distutils: define_macros=CYTHON_TRACE=1 46 47def func1(int a, int b): 48 cdef int x = 1 # 5 49 c = func2(a) + b # 6 50 return x + c # 7 51 52 53def func2(int a): 54 return a * 2 # 11 55 56 57######## coverage_test_include_pyx.pyx ######## 58# cython: linetrace=True 59# distutils: define_macros=CYTHON_TRACE=1 60 61cdef int x = 5 # 4 62 63cdef int cfunc1(int x): # 6 64 return x * 3 # 7 65 66include "pkg/coverage_test_pyx.pxi" # 9 67 68def main_func(int x): # 11 69 return cfunc1(x) + func1(x, 4) + func2(x) # 12 70 71 72######## Package2/__init__.py ######## 73# Add MixedCase package and filenames to test if the files are found 74 75######## Package2/CoverageTest_py.py ######## 76# cython: linetrace=True 77# distutils: define_macros=CYTHON_TRACE=1 78 79def func1(a, b): 80 x = 1 # 5 81 c = func2(a) + b # 6 82 return x + c # 7 83 84 85def func2(a): 86 return a * 2 # 11 87 88 89######## Package2/CoverageTest_pyx.pyx ######## 90# cython: linetrace=True 91# distutils: define_macros=CYTHON_TRACE=1 92 93def func1(int a, int b): 94 cdef int x = 1 # 5 95 c = func2(a) + b # 6 96 return x + c # 7 97 98 99def func2(int a): 100 return a * 2 # 11 101 102 103######## coverage_test_include_pyx.pyx ######## 104# cython: linetrace=True 105# distutils: define_macros=CYTHON_TRACE=1 106 107cdef int x = 5 # 4 108 109cdef int cfunc1(int x): # 6 110 return x * 3 # 7 111 112include "pkg/coverage_test_pyx.pxi" # 9 113 114def main_func(int x): # 11 115 return cfunc1(x) + func1(x, 4) + func2(x) # 12 116 117 118######## coverage_test.py ######## 119 120import re 121import os.path 122try: 123 # io.StringIO in Py2.x cannot handle str ... 124 from StringIO import StringIO 125except ImportError: 126 from io import StringIO 127 128from coverage import coverage 129 130from pkg import coverage_test_py 131from pkg import coverage_test_pyx 132import coverage_test_include_pyx 133 134# test the MixedCase Files and packages 135from Package2 import CoverageTest_py 136from Package2 import CoverageTest_pyx 137 138for module in [coverage_test_py, coverage_test_pyx, coverage_test_include_pyx, 139 CoverageTest_py, CoverageTest_pyx]: 140 assert not any(module.__file__.endswith(ext) for ext in '.py .pyc .pyo .pyw .pyx .pxi'.split()), \ 141 module.__file__ 142 143 144def source_file_for(module): 145 module_name = module.__name__ 146 path, ext = os.path.splitext(module.__file__) 147 if ext == '.so': 148 # Linux/Unix/Mac extension module 149 platform_suffix = re.search(r'[.](?:cpython|pypy)-[0-9]+[-_a-z0-9]*$', path, re.I) 150 if platform_suffix: 151 path = path[:platform_suffix.start()] 152 elif ext == '.pyd': 153 # Windows extension module 154 platform_suffix = re.search(r'[.]cp[0-9]+-win[_a-z0-9]*$', path, re.I) 155 if platform_suffix: 156 path = path[:platform_suffix.start()] 157 source_filepath = path + '.' + module_name.rsplit('_', 1)[-1] 158 return source_filepath 159 160 161def run_coverage(module): 162 module_name = module.__name__ 163 module_path = module_name.replace('.', os.path.sep) + '.' + module_name.rsplit('_', 1)[-1] 164 165 cov = coverage() 166 cov.start() 167 assert module.func1(1, 2) == (1 * 2) + 2 + 1 168 assert module.func2(2) == 2 * 2 169 if '_include_' in module_name: 170 assert module.main_func(2) == (2 * 3) + ((2 * 2) + 4 + 1) + (2 * 2) 171 cov.stop() 172 173 out = StringIO() 174 cov.report(file=out) 175 #cov.report([module], file=out) 176 lines = out.getvalue().splitlines() 177 assert any(module_path in line for line in lines), "'%s' not found in coverage report:\n\n%s" % ( 178 module_path, out.getvalue()) 179 180 mod_file, exec_lines, excl_lines, missing_lines, _ = cov.analysis2(source_file_for(module)) 181 assert module_path in mod_file 182 183 if '_include_' in module_name: 184 executed = set(exec_lines) - set(missing_lines) 185 assert all(line in executed for line in [7, 12]), '%s / %s' % (exec_lines, missing_lines) 186 187 # rest of test if for include file 188 mod_file, exec_lines, excl_lines, missing_lines, _ = cov.analysis2( 189 os.path.join(os.path.dirname(module.__file__), "pkg", "coverage_test_pyx.pxi")) 190 191 executed = set(exec_lines) - set(missing_lines) 192 assert all(line in executed for line in [5, 6, 7, 11]), '%s / %s' % (exec_lines, missing_lines) 193 194 195if __name__ == '__main__': 196 run_coverage(coverage_test_py) 197 run_coverage(coverage_test_pyx) 198 run_coverage(coverage_test_include_pyx) 199 run_coverage(CoverageTest_py) 200 run_coverage(CoverageTest_pyx) 201