匹配的C样式数组通过GMock作为void *传递

Yks*_*nen 5 c++ gmock

我正在尝试模拟这样的功能:

int write(int fd, const void* buffer, size_t size, bool something)
Run Code Online (Sandbox Code Playgroud)

我想检查通过缓冲区传递的数据的正确性(第一个和最后一个参数对测试不重要)。很少有匹配器可以帮助我们完成这些任务,即ElementsAreArray。如果指针是eg char*,那么很简单:

EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
    .With(Args<1,2>(ElementsAreArray(dummyArray));
Run Code Online (Sandbox Code Playgroud)

问题:void *无法取消引用。因此,它不能与ElementsAreArray匹配。

我尝试了以下方法:

EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
    .With(Args<1,2>(MatcherCast<::testing::tuple<const char*, size_t>>(ElementsAreArray(dummyArray)));
Run Code Online (Sandbox Code Playgroud)

但在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, _);
Run Code Online (Sandbox Code Playgroud)

编辑:对不起,我可能还没有说清楚。
我知道从void *转换为任何其他指针类型的问题不大。但这要求我们拥有一个功能或用户定义的匹配器,例如与我编写的功能或用户定义的匹配器,如果可能的话,我试图避免使用用户定义的匹配器,如果可能的话,可以使用已经定义的GMock匹配器。

因此,更具体的问题是:
是否可以强制 void* 转换为 char* 内部 EXPECT_CALL 宏?
换句话说:
是否可以在不更改 为用户定义匹配器的情况下使以下代码段起作用ElementsAreArray()

EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
    .With(Args<1,2>(ElementsAreArray(dummyArray));
Run Code Online (Sandbox Code Playgroud)

Ker*_*ley 2

编辑:我找到了一种无需自定义匹配器即可完成此操作的方法,遵循此答案中的信息。它涉及创建一个中间类并使用 3 个(数数)嵌套SafeMatcherCast

#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))));
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式使用它:

EXPECT_CALL(mock_cstdio, fwrite(_, 1, _, _))
    .With(Args<0, 2>(elementsAreArrayVoidPointer(my_char_p, my_size)));
Run Code Online (Sandbox Code Playgroud)

上一个答案:

我认为这是不可能的。

来自googlemock 的食谱

...只要您可以将 T 类型静态转换为 U 类型,MatcherCast 就可以工作。

在这种情况下,Ttuple<void*, size_t>(你试图匹配的内容)和Utuple<char*, size_t>(你的匹配器接受的内容ElementsAreArray)。

正如本问题中所讨论的tuple<void*, size_t>totuple<char*, size_t>不是有效的static_cast。(尽管void*tochar*是有效的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);
Run Code Online (Sandbox Code Playgroud)