2011-12-06 96 views
6

我喜欢GNU链接器的功能来包装很多功能。我通常使用它模拟例如像rand()这样的非确定性函数调用。看看下面的例子,我想编写giveMeANumber单元测试:用GNU链接器包装C++函数

//number.cpp 
int giveMeANumber() { 
    return rand() % 6 + 1; 
} 

我可以换调用兰德与GNU链接功能包装是这样的:

//test.cpp 
extern "C" int __wrap_rand(void) { 
return 4; 
} 

void unitTest() { 
    assert giveMeANumber() == 5; 
} 

$ g++ test.cpp -o test number.o -Xlinker --wrap=rand 

有什么办法使用正常的C++函数做同样的事情?以下是行不通的,我猜这是因为名字混乱。但即使当我尝试使用损坏的名称,它也不起作用。

//number.cpp 
int foo() { 
    //some complex calculations I would like to mock 
} 
int giveMeANumber() { 
    return foo() % 6 + 1; 
} 

//test.cpp 
extern "C" int __wrap_foo(void) { 
return 4; 
} 

$ g++ test.cpp -o test number.o -Xlinker --wrap=foo 

任何想法?

+0

实际上,rand是一个确定性函数。它返回一个伪随机数字序列。调用rand将返回与srand一起使用的任何给定种子的相同数字序列。 – TJD

+1

好的,布拉沃,这是真的。但为了保持这个例子简短易读,我没有使用种子。 – Mike

+0

您需要将'__wrap_foo'重命名为'getRandomNumber'。 (http://xkcd.com/221/) –

回答

8

你需要或者也extern "C"要换行(如果可能的话),或者你需要用错位名称的功能,例如,__wrap__Z3foov再通--wrap=_Z3foov给连接器。

正确获取下划线有点棘手。这适用于我:

$ cat x.cc 
#include <iostream> 
using namespace std; 

int giveMeANumber(); 

int main() { 
    cerr << giveMeANumber() << endl; 
    return 0; 
} 

$ cat y.cc 
int giveMeANumber() { 
    return 0; 
} 

extern "C" int __wrap__Z13giveMeANumberv() { 
    return 10; 
} 

$ g++ -c x.cc y.cc && g++ x.o y.o -Wl,--wrap=_Z13giveMeANumberv && ./a.out 
10 
+0

要包装的C链接C++函数不是一个选项,因为此函数可能被重载,应该仍然可以从其他C++函数调用它。我试图包装这个损坏的名字,但它不起作用。我做的是这样的:'extern“C”int __wrap__Z3foov(void){ \t return 4; } void thisIsATest(){ assert 5 == giveMeANumber(); } '连同链接器选项'-Xlinker --wrap = _Z3foov'。不幸的是,真正的'foo'函数仍然被调用。有任何想法吗? – Mike

+0

我添加了一个例子。花了我一段时间才得到所有的下划线。 – smparkes

+0

并感谢您的问题。我甚至不知道 - 包装。非常好。 – smparkes

1

这似乎是你试图模拟函数和类进行测试。你有没有考虑使用Google Mock

+1

使用谷歌模拟不适合我。我只想在GNU链接器的帮助下完成此操作。 – Mike