假设我有一个带有签名的模拟函数,如下所示
class MyMock
{
MOCK_METHOD4( f, void( X, Iterator begin, Iterator end, Y ) );
};
我想写一个EXPECT_CALL
,它可以在序列{{1}}上使用ContainerEq
,ElementsAre
或任何其他容器匹配器。理想情况下类似于' Range'匹配器将存在,例如:
[begin, end)
有这样的事吗?我怎样才能使用允许使用所有各种容器匹配而不重写它们?
答案 0 :(得分:1)
此类IteratorRange
在大多数情况下都有效 - 限制请参阅匹配器主体:
MATCHER_P(IteratorRange, param, "")
{
auto begin = get<0>(arg);
auto end = get<1>(arg);
// these two lines might be weak point of this matcher implementation...
// I mean:
// 1. constructing vector might be not supported
// e.g. object are not copyable)
// 2. copying objects from range might "change" the tested code behavior
// e.g. copy is badly implemented
// 3. it is for sure "performance" degradation
using value_type = typename std::iterator_traits<decltype(begin)>::value_type;
std::vector<value_type> range{begin, end};
Matcher<decltype(range)> matcher = param;
return matcher.MatchAndExplain(range, result_listener);
}
可以像这样使用:
TEST(A,A)
{
int a,b,c;
std::vector<int> values{ a,b,c };
MyMock m;
EXPECT_CALL( m, f(_,_,_,_) ).With(Args<1,2>(IteratorRange(ContainerEq(values))));
m.f(X{}, values.begin(), values.end(), Y{});
}
<强> [UPDATE] 强>
克服了内部将范围复制到容器中的缺点 - 你需要发明一个轻容器 - 就像这样:
template <typename Iterator>
class RangeView
{
public:
using iterator = Iterator;
using const_iterator = Iterator;
using value_type = typename std::iterator_traits<Iterator>::value_type;
RangeView(Iterator begin, Iterator end) : beginIter(begin), endIter(end) {}
iterator begin() const { return beginIter; }
iterator end() const { return endIter; }
std::size_t size() const { return std::distance(beginIter, endIter); }
bool operator == (const RangeView& other) const
{
return size() == other.size() && std::equal(beginIter, endIter, other.beginIter);
}
private:
Iterator beginIter, endIter;
};
加上一些辅助函数,以便更容易使用此类:
template <typename Iterator>
void PrintTo(RangeView<Iterator> const& range, std::ostream* os)
{
*os << "{";
for (auto&& e: range) *os << "[" << PrintToString(e) << "]";
*os << "}";
}
template <typename Iterator>
RangeView<Iterator> makeRangeView(Iterator begin, Iterator end)
{
return RangeView<Iterator>(begin, end);
}
template <typename Container>
auto makeRangeView(Container const& container)
{
return makeRangeView(std::begin(container), std::end(container));
}
请注意,如果您在项目中使用boost - 您可以使用range from boost - 您不需要“重新发明轮子”。
然后 - 可以定义光匹配器而没有这些缺点:
MATCHER_P(IteratorRangeLight, param, "")
{
auto begin = get<0>(arg);
auto end = get<1>(arg);
auto range = makeRangeView(begin, end);
Matcher<decltype(range)> matcher = param;
return matcher.MatchAndExplain(range, result_listener);
}
然后 - 像这样使用它:
TEST(A,A)
{
int a=1,b=2,c=3;
std::vector<int> values{ a,b,c };
MyMock m;
EXPECT_CALL( m, f(_,_,_,_) ).
With(Args<1,2>(IteratorRangeLight(ContainerEq(makeRangeView(values)))));
// ^^^^^^^^^^^^^
// note that you need to use makeRangeView also within the matcher
m.f(X{}, values.begin(), values.end(), Y{});
}