匹配作为 void* 与 GMock 传递的 C 样式数组
Matching C-style array passed as void* with GMock
我正在尝试模拟这样的功能:
int write(int fd, const void* buffer, size_t size, bool something)
我想检查缓冲区传递的数据的正确性(第一个和最后一个参数对测试不重要)。
很少有好的匹配器可以帮助我们做到这一点,即 ElementsAreArray。如果指针是例如char*
,那就简单了:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(ElementsAreArray(dummyArray));
问题:无法取消引用 void*。因此,它无法与 ElementsAreArray 匹配。
我尝试了以下方法:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(MatcherCast<::testing::tuple<const char*, size_t>>(ElementsAreArray(dummyArray)));
但它在 MatcherCast 中失败 static_assert - T_must_be_implicitly_convertible_to_U
可以编写自己的匹配器来避免这种情况,但感觉很笨拙。下面的一个有效,但我更愿意避免编写自己的匹配器:
MATCHER_P2(EqualToArray, compareArray, n, "")
{
const char *arr = static_cast<const char*>(arg);
for (size_t i = 0; i < n; ++i)
{
if (arr[i] != compareArray[i])
{
return false;
}
}
return true;
}
EXPECT_CALL(myMock, write(_, EqualToArray(dummyArray, expectedSize), expectedSize, _);
编辑:对不起,我可能没说清楚。
我知道从 void* 转换为任何其他指针类型并不是什么大问题。但这需要我们有一个函数或用户定义的匹配器,例如像我写的那样,如果可以使用已经定义的 GMock 匹配器,我会尽量避免使用用户定义的匹配器。
所以,更具体的问题是:
是否可以将void*
转换为char*
EXPECT_CALL
宏?
或者换句话说:
是否可以在不将 ElementsAreArray()
更改为用户定义的匹配器的情况下使以下代码片段工作:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(ElementsAreArray(dummyArray));
编辑: 根据 this answer 中的信息,我找到了一种无需自定义匹配器即可执行此操作的方法。它涉及创建一个中间 class 并使用 3 个(计数)嵌套 SafeMatcherCast
s:
#include <tuple>
#include <gmock/gmock.h>
// This is a matcher like ElementsAreArray, but it allows you to match against a void *.
template <typename T>
testing::Matcher<std::tuple<const void*, size_t>> elementsAreArrayVoidPointer(
const T* ptr, size_t size) {
class TupleConverter : public std::tuple<const T*, size_t> {
public:
TupleConverter(const std::tuple<const void*, size_t>& t)
: std::tuple<const T*, size_t>(static_cast<const T*>(std::get<0>(t)), std::get<1>(t)) {}
};
return testing::SafeMatcherCast<std::tuple<const void*, size_t>>(
testing::SafeMatcherCast<TupleConverter>(
testing::SafeMatcherCast<std::tuple<const T*, size_t>>(
testing::ElementsAreArray(ptr, size))));
}
您可以按如下方式使用它:
EXPECT_CALL(mock_cstdio, fwrite(_, 1, _, _))
.With(Args<0, 2>(elementsAreArrayVoidPointer(my_char_p, my_size)));
上一个答案:
我认为这是不可能的。
... MatcherCast works as long as you can static_cast type T to type U.
在此上下文中,T
是 tuple<void*, size_t>
(您要匹配的内容),U
是 tuple<char*, size_t>
(您的 ElementsAreArray
匹配器接受)。
As discussed in this question、tuple<void*, size_t>
到 tuple<char*, size_t>
不是有效的 static_cast
。 (尽管 void*
到 char*
是有效的 static_cast
!)
所以我认为在这种情况下您需要编写自定义匹配器。
注意:T_must_be_implicitly_convertible_to_U
消息是转移注意力。你看到了,因为 googlemock 也尝试使用 SafeMatcherCast
并且失败了,正如预期的那样。这是真正的错误(来自我们希望有效但无效的模板实例化):
external/gtest/googlemock/include/gmock/gmock-matchers.h:577:73: error: invalid static_cast from type 'std::tuple<void*, long unsigned int>' to type 'const std::tuple<char*, long unsigned int>&'
return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);
我正在尝试模拟这样的功能:
int write(int fd, const void* buffer, size_t size, bool something)
我想检查缓冲区传递的数据的正确性(第一个和最后一个参数对测试不重要)。
很少有好的匹配器可以帮助我们做到这一点,即 ElementsAreArray。如果指针是例如char*
,那就简单了:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(ElementsAreArray(dummyArray));
问题:无法取消引用 void*。因此,它无法与 ElementsAreArray 匹配。
我尝试了以下方法:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(MatcherCast<::testing::tuple<const char*, size_t>>(ElementsAreArray(dummyArray)));
但它在 MatcherCast 中失败 static_assert - T_must_be_implicitly_convertible_to_U
可以编写自己的匹配器来避免这种情况,但感觉很笨拙。下面的一个有效,但我更愿意避免编写自己的匹配器:
MATCHER_P2(EqualToArray, compareArray, n, "")
{
const char *arr = static_cast<const char*>(arg);
for (size_t i = 0; i < n; ++i)
{
if (arr[i] != compareArray[i])
{
return false;
}
}
return true;
}
EXPECT_CALL(myMock, write(_, EqualToArray(dummyArray, expectedSize), expectedSize, _);
编辑:对不起,我可能没说清楚。
我知道从 void* 转换为任何其他指针类型并不是什么大问题。但这需要我们有一个函数或用户定义的匹配器,例如像我写的那样,如果可以使用已经定义的 GMock 匹配器,我会尽量避免使用用户定义的匹配器。
所以,更具体的问题是:
是否可以将void*
转换为char*
EXPECT_CALL
宏?
或者换句话说:
是否可以在不将 ElementsAreArray()
更改为用户定义的匹配器的情况下使以下代码片段工作:
EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
.With(Args<1,2>(ElementsAreArray(dummyArray));
编辑: 根据 this answer 中的信息,我找到了一种无需自定义匹配器即可执行此操作的方法。它涉及创建一个中间 class 并使用 3 个(计数)嵌套 SafeMatcherCast
s:
#include <tuple>
#include <gmock/gmock.h>
// This is a matcher like ElementsAreArray, but it allows you to match against a void *.
template <typename T>
testing::Matcher<std::tuple<const void*, size_t>> elementsAreArrayVoidPointer(
const T* ptr, size_t size) {
class TupleConverter : public std::tuple<const T*, size_t> {
public:
TupleConverter(const std::tuple<const void*, size_t>& t)
: std::tuple<const T*, size_t>(static_cast<const T*>(std::get<0>(t)), std::get<1>(t)) {}
};
return testing::SafeMatcherCast<std::tuple<const void*, size_t>>(
testing::SafeMatcherCast<TupleConverter>(
testing::SafeMatcherCast<std::tuple<const T*, size_t>>(
testing::ElementsAreArray(ptr, size))));
}
您可以按如下方式使用它:
EXPECT_CALL(mock_cstdio, fwrite(_, 1, _, _))
.With(Args<0, 2>(elementsAreArrayVoidPointer(my_char_p, my_size)));
上一个答案:
我认为这是不可能的。
... MatcherCast works as long as you can static_cast type T to type U.
在此上下文中,T
是 tuple<void*, size_t>
(您要匹配的内容),U
是 tuple<char*, size_t>
(您的 ElementsAreArray
匹配器接受)。
As discussed in this question、tuple<void*, size_t>
到 tuple<char*, size_t>
不是有效的 static_cast
。 (尽管 void*
到 char*
是有效的 static_cast
!)
所以我认为在这种情况下您需要编写自定义匹配器。
注意:T_must_be_implicitly_convertible_to_U
消息是转移注意力。你看到了,因为 googlemock 也尝试使用 SafeMatcherCast
并且失败了,正如预期的那样。这是真正的错误(来自我们希望有效但无效的模板实例化):
external/gtest/googlemock/include/gmock/gmock-matchers.h:577:73: error: invalid static_cast from type 'std::tuple<void*, long unsigned int>' to type 'const std::tuple<char*, long unsigned int>&'
return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);