Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Cannot mock recursive lambda with deducing this parameter #4549

Open
zmajeed opened this issue May 26, 2024 · 0 comments
Open

[Bug]: Cannot mock recursive lambda with deducing this parameter #4549

zmajeed opened this issue May 26, 2024 · 0 comments

Comments

@zmajeed
Copy link

zmajeed commented May 26, 2024

Describe the issue

Using MockFunction to mock a lambda function with deducing this self parameter gives a compile error with gcc 14.1 on Ubuntu 24.04

test.cpp: In member function ‘virtual void ::testing::Expr_test_1002_Test::TestBody()’:
test.cpp:975:20: error: ‘auto’ parameter not permitted in this context
  975 |   MockFunction<int(this const auto&, const Neg&)> mockNegVisit;
      |                    ^~~~~~~~~~~~~~~~
test.cpp:975:20: error: a function type cannot have an explicit object parameter
test.cpp:975:20: note: the type of an explicit object member function is a regular function type
In file included from googletest/googlemock/include/gmock/gmock-function-mocker.h:43,
                 from googletest/googlemock/include/gmock/gmock.h:58,
                 from test.cpp:14:
googletest/googlemock/include/gmock/gmock-spec-builders.h: In instantiation of ‘class testing::MockFunction<int(...)>’:
test.cpp:975:44:   required from here
test.cpp:975:20: note:   975 |   MockFunction<int(this const auto&, const Neg&)> mockNegVisit;
test.cpp:975:20: note:       |                                            ^~~~~~~~~~~~
googletest/googlemock/include/gmock/gmock-spec-builders.h:2033:7: error: invalid use of incomplete type ‘struct testing::internal::SignatureOf<int(...), void>’
 2033 | class MockFunction : public internal::MockFunction<internal::SignatureOfT<F>> {
      |       ^~~~~~~~~~~~
googletest/googlemock/include/gmock/gmock-spec-builders.h:1955:8: note: declaration of ‘struct testing::internal::SignatureOf<int(...), void>’
 1955 | struct SignatureOf;
      |        ^~~~~~~~~~~
googletest/googlemock/include/gmock/gmock-spec-builders.h:2034:9: error: invalid use of incomplete type ‘struct testing::internal::SignatureOf<int(...), void>’
 2034 |   using Base = internal::MockFunction<internal::SignatureOfT<F>>;
      |         ^~~~
googletest/googlemock/include/gmock/gmock-spec-builders.h:1955:8: note: declaration of ‘struct testing::internal::SignatureOf<int(...), void>’
 1955 | struct SignatureOf;
      |        ^~~~~~~~~~~
test.cpp: In lambda function:
test.cpp:983:20: error: ‘class testing::MockFunction<int(...)>’ has no member named ‘AsStdFunction’
  983 |       mockNegVisit.AsStdFunction(),

The code defines a recursive variant with visit lambda overloads

namespace {
struct Expr;
struct Neg {
  shared_ptr<Expr> expr;
};
struct Add {
  shared_ptr<Expr> lhs, rhs;
};
struct Mul {
  shared_ptr<Expr> lhs, rhs;
};
struct Expr: variant<int, Neg, Add, Mul> {
  using variant::variant;
};

auto intVisit = [](int i) -> int { return i; };
auto negVisit = [](this const auto& self, const Neg& n) -> int { return -visit(self, *n.expr); };
auto addVisit = [](this const auto& self, const Add& a) -> int { return visit(self, *a.lhs) + visit(self, *a.rhs); };
auto mulVisit = [](this const auto& self, const Mul& m) -> int { return visit(self, *m.lhs) * visit(self, *m.rhs); };

template<class... Ts>
struct overload: Ts... { using Ts::operator()...; };

auto evalExpr(const Expr& expr) -> int {
  return visit(overload{
    intVisit,
    negVisit,
    addVisit,
    mulVisit,
  },
  expr);
}
}

test_1001 works

TEST(Expr, test_1001) {
// 5 + 2 = 7
  EXPECT_EQ(evalExpr(Add{make_shared<Expr>(5), make_shared<Expr>(2)}), 7);
}

test_1002 fails to compile mockNegVisit though mockIntVisit without the auto self parameter works

TEST(Expr, test_1002) {
// 5 + 2 = 7
  Add a{make_shared<Expr>(5), make_shared<Expr>(2)};

  MockFunction<int(int)> mockIntVisit;
  MockFunction<int(this const auto&, const Neg&)> mockNegVisit;

  ON_CALL(mockIntVisit, Call).WillByDefault(ReturnArg<0>());

  auto evalExprMock = [&mockIntVisit, &mockNegVisit](const Expr& expr) -> int {
    return visit(overload{
      mockIntVisit.AsStdFunction(),
      mockNegVisit.AsStdFunction(),
      addVisit,
      mulVisit,
    },
    expr);
  };
  auto result = evalExprMock(a);
  EXPECT_EQ(result, 7);
}

Is there a way to mock a recursive lambda?

Steps to reproduce the problem

As above

What version of GoogleTest are you using?

latest main branch of GoogleTest repo

What operating system and version are you using?

Ubuntu 24.04

What compiler and version are you using?

GCC 14.1

What build system are you using?

CMake 3.29.3

Additional context

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant