Comparación de matrices en la prueba de Google?

81

Estoy buscando comparar dos matrices en la prueba de Google. En UnitTest ++ esto se hace a través de CHECK_ARRAY_EQUAL. ¿Cómo lo haces en Google Test?

Tobias Furuholm
fuente

Respuestas:

115

Realmente sugeriría mirar Google C ++ Mocking Framework . Incluso si no quiere burlarse de nada, le permite escribir afirmaciones bastante complicadas con facilidad.

Por ejemplo

//checks that vector v is {5, 10, 15}
ASSERT_THAT(v, ElementsAre(5, 10, 15));

//checks that map m only have elements 1 => 10, 2 => 20
ASSERT_THAT(m, ElementsAre(Pair(1, 10), Pair(2, 20)));

//checks that in vector v all the elements are greater than 10 and less than 20
ASSERT_THAT(v, Each(AllOf(Gt(10), Lt(20))));

//checks that vector v consist of 
//   5, number greater than 10, anything.
ASSERT_THAT(v, ElementsAre(5, Gt(10), _));

Hay muchos emparejadores para todas las situaciones posibles, y puedes combinarlos para lograr casi cualquier cosa.

¿Te he dicho que las ElementsArenecesidades única iteratorsy size()método en una clase de trabajo? Por lo tanto, no solo funciona con cualquier contenedor de STL, sino también con contenedores personalizados.

Google Mock afirma ser casi tan portátil como Google Test y, francamente, no veo por qué no lo usaría. Es simplemente asombroso.

vava
fuente
7
Yo uso Google Mock. Y estoy de acuerdo en que es asombroso. Nunca esperé ver algo así para C ++.
Tobias Furuholm
2
ElementsAreArrayEs mejor comparar matrices, ya que ElementsAretiene un límite de 10 elementos.
BЈовић
2
Tenga en cuenta que es posible que desee utilizar EXPECT_THAT en lugar de ASSERT_THAT en las pruebas.
arhuaco
¿y si los elementos son std :: string? Tengo un error de enlazador testing::Matcher<std::string const&>::Matcher(char const*)no definido
Frank Liu
1
Como BЈовић mencionó ElementsAreArray, aquí hay un ejemplo para el uso de eso: EXPECT_THAT(v, ElementsAreArray(u));que he tenido más uso que los ejemplos actuales.
Zitrax
18

Si solo necesita verificar si las matrices son iguales, entonces la fuerza bruta también funciona:

int arr1[10];
int arr2[10];

// initialize arr1 and arr2

EXPECT_TRUE( 0 == std::memcmp( arr1, arr2, sizeof( arr1 ) ) );

Sin embargo, esto no le dice qué elemento difiere.

BЈовић
fuente
15

Si desea comparar un puntero de matriz de estilo c con una matriz usando Google Mock, puede pasar por std :: vector. Por ejemplo:

uint8_t expect[] = {1, 2, 3, 42};
uint8_t * buffer = expect;
uint32_t buffer_size = sizeof(expect) / sizeof(expect[0]);
ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(expect));

ElementsAreArray de Google Mock también acepta puntero y longitud que permiten la comparación de dos punteros de matriz de estilo C. Por ejemplo:

ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(buffer, buffer_size));

Pasé demasiado tiempo tratando de reconstruir esto. Gracias a esta publicación de StackOverflow por el recordatorio sobre la inicialización del iterador std :: vector. Tenga en cuenta que este método copiará los elementos de la matriz de búfer en el vector std :: antes de la comparación.

Matt Liberty
fuente
1
Si el error en el código que se está probando es aquel en el buffer_sizeque un valor devuelto por el código que se está probando se establece incorrectamente (size_t)-1, lo cual no es un error poco común, entonces el constructor de vectores intentará hacer un vector muy grande. Es posible que el programa de prueba se elimine con un límite de recursos o un error de memoria insuficiente, o simplemente se bloquee, en lugar de que falle la afirmación de prueba. Con C ++ 20, usar en std::spanlugar de vector debería evitar esto, ya que no es necesario copiar el búfer en un nuevo contenedor.
TrentP
Algo similar se podría lograr reinterpretando la conversión del actualData al puntero std :: array <tipo, tamaño> y desreferenciando el ptr. en la aseveración. Algo como: gist.github.com/daantimmer/…
Daan Timmer
13
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i < x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}

Fuente

Николай Русскин
fuente
Me gusta un poco. No requiere copiar los datos a un contenedor stl, y es bastante simple. Envolver esto en una macro para un tipo común de comparación de matrices (como un vector o una matriz), simplemente se hace y hace el trabajo.
johnb003
9

Tenía exactamente la misma pregunta, así que escribí un par de macros que hacen comparaciones entre dos contenedores genéricos. Es extensible a cualquier recipiente que tiene const_iterator, beginy end. Si falla, mostrará un mensaje detallado de dónde salió mal la matriz y lo hará para cada elemento que falle; se asegurará de que tengan la misma longitud; y la ubicación en su código que informa que falla es la misma línea a la que llama EXPECT_ITERABLE_EQ( std::vector< double >, a, b).

