匹配C样式数组作为void *传递给GM​​ock

时间:2018-02-13 14:58:41

标签: c++ 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));

问题:无法取消引用*。因此,它无法与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 ?< / em>的
或者换句话说:
是否可以在不将 ElementsAreArray() 更改为用户定义的匹配器的情况下使以下代码段正常工作:

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

2 个答案:

答案 0 :(得分:1)

编辑:我按照this answer中的信息找到了一种无需自定义匹配器的方法。它涉及到创建一个中间类并使用3个(count'em)嵌套的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))));
}

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

EXPECT_CALL(mock_cstdio, fwrite(_, 1, _, _))
    .With(Args<0, 2>(elementsAreArrayVoidPointer(my_char_p, my_size)));

上一个答案:

我认为这不可能。

来自googlemock's cookbook

  

... MatcherCast可以正常工作,只要您可以将static_cast类型T转换为U类型即可。

在这种情况下,Ttuple<void*, size_t>(您要匹配的内容),Utuple<char*, size_t>(您的ElementsAreArray匹配者接受的内容)

As discussed in this questiontuple<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);

答案 1 :(得分:-1)

  

问题是:我们如何将const void*投射到const char*

如果您知道buffer当然是const char*,那么您可以通过常规方式完成此操作。

const char* cstring = static_cast<const char *>(buffer);

这是有效的,因为您可以将void *转换为您想要的任何内容并使用它(再次假设您知道基础类型)。将void转换为其他类型后,const是一个const指针是无关紧要的。保留{{1}}部分是个好主意,因为这是一个不会改变数据的承诺。