之前在词法和语法分析部分都有测试,不过那些测试显得很小打小闹,而且比较麻烦。好在那都是不复杂的东西,测试负担较小。而符号表这东西是语义分析需要用到的基础结构,如果等到最后进行集成测试,出了bug还真不好找。所以这东西有必要单独拿来测试一下。不过C语言的测试驱动开发工具还真是难找,这里就山寨一个先。
测试数据这里简单给出4组
// 测试数据数目
#define NR_TEST_CASE (4)
// 测试数据的基地址
#define BASE_ADDR (1 << 3)
// 待测试的符号表指针
struct SymbolTable* table;
// 维度信息,等于0时结束
// 比如第一组数据,表示 i [2][3][4][5]
int DIM[NR_TEST_CASE][5] = {
{ 2, 3, 4, 5, 0 },
{ 2, 4, 0 },
{ 0 },
{ 2, 3, 4, 0 }
};
// 其它数据
struct {
char* ident; // 标识符
AcceptType type; // 类型
int nrDim; // 维度数
int* dims; // 每一维大小
int size; // 总大小
} data[NR_TEST_CASE] = {
{ "i", INTEGER },
{ "ij", INTEGER },
{ "j", REAL },
{ "k", REAL }
};
按照单元测试的规范,对于每个函数的测试不应该依赖于其它函数。所以每个测试应该独立地进行数据准备工作。这两个函数进行数据准备和测试结束后的清理
void prepare(void)
{
int i, j, size;
table = newSymbolTable(BASE_ADDR);
for (i = 0; i < NR_TEST_CASE; ++i ) {
// 填充数据中其它部分:总大小及每一维的大小
size = INTEGER == data[i].type ? INT_SIZE : REAL_SIZE;
data[i].dims = DIM[i];
for (j = 0; 0 != DIM[i][j]; ++j) {
size *= DIM[i][j];
}
data[i].nrDim = j;
data[i].size = size;
}
for (i = 0; i < NR_TEST_CASE; ++i) {
// 将符号注册进符号表,并顺带判断是否每次都成功
assert (SymTab_OK ==
regVar(table, data[i].ident, data[i].type, data[i].nrDim,
data[i].dims));
}
}
void clear(void)
{
finalizeSymbolTable(table);
showAlloc;
}
再就是为每个函数准备的测试,依次是
/* * 测试 regVar * 测试涵盖可能出现的错误,包括 SymTab_MultiDef 和 SymTab_SizeExceeded * 因为正确的变量注册在 prepare 中完成了,所以这里不测试 */ void testRegister(void); /* * 测试 getVarType * 测试涵盖正确的返回及 SymTab_NotDef 错误 */ void testVarType(void); /* * 测试 getVarAddr * 测试涵盖正确的返回及 SymTab_NotDef 错误 */ void testVarAddr(void); /* * 测试 getVarNrDim * 测试涵盖正确的返回及 SymTab_NotDef 错误 */ void testNrDim(void); /* * 测试 getVarDimSize * 测试过程中会根据数组大小计算出其单元偏移 * 测试涵盖正确的返回及 SymTab_NotDef 和 SymTab_ArrDimOutOfRange 错误 */ void testDimSize(void);
它们的具体实现如下
void testRegister(void)
{
prepare();
// totalSize: 总的内存使用量,判别在试图重复注册同名变量失败后,符号表内使用内存数是否不变
int i, totalSize = table->used;
for (i = 0; i < NR_TEST_CASE; ++i) {
// 重复注册在 prepare 中已经注册的数据
assert (SymTab_MultiDef ==
regVar(table, data[i].ident, data[i].type, data[i].nrDim,
data[i].dims));
}
assert (totalSize == table->used);
// 内存超出最大限度,试图注册该变量
int exceed = MAX_VAR_IN_STACK - BASE_ADDR;
int exceedDim[1] = { exceed };
assert (SymTab_SizeExceeded
== regVar(table, "non-exist", INTEGER, 1, exceedDim));
clear();
puts(" -> Register test done.\n");
}
void testVarType(void)
{
prepare();
int i;
AcceptType type; // 变量类型,其地址传入函数以存放返回值
for (i = 0; i < NR_TEST_CASE; ++i) {
assert (SymTab_OK == getVarType(table, data[i].ident, &type));
assert (data[i].type == type);
}
assert (SymTab_NotDef == getVarType(table, "non-exist", &type));
clear();
puts(" -> Type getter test done.\n");
}
void testVarAddr(void)
{
prepare();
// addr: 变量地址,其地址传入函数以存放返回值
// accumulator: 地址积累量,也就是期望的变量地址
int i, addr, accumulator = BASE_ADDR;
for (i = 0; i < NR_TEST_CASE; ++i) {
assert (SymTab_OK == getVarAddr(table, data[i].ident, &addr));
assert (addr == accumulator);
accumulator += data[i].size; // 调整到下一变量的期望地址
}
assert (accumulator - BASE_ADDR == table->used);
assert (SymTab_NotDef == getVarAddr(table, "non-exist", &addr));
clear();
puts(" -> Address getter test done.\n");
}
void testNrDim(void)
{
prepare();
// nrDim: 维度数目,其地址传入函数以存放返回值
int i, nrDim;
for (i = 0; i < NR_TEST_CASE; ++i) {
assert (SymTab_OK == getVarNrDim(table, data[i].ident, &nrDim));
assert (data[i].nrDim == nrDim);
}
assert (SymTab_NotDef == getVarNrDim(table, "non-exist", &nrDim));
clear();
puts(" -> Dimension number getter test done.\n");
}
void testDimSize(void)
{
prepare();
// dimSize: 维度大小,其地址传入函数以存放返回值
// expected: 期望维度大小,计算得出
int i, j, dimSize, expected;
for (i = 0; i < NR_TEST_CASE; ++i) {
// 越界错误
assert (SymTab_ArrDimOutOfRange
== getVarDimSize(table, data[i].ident, &dimSize, -1));
expected = INTEGER == data[i].type ? INT_SIZE : REAL_SIZE;
for (j = 0; j < data[i].nrDim; ++j) {
assert(SymTab_OK
== getVarDimSize(table, data[i].ident, &dimSize, j));
assert(expected == dimSize);
expected *= DIM[i][j];
}
assert (expected == data[i].size);
// 越界错误
assert (SymTab_ArrDimOutOfRange
== getVarDimSize(table, data[i].ident, &dimSize, j));
}
assert (SymTab_NotDef == getVarDimSize(table, "non-exist", &dimSize, 0));
clear();
puts(" -> Dimension size getter test done.\n");
}
最后是文件中其它的散件及main函数
#include<stdio.h>
#include<assert.h>
#define _DEBUG_MODE
#include"symbol-table.h"
int main(void)
{
testRegister();
testVarType();
testVarAddr();
testNrDim();
testDimSize();
puts(":-) All test done.");
return 0;
}
1600

被折叠的 条评论
为什么被折叠?