//! Using the google test framework, check all elements of two containers
#define EXPECT_ITERABLE_BASE( PREDICATE, REFTYPE, TARTYPE, ref, target) \
    { \
    const REFTYPE& ref_(ref); \
    const TARTYPE& target_(target); \
    REFTYPE::const_iterator refIter = ref_.begin(); \
    TARTYPE::const_iterator tarIter = target_.begin(); \
    unsigned int i = 0; \
    while(refIter != ref_.end()) { \
        if ( tarIter == target_.end() ) { \
            ADD_FAILURE() << #target " has a smaller length than " #ref ; \
            break; \
        } \
        PREDICATE(* refIter, * tarIter) \
            << "Containers " #ref  " (refIter) and " #target " (tarIter)" \
               " differ at index " << i; \
        ++refIter; ++tarIter; ++i; \
    } \
    EXPECT_TRUE( tarIter == target_.end() ) \
        << #ref " has a smaller length than " #target ; \
    }

//! Check that all elements of two same-type containers are equal
#define EXPECT_ITERABLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, TYPE, TYPE, ref, target )

//! Check that all elements of two different-type containers are equal
#define EXPECT_ITERABLE_EQ2( REFTYPE, TARTYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, REFTYPE, TARTYPE, ref, target )

//! Check that all elements of two same-type containers of doubles are equal
#define EXPECT_ITERABLE_DOUBLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_DOUBLE_EQ, TYPE, TYPE, ref, target )

Espero que esto funcione para usted (y que realmente verifique esta respuesta dos meses después de que se envió su pregunta).

Seth Johnson
fuente
¡Ese es un gran enfoque! ¿Quizás podrías proporcionar esto a Google para que lo agreguen al marco?
Tobias Furuholm
2
Dijeron ( code.google.com/p/googletest/issues/detail?id=231 ) que desalientan la adición de macros, y esta funcionalidad está disponible hasta cierto punto en el marco de Google Mock.
Seth Johnson
5

Me encontré con un problema similar al comparar matrices en la prueba de Google .

Como necesitaba una comparación con lo básico void*y char*(para pruebas de código de bajo nivel), no creo que Google Mock (que también estoy usando en el proyecto) o la gran macro de Seth puedan ayudarme en la situación particular. Escribí la siguiente macro:

#define EXPECT_ARRAY_EQ(TARTYPE, reference, actual, element_count) \
    {\
    TARTYPE* reference_ = static_cast<TARTYPE *> (reference); \
    TARTYPE* actual_ = static_cast<TARTYPE *> (actual); \
    for(int cmp_i = 0; cmp_i < element_count; cmp_i++ ){\
      EXPECT_EQ(reference_[cmp_i], actual_[cmp_i]);\
    }\
    }

Los moldes están ahí para hacer que la macro se pueda usar cuando se compara void*con otras cosas:

  void* retrieved = ptr->getData();
  EXPECT_EQ(6, ptr->getSize());
  EXPECT_ARRAY_EQ(char, "data53", retrieved, 6)

Tobias en los comentarios sugirieron fundición void*a char*y el uso EXPECT_STREQ, una macro de alguna manera perdido antes - que se parece a una mejor alternativa.

nietaki
fuente
2
Preferiría convertir el vacío * en un char * y usar EXPECT_STREQ. ¿No funcionaría eso también?
Tobias Furuholm
Una de las razones por las que publiqué mi respuesta fue porque esperaba que alguien sugiriera una alternativa mejor. Parece que lo hiciste, Tobias :)
nietaki
EXPECT_STREQno funciona para matrices arbitrarias que contienen cero elementos. Todavía votaría por la solución de @nietaki.
Mohammad Dashti
4

A continuación se muestra una afirmación que escribí para comparar [fragmentos de] dos matrices de punto flotante:

/* See
http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
for thorough information about comparing floating point values.
For this particular application we know that the value range is -1 to 1 (audio signal),
so we can compare to absolute delta of 1/2^22 which is the smallest representable value in
a 22-bit recording.
*/
const float FLOAT_INEQUALITY_TOLERANCE = float(1.0 / (1 << 22));


template <class T>
::testing::AssertionResult AreFloatingPointArraysEqual(
                                const T* const expected,
                                const T* const actual,
                                unsigned long length)
{
    ::testing::AssertionResult result = ::testing::AssertionFailure();
    int errorsFound = 0;
    const char* separator = " ";
    for (unsigned long index = 0; index < length; index++)
    {
        if (fabs(expected[index] - actual[index]) > FLOAT_INEQUALITY_TOLERANCE)
        {
            if (errorsFound == 0)
            {
                result << "Differences found:";
            }
            if (errorsFound < 3)
            {
                result << separator
                        << expected[index] << " != " << actual[index]
                        << " @ " << index;
                separator = ", ";
            }
            errorsFound++;
        }
    }
    if (errorsFound > 0)
    {
        result << separator << errorsFound << " differences in total";
        return result;
    }
    return ::testing::AssertionSuccess();
}

El uso dentro del marco de prueba de Google es este:

EXPECT_TRUE(AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare));

En caso de error, se produce algo como el siguiente resultado:

..\MyLibraryTestMain.cpp:145: Failure
Value of: AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare)
  Actual: false (Differences found: 0.86119759082794189 != 0.86119747161865234 @ 14, -0.5552707314491272 != -0.55527061223983765 @ 24, 0.047732405364513397 != 0.04773232713341713 @ 36, 339 differences in total)
Expected: true

Para una discusión detallada sobre la comparación de valores de coma flotante en general, consulte esto .

astraujums
fuente
3

Usé un bucle clásico a través de todos los elementos. Puede usar SCOPED_TRACE para leer en qué iteración difieren los elementos de la matriz. Esto le proporciona información adicional en comparación con otros enfoques y es fácil de leer.

for (int idx=0; idx<ui16DataSize; idx++)
{
    SCOPED_TRACE(idx); //write to the console in which iteration the error occurred
    ASSERT_EQ(array1[idx],array2[idx]);
}
Wintermute
fuente