#c #googletest
#c #googletest
Вопрос:
Я пытаюсь использовать std::chrono
типы с помощью Google test. Мой первый подход заключается в определении PrintTo
for nanoseconds
в пространстве имен std::chrono
, но, к сожалению , добавление объявлений или определений в пространство имен std
или в любое пространство имен, вложенное в std
. Следующий код демонстрирует идею.
#include <gtest/gtest.h>
#include <chrono>
namespace std::chrono {
void PrintTo(nanoseconds ns, std::ostream* os) // UB
{
*os << ns.count() << " nanoseconds ";
}
}
namespace {
struct MyTest : ::testing::Test{
};
TEST_F(MyTest, PrintingTest)
{
using namespace testing;
using namespace std::chrono_literals;
ASSERT_THAT(1ns, Eq(2ns));
}
}
Если std::chrono::PrintTo
определено, оно печатает:
Value of: 1ns
Expected: is equal to 2 nanoseconds
Actual:
Если std::chrono::PrintTo
не определено, оно печатается через байтовый принтер по умолчанию:
Value of: 1ns
Expected: is equal to 8-byte object <02-00 00-00 00-00 00-00>
Actual:
Каков идиоматический способ определения принтера для std::chrono
типов с помощью Google test?
Комментарии:
1. C 20-х
operator<<()
годов решит проблему.
Ответ №1:
Вы можете перегрузить оператор std::ostream для типов chrono следующим образом:
#include <gtest/gtest.h>
#include <chrono>
std::ostreamamp; operator<<(std::ostreamamp; os, const ::std::chrono::nanosecondsamp; ns)
{
return os << ns.count() << " nanoseconds ";
}
namespace {
struct MyTest : ::testing::Test{
};
TEST_F(MyTest, PrintingTest)
{
using namespace testing;
using namespace std::chrono_literals;
ASSERT_EQ(1ns, 2ns);
}
}
Тогда результат должен быть таким, как ожидалось:
error: Expected: 1ns
Which is: 1 nanoseconds
To be equal to: 2ns
Which is: 2 nanoseconds
[ FAILED ] MyTest.PrintingTest (0 ms)
Комментарии:
1. Кстати, это приведет к нарушениям ODR (из-за принтера по умолчанию в Google test
UniversalPrinter
), если есть другой cpp-файл, который не определяетoperator<<(... std::chrono::nanoseconds)
или определяет его по-другому.2. @DevNull Верно, но тогда ваши варианты — «неопределенное поведение» против «возможного ODR», я не знаю, есть ли другой правильный способ. Я использую реализацию UB (как в вашем вопросе) в своих тестах, я думаю, что в данном случае это приемлемо и правильно определено для текущего STL, в будущем это может стать UB. Возможно, следует задать вопрос на странице gtest github, чтобы попытаться спросить разработчиков, что они рекомендуют
3. Проблема с UB в том, что он может работать, но может и не работать… У меня есть две цели, одна с gcc (7.5) и одна с clang (8.0.1). Это решение отлично работает для первого, но не работает для последнего.
4. @Quarra Возможно, вам потребуется переместить реализацию в пространство имен std:: chrono таким же образом, как в исходном вопросе с помощью PrintTo() . Если это работает для обоих, то было бы неплохо узнать, какой из них правильный, а какой неправильный в данном решении.
5. Но разве расширение пространства имен std само по себе не является UB? en.cppreference.com/w/cpp/language/extending_std