测试 numpy.i 类型映射#
介绍#
numpy.i 为SWIG接口文件编写测试
是一件令人头痛的事情。目前,支持 12 种不同的数据类型,每种数据类型有 74 种不同的参数签名,总共支持“开箱即用”的 888 种类型映射。反过来,每个类型映射可能需要多次单元测试,以便验证正确和不正确输入的预期行为。目前,这会导致在子目录中运行时执行 1,000 多个单独的单元测试
。make testnumpy/tools/swig
为了促进许多类似的单元测试,采用了一些高级编程技术,包括 C 和SWIG宏以及 Python 继承。本文档的目的是描述用于验证numpy.i
类型映射是否按预期工作的测试基础设施。
测试组织#
支持三个独立的测试框架,分别针对一维、二维和三维数组。对于一维数组,有两个 C++ 文件,一个头文件和一个源文件,名称为:
Vector.h
Vector.cxx
包含各种以一维数组作为函数参数的函数的原型和代码。文件:
Vector.i
是一个SWIG接口文件,它定义了一个 python 模块Vector
,该模块包装了函数,Vector.h同时利用类型映射来numpy.i正确处理 C 数组。
调用生成和
,并且还执行编译扩展模块
或并将Makefile其链接在一起的脚本,具体取决于平台。这个扩展模块和代理文件都放在该目录下的子目录中。swigVector.pyVector_wrap.cxxsetup.pyVector_wrap.cxx_Vector.so_Vector.dylibVector.pybuild
实际测试使用名为以下的 Python 脚本进行:
testVector.py
它使用标准 Python 库模块unittest,该模块对支持的每种数据类型定义的每个函数执行多项测试Vector.h。
二维数组的测试方式完全相同。上述描述适用,但用Matrix代替
Vector。对于三维测试,替换Tensor为
Vector。对于四维测试,替换SuperTensor
为Vector。对于平面就地阵列测试,请Flat
替换Vector.对于下面的描述,我们将引用
Vector测试,但相同的信息适用于Matrix、
Tensor和SuperTensor测试。
该命令将确保构建所有测试软件,然后运行所有三个测试脚本。make test
测试头文件#
Vector.h是一个 C++ 头文件,它定义了一个名为 的 C 宏,
TEST_FUNC_PROTOS该宏带有两个参数:TYPE,它是一个数据类型名称,例如; and ,它是相同数据类型的短名称,不带空格,例如。该宏定义了多个具有前缀的函数原型
,并且至少有一个参数为类型数组
。那些具有返回参数的函数会返回一个
值。unsigned intSNAMEuintSNAMETYPETYPE
TEST_FUNC_PROTOS然后针对以下支持的所有数据类型实现numpy.i:
signed char
unsigned char
short
unsigned short
int
unsigned int
long
unsigned long
long long
unsigned long long
float
double
测试源文件#
Vector.cxx是一个 C++ 源文件,它为 中指定的每个函数原型实现可编译代码Vector.h。它定义了一个 C 宏,该宏具有与 中TEST_FUNCS相同的参数和工作方式。
如上所述,对 12 种数据类型中的每一种进行了实现。TEST_FUNC_PROTOSVector.hTEST_FUNCS
测试 SWIG 接口文件#
Vector.i是一个定义 python 模块的
SWIGVector接口文件。它遵循numpy.i本章所述的使用约定。它定义了一个具有单个参数的SWIG宏
。它使用SWIG指令将提供的类型映射应用到 中找到的参数签名。然后针对 所支持的所有数据类型实现该宏
。然后,它使用 中的类型映射
来包装所有函数原型。%apply_numpy_typemapsTYPE%applyVector.hnumpy.i%include "Vector.h"Vector.hnumpy.i
测试 Python 脚本#
make用于构建测试扩展模块
后,testVector.py可以运行来执行测试。与用于unittest促进单元测试的其他脚本一样,
testVector.py定义一个继承自的类
unittest.TestCase:
class VectorTestCase(unittest.TestCase):
然而,这个类并不是直接运行的。相反,它充当其他几个 Python 类的基类,每个类都特定于一种特定的数据类型。该类VectorTestCase存储两个用于输入信息的字符串:
- self.typeStr
与 和
SNAME中使用的前缀 之一匹配的字符串。例如,。Vector.hVector.cxx"double"- 自我类型代码
一个短(通常是单字符)字符串,表示 numpy 中的数据类型并对应于
self.typeStr.例如,如果self.typeStr是"double",那么self.typeCode应该是"d"。
类定义的每个测试都会VectorTestCase通过访问模块的字典来提取它尝试测试的 python 函数Vector:
length = Vector.__dict__[self.typeStr + "Length"]
在双精度测试的情况下,这将返回 python function Vector.doubleLength。
然后,我们为每个支持的数据类型定义一个新的测试用例类,并带有简短的定义,例如:
class doubleTestCase(VectorTestCase):
def __init__(self, methodName="runTest"):
VectorTestCase.__init__(self, methodName)
self.typeStr = "double"
self.typeCode = "d"
这 12 个类中的每一个都被收集到一个 中unittest.TestSuite,然后执行。错误和失败会汇总在一起并作为退出参数返回。任何非零结果都表明至少有一项测试未通过。