强制 googletest 签名与未签名比较失败
Force googletest signed vs unsigned comparison to fail
首先,我是 googletest 框架的新手,请多关照。
我有一个功能
void setID(const int id)
{
ID = id;
}
其中 ID 是全局的 unsigned int
。 (是的,全局变量不好,我只是想弄清楚我在做什么。)
我的单元测试是这样的
TEST_F(TempTests, SetId)
{
// Arrange
int id = -99;
// Act
setId(id);
// Assert
EXPECT_EQ(id, ID);
}
问题是我的单元测试总是通过,但我需要它失败,因为 ID 应该是有符号整数而不是无符号整数。如果我没有在视觉上发现错误,单元测试就会通过,它可能会在以后导致错误。
为确保以后不会发生这种情况,最好在这种情况下单元测试比较失败。
我已经尝试以各种方式将 id
和 ID
静态转换为有符号和无符号整数。
我尝试过 EXPECT_TRUE(id == ID)
以各种方式将变量静态转换为有符号和无符号整数。
但在所有这些情况下,结果都是通过测试。
那么我怎样才能让 gtest 比较 id
的有符号值和 ID
的无符号值,这样测试就会失败,因为 id
将为 -99 而 ID
将是 4294967197?
编译器需要将类型转换为相等。我推荐阅读 this related answer.
您或许能够创建自定义 googletest 比较器。即使没有,你至少可以使用类似这样的东西:
#include <iostream>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <typeinfo>
template <class T>
class SignedUnsignedIntCompare final /* final for non-virtual dtor, remember to make dtor virtual if you need to inherit */ {
public:
const T & v;
SignedUnsignedIntCompare(const T & v) : v(v) {}
SignedUnsignedIntCompare(SignedUnsignedIntCompare && move_ctor) = default;
SignedUnsignedIntCompare(const SignedUnsignedIntCompare & copy_ctor) = default;
SignedUnsignedIntCompare & operator=(SignedUnsignedIntCompare && move_assign) = default;
SignedUnsignedIntCompare & operator=(const SignedUnsignedIntCompare & copy_assign) = default;
~SignedUnsignedIntCompare() = default;
template <class TT>
bool operator==(const TT & i) const {
if ( std::numeric_limits<T>::is_signed != std::numeric_limits<TT>::is_signed ) {
return ((v == i) && (T(v) <= std::numeric_limits<TT>::max()) && (TT(i) <= std::numeric_limits<T>::max()));
}
return (v == i);
}
};
typedef SignedUnsignedIntCompare<int> SignedIntCompare;
typedef SignedUnsignedIntCompare<unsigned> UnsignedIntCompare;
int main() {
int i = -99;
unsigned int u = i;
std::cout << (i == u) << " vs " << (SignedIntCompare(i) == u) << std::endl;
return 0;
}
此时,您可以使用 EXPECT_TRUE
或类似的布尔检查,例如:
TEST(foo, bar) {
int id = -99;
setId(id);
EXPECT_TRUE(SignedUnsignedIntCompare<decltype(ID)>(ID) == id);
}
所以我不确定如何给予信任,但我最终结合了 inetknght 和 mkk 的建议。
TEST_F(TempTests, SetId)
{
// Arrange
int id = -99;
// Act
setId(id);
// Assert
EXPECT_TRUE(std::numeric_limits<decltype(id)>::is_signed == std::numeric_limits<decltype(ID)>::is_signed);
EXPECT_EQ(id, ID);
}
根据 inetknght 的建议,通过检查已签名的类型,我能够使测试失败,因为这些类型并非都已签名。根据 mkk 的建议,通过使用 decltype,我可以在更正 ID 类型时获取变量的声明类型,而无需在将来修改单元测试。更正 ID 类型后,测试通过。
编辑
根据 Adrian McCarthy 的建议,我还添加了 -Werror=conversion 到我的编译器标志中。
首先,我是 googletest 框架的新手,请多关照。
我有一个功能
void setID(const int id)
{
ID = id;
}
其中 ID 是全局的 unsigned int
。 (是的,全局变量不好,我只是想弄清楚我在做什么。)
我的单元测试是这样的
TEST_F(TempTests, SetId)
{
// Arrange
int id = -99;
// Act
setId(id);
// Assert
EXPECT_EQ(id, ID);
}
问题是我的单元测试总是通过,但我需要它失败,因为 ID 应该是有符号整数而不是无符号整数。如果我没有在视觉上发现错误,单元测试就会通过,它可能会在以后导致错误。
为确保以后不会发生这种情况,最好在这种情况下单元测试比较失败。
我已经尝试以各种方式将 id
和 ID
静态转换为有符号和无符号整数。
我尝试过 EXPECT_TRUE(id == ID)
以各种方式将变量静态转换为有符号和无符号整数。
但在所有这些情况下,结果都是通过测试。
那么我怎样才能让 gtest 比较 id
的有符号值和 ID
的无符号值,这样测试就会失败,因为 id
将为 -99 而 ID
将是 4294967197?
编译器需要将类型转换为相等。我推荐阅读 this related answer.
您或许能够创建自定义 googletest 比较器。即使没有,你至少可以使用类似这样的东西:
#include <iostream>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <typeinfo>
template <class T>
class SignedUnsignedIntCompare final /* final for non-virtual dtor, remember to make dtor virtual if you need to inherit */ {
public:
const T & v;
SignedUnsignedIntCompare(const T & v) : v(v) {}
SignedUnsignedIntCompare(SignedUnsignedIntCompare && move_ctor) = default;
SignedUnsignedIntCompare(const SignedUnsignedIntCompare & copy_ctor) = default;
SignedUnsignedIntCompare & operator=(SignedUnsignedIntCompare && move_assign) = default;
SignedUnsignedIntCompare & operator=(const SignedUnsignedIntCompare & copy_assign) = default;
~SignedUnsignedIntCompare() = default;
template <class TT>
bool operator==(const TT & i) const {
if ( std::numeric_limits<T>::is_signed != std::numeric_limits<TT>::is_signed ) {
return ((v == i) && (T(v) <= std::numeric_limits<TT>::max()) && (TT(i) <= std::numeric_limits<T>::max()));
}
return (v == i);
}
};
typedef SignedUnsignedIntCompare<int> SignedIntCompare;
typedef SignedUnsignedIntCompare<unsigned> UnsignedIntCompare;
int main() {
int i = -99;
unsigned int u = i;
std::cout << (i == u) << " vs " << (SignedIntCompare(i) == u) << std::endl;
return 0;
}
此时,您可以使用 EXPECT_TRUE
或类似的布尔检查,例如:
TEST(foo, bar) {
int id = -99;
setId(id);
EXPECT_TRUE(SignedUnsignedIntCompare<decltype(ID)>(ID) == id);
}
所以我不确定如何给予信任,但我最终结合了 inetknght 和 mkk 的建议。
TEST_F(TempTests, SetId)
{
// Arrange
int id = -99;
// Act
setId(id);
// Assert
EXPECT_TRUE(std::numeric_limits<decltype(id)>::is_signed == std::numeric_limits<decltype(ID)>::is_signed);
EXPECT_EQ(id, ID);
}
根据 inetknght 的建议,通过检查已签名的类型,我能够使测试失败,因为这些类型并非都已签名。根据 mkk 的建议,通过使用 decltype,我可以在更正 ID 类型时获取变量的声明类型,而无需在将来修改单元测试。更正 ID 类型后,测试通过。
编辑
根据 Adrian McCarthy 的建议,我还添加了 -Werror=conversion 到我的编译器标志中。