2011-12-06 8 views
6

Me gusta la funcionalidad del enlazador GNU para ajustar funciones mucho. Normalmente lo uso simulacro, p. funciones no deterministas llamadas como rand(). Considere el siguiente ejemplo en el que me gustaría escribir una prueba unitaria para giveMeANumber:Envoltura de funciones C++ con el enlazador GNU

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

puedo envolver la llamada a rand con la GNU funcionalidad enlazador envoltura de la siguiente manera:

//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 

¿Hay alguna manera hacer lo mismo con las funciones normales de C++? Lo siguiente no funciona, supongo que es debido al cambio de nombre. Pero incluso cuando lo intento con el nombre destrozado, no funciona.

//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 

¿Alguna idea?

+0

En realidad, rand es una función determinista. Devuelve una secuencia numérica pseudoaleatoria. Llama al rand para que devuelva la misma secuencia de números para cualquier semilla dada usada con srand. – TJD

+1

Bien, bravo, eso es verdad. Pero para mantener el ejemplo corto y legible, no usé una semilla. – Mike

+0

Debe cambiar el nombre '__wrap_foo' por' getRandomNumber'. (http://xkcd.com/221/) –

Respuesta

8

Necesitas sea también extern "C" la función que desee para envolver (si eso es posible) o que necesita para envolver el nombre revuelto, por ejemplo, __wrap__Z3foov y luego pasar --wrap=_Z3foov al enlazador.

Obtener los caracteres de subrayado correctos es un poco complicado. Esto funciona para mí:

$ 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

La vinculación C para la función envolvente de C++ no es una opción porque esta función podría estar sobrecargada y todavía debería ser posible llamarla desde otras funciones de C++. Traté de envolver el nombre destrozado, pero no funciona. Lo que hice fue esto: 'extern" C "int __wrap__Z3foov (void) { \t return 4; } void thisIsATest() { assert 5 == giveMeANumber(); } 'junto con la opción del enlazador' -Xlinker --wrap = _Z3foov'. Desafortunadamente, la verdadera función 'foo' todavía se está llamando. ¿Algunas ideas? – Mike

+0

Agregué un ejemplo. Me tomó un tiempo para tener todos los guiones bajos correctos. – smparkes

+0

Y gracias por la pregunta. Ni siquiera sabía sobre - envoltura. Muy agradable. – smparkes

1

Parece que está intentando simular funciones y clases para probar. ¿Te considerar el uso de Google Mock

+1

Usar Google mock no es una opción para mí. Quiero lograr esto únicamente con la ayuda del enlazador GNU. – Mike

Cuestiones relacionadas