【问题标题】:Matching C-style array passed as void* with GMock使用 GMock 匹配作为 void* 传递的 C 样式数组
【发布时间】:2018-02-13 14:58:40
【问题描述】:

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

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* @ 987654329@ 宏?
或者换句话说:
是否可以在不改变ElementsAreArray() 用户定义的匹配器的情况下使以下 sn-p 工作

EXPECT_CALL(myMock, write(_, NotNull(), expectedSize, _)
    .With(Args<1,2>(ElementsAreArray(dummyArray));

【问题讨论】:

  • const char * foo = static_cast&lt;const char*&gt;(buffer); 是这样做的正确方法。

标签: c++ gmock


【解决方案1】:

编辑:按照this answer 中的信息,我找到了一种无需自定义匹配器的方法。它涉及创建一个中间类并使用 3 个(count 'em)嵌套 SafeMatcherCasts:

#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)));

上一个答案:

我认为这是不可能的。

来自googlemock's cookbook

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

在这种情况下,Ttuple&lt;void*, size_t&gt;(您要匹配的内容),Utuple&lt;char*, size_t&gt;(您的 ElementsAreArray 匹配器接受的内容)。

As discussed in this questiontuple&lt;void*, size_t&gt;tuple&lt;char*, size_t&gt; 不是有效的 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);

【讨论】:

  • 非常有趣。这个解决方案似乎比匹配器更通用,但也更难理解 :) 我想知道这是否可以合并到 GoogleMock 源代码中 - 我想检查原始数据缓冲区并不少见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
相关资源
最近更新 更多