Подтвердить что ты не робот

Как сравнить векторы с Boost.Test?

Я использую Boost Test для unit test некоторого кода на С++.

У меня есть вектор значений, которые мне нужно сравнить с ожидаемыми результатами, но я не хочу вручную проверять значения в цикле:

BOOST_REQUIRE_EQUAL(values.size(), expected.size());

for( int i = 0; i < size; ++i )
{
    BOOST_CHECK_EQUAL(values[i], expected[i]);
}

Основная проблема заключается в том, что проверка цикла не печатает индекс, поэтому для поиска несоответствия требуется некоторый поиск.

Я мог бы использовать std::equal или std::mismatch для двух векторов, но для этого потребуется много шаблонов.

Есть ли более чистый способ сделать это?

4b9b3361

Ответ 1

Используйте BOOST_CHECK_EQUAL_COLLECTIONS. Это макрос в test_tools.hpp, который принимает две пары итераторов:

BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(), 
                              expected.begin(), expected.end());

Он будет сообщать индексы и значения, которые не совпадают. Если размеры не совпадают, они сообщают об этом также (и не будут просто заканчиваться с конца вектора).


Обратите внимание, что если вы хотите использовать BOOST_CHECK_EQUAL или BOOST_CHECK_EQUAL_COLLECTIONS с не-POD-типами, вам нужно будет реализовать

bool YourType::operator!=(const YourType &rhs)  //  or OtherType
std::ostream &operator<<(std::ostream &os, const YourType &yt)

для сравнения и каротажа, соответственно.
Порядок итераторов, переданных на BOOST_CHECK_EQUAL_COLLECTIONS, определяет, что является RHS и LHS сравнения != - первый диапазон итераторов будет LHS в сравнении.

Ответ 2

Как насчет BOOST_CHECK_EQUAL_COLLECTIONS?

BOOST_AUTO_TEST_CASE( test )
{
    int col1 [] = { 1, 2, 3, 4, 5, 6, 7 };
    int col2 [] = { 1, 2, 4, 4, 5, 7, 7 };

    BOOST_CHECK_EQUAL_COLLECTIONS( col1, col1+7, col2, col2+7 );
}

Пример

Запуск 1 тестового примера...

test.cpp(11): ошибка в "тесте": проверить {col1, col1 + 7} == {col2, col2 + 7} не удалось.

Несоответствие в позиции 2: 3!= 4

Несоответствие в позиции 5: 6!= 7

* 1 обнаружен отказ в наборе тестов "пример"

Ответ 3

Немного не по теме, однако, когда иногда приходится сравнивать коллекции чисел с плавающей запятой, используя сравнение с допуском, этот фрагмент может быть полезен:

// Have to make it a macro so that it reports exact line numbers when checks fail.
#define CHECK_CLOSE_COLLECTION(aa, bb, tolerance) { \
    using std::distance; \
    using std::begin; \
    using std::end; \
    auto a = begin(aa), ae = end(aa); \
    auto b = begin(bb); \
    BOOST_REQUIRE_EQUAL(distance(a, ae), distance(b, end(bb))); \
    for(; a != ae; ++a, ++b) { \
        BOOST_CHECK_CLOSE(*a, *b, tolerance); \
    } \
}

Это не печатает индексы массива несоответствующих элементов, но печатает значения несоответствия с высокой точностью, поэтому их часто легко найти.

Пример использования:

auto mctr = pad.mctr();
std::cout << "mctr: " << io::as_array(mctr) << '\n';
auto expected_mctr{122.78731602430344,-13.562000155448914};
CHECK_CLOSE_COLLECTION(mctr, expected_mctr, 0.001);

Ответ 4

Вы можете использовать BOOST_REQUIRE_EQUAL_COLLECTIONS с помощью std::vector<T>, но вам нужно научить Boost.Test, как печатать std::vector, когда вы имеют вектор векторов или отображение, значения которого являются векторами. Когда у вас есть карта, Boost.Test нужно научить печатать std::pair. Поскольку вы не можете изменить определение std::vector или std::pair, вы должны сделать это таким образом, чтобы определяемый вами оператор вставки потока использовался Boost.Test, не являясь частью определения класса std::vector. Кроме того, этот метод полезен, если вы не хотите добавлять операторы вставки потока в свою тестовую систему, чтобы сделать Boost.Test счастливым.

Вот рецепт для любого std::vector:

namespace boost
{

// teach Boost.Test how to print std::vector
template <typename T>
inline wrap_stringstream&
operator<<(wrap_stringstream& wrapped, std::vector<T> const& item)
{
    wrapped << '[';
    bool first = true;
    for (auto const& element : item) {
        wrapped << (!first ? "," : "") << element;
        first = false;
    }
    return wrapped << ']';
}

}

Это форматирует векторы как [e1,e2,e3,...,eN] для вектора с элементами N и будет работать для любого количества вложенных векторов, например. где элементы вектора также являются векторами.

Вот аналогичный рецепт для std::pair:

namespace boost
{

// teach Boost.Test how to print std::pair
template <typename K, typename V>
inline wrap_stringstream&
operator<<(wrap_stringstream& wrapped, std::pair<const K, V> const& item)
{
    return wrapped << '<' << item.first << ',' << item.second << '>';
}

}

BOOST_REQUIRE_EQUAL_COLLECTIONS сообщит вам индекс несогласованных элементов, а также содержимое двух коллекций, предполагая, что две коллекции имеют одинаковый размер. Если они имеют разные размеры, то это считается несоответствием и печатаются разные размеры.

Ответ 5

Так как Boost 1.59 намного проще сравнивать экземпляры std::vector. См. эту документацию для версии 1.63 (что почти равно этому 1.59).

Например, если вы объявили std::vector<int> a, b;, вы можете написать

BOOST_TEST(a == b);

чтобы получить очень базовое сравнение. Недостатком этого является то, что в случае сбоя Boost сообщает, что a и b не совпадают. Но вы получаете больше информации, сравнивая элементы, которые возможны элегантным способом.

BOOST_TEST(a == b, boost::test_tools::per_element() );

Или, если вы хотите использовать лексикографическое сравнение, вы можете сделать

BOOST_TEST(a <= b, boost::test_tools::lexicographic() );