UnitTests: Add PropertyMatcher

Extend the matcher for Properties with arguments. It is only used if
arguments are provided. The matcher argument must be always a matcher.

struct Foo
{
    int foo(int) const { return 1; }
};

TEST(X, X)
{
    Property("Foo::foo", &Foo::foo, Eq(10), 8);
}

Change-Id: If20d958dd65652f8268fc5e744220ed2ff26a0f5
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-04-17 11:39:37 +02:00
committed by Burak Hancerli
parent f3eaf3877b
commit f2342f2563
2 changed files with 87 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <gmock/gmock-matchers.h>
#include <gmock/gmock-more-matchers.h>
#include <concepts>
#include <type_traits>
namespace internal {
template<typename Property, typename Matcher, typename... Arguments>
class PropertyMatcher
{
public:
PropertyMatcher(Property property, const Matcher &matcher, Arguments... arguments)
: m_property(property)
, matcher_(matcher)
, m_whose_property()
, m_arguments{arguments...}
{}
PropertyMatcher(const std::string &whose_property,
Property property,
const Matcher &matcher,
Arguments... arguments)
: m_property(property)
, matcher_(matcher)
, m_whose_property(whose_property)
, m_arguments{arguments...}
{}
void DescribeTo(::std::ostream *os) const
{
*os << "is an object " << m_whose_property;
matcher_.DescribeTo(os);
}
void DescribeNegationTo(::std::ostream *os) const
{
*os << "is an object " << m_whose_property;
matcher_.DescribeNegationTo(os);
}
template<typename T>
bool MatchAndExplain(const T &value, testing::MatchResultListener *listener) const
{
*listener << "which points to an object ";
auto result = std::apply(
[&](auto &&...arguments) { return std::invoke(m_property, value, arguments...); },
m_arguments);
return MatchPrintAndExplain(result, matcher_, listener);
}
private:
Property m_property;
const Matcher matcher_;
const std::string m_whose_property;
const std::tuple<Arguments...> m_arguments;
};
template<typename PropertyMatcher>
concept matcher = std::derived_from<PropertyMatcher, testing::MatcherDescriberInterface>
|| requires { typename PropertyMatcher::is_gtest_matcher; };
} // namespace internal
template<typename PropertyType, internal::matcher PropertyMatcher, typename... Arguments>
inline auto Property(const std::string &propertyName,
PropertyType property,
const PropertyMatcher &matchingType,
Arguments... arguments)
// requires(sizeof...(Arguments) >= 1)
{
using namespace std::string_literals;
return testing::MakePolymorphicMatcher(
internal::PropertyMatcher<PropertyType, PropertyMatcher, Arguments...>(
"whose property `"s + propertyName + "` "s,
property,
matchingType,
std::forward<Arguments>(arguments)...));
}

View File

@@ -4,6 +4,7 @@
#pragma once
#include <gmock/gmock.h>
#include <matchers/property-matcher.h>
using testing::_;
using testing::A;