christophgysin / googlemock

Automatically exported from code.google.com/p/googlemock
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Using SetArgumentPointee with functions with return type other than void causes compile error #15

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Using gmock 1.0.0 on Ubuntu 7.04 with g++ 4.1.2

What steps will reproduce the problem?
The following program will show the problem

#include <gmock/gmock.h>
#include <memory>

using testing::_;
using testing::Return;
using testing::Action;
using testing::ActionInterface;
using testing::MakeAction;
using testing::DoAll;
using testing::SetArgumentPointee;
using testing::internal::Function;
class Foo
{
public:
  virtual bool func(int*) = 0;
};

class MockFoo : public Foo
{
public:
  MOCK_METHOD1(func, bool(int*));
};

class Bar
{
public:
  explicit Bar(Foo* pFoo) : m_pFoo(pFoo)
  {
  }

  int CallIt()
  {
    int i = 0;
    m_pFoo->func(&i);
    return i;
  }
  Foo* m_pFoo;
};

TEST(Testitout, argpointee)
{
  MockFoo foo;
  EXPECT_CALL(foo, func(_))
    .WillOnce(SetArgumentPointee<0>(5));

  Bar bar(&foo);

  EXPECT_EQ(5, bar.CallIt());
}

int main(int argc, char **argv) {

  std::cout << "Running main() from gtest_main.cc\n";
  testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}

yields the following compile error:

/home/trask/gmock/gmock-1.0.0/include/gmock/gmock-actions.h: In member
function $-1òøtypename testing::internal::Function<F>::Result
testing::PolymorphicAction<Impl>::MonomorphicImpl<F>::Perform(const
typename testing::internal::Function<F>::ArgumentTuple&) [with F = bool
()(int*), Impl = testing::internal::SetArgumentPointeeAction<0u, int,
false>]òù:
test.cpp:57:   instantiated from here
/home/trask/gmock/gmock-1.0.0/include/gmock/gmock-actions.h:373: error:
void value not ignored as it ought to be
/home/trask/gmock/gmock-1.0.0/include/gmock/gmock-actions.h: In member
function $-1òøvoid testing::internal::SetArgumentPointeeAction<N, A,
kIsProto>::Perform(const ArgumentTuple&) const [with Result = bool,
ArgumentTuple = std::tr1::tuple<int*, std::tr1::_NullClass,
std::tr1::_NullClass, std::tr1::_NullClass, std::tr1::_NullClass,
std::tr1::_NullClass, std::tr1::_NullClass, std::tr1::_NullClass,
std::tr1::_NullClass, std::tr1::_NullClass>, unsigned int N = 0u, A = int,
bool kIsProto = false]òù:
/home/trask/gmock/gmock-1.0.0/include/gmock/gmock-actions.h:373:  
instantiated from $-1òøtypename testing::internal::Function<F>::Result
testing::PolymorphicAction<Impl>::MonomorphicImpl<F>::Perform(const
typename testing::internal::Function<F>::ArgumentTuple&) [with F = bool
()(int*), Impl = testing::internal::SetArgumentPointeeAction<0u, int, 
false>]òù
test.cpp:57:   instantiated from here
/home/trask/gmock/gmock-1.0.0/include/gmock/gmock-actions.h:616: error:
invalid use of undefined type $-1òøstruct
testing::internal::CompileAssertTypesEqual<void, bool>òù
/home/trask/gmock/gmock-1.0.0/include/gmock/internal/gmock-internal-utils.h:69:
error: declaration of $-1òøstruct
testing::internal::CompileAssertTypesEqual<void, bool>òù
make: *** [test.o] Error 1

Compilation exited abnormally with code 2 at Wed Dec 24 20:51:26

What is the expected output? What do you see instead?
When I change the func to have return type void. It compiles fine.

What version of the product are you using? On what operating system?
Using gmock 1.0.0 on Ubuntu 7.04 with g++ 4.1.2

Please provide any additional information below.
I believe the culprit is the Perform function in:
template <size_t N, typename A, bool kIsProto>
class SetArgumentPointeeAction {
 public:
  // Constructs an action that sets the variable pointed to by the
  // N-th function argument to 'value'.
  explicit SetArgumentPointeeAction(const A& value) : value_(value) {}

  template <typename Result, typename ArgumentTuple>
    void Perform(const ArgumentTuple& args) const {
    CompileAssertTypesEqual<void, Result>();
    *::std::tr1::get<N>(args) = value_;
  }

 private:
  const A value_;
};

the Perform function returns void which is problem when called from 

template <typename Impl>
class PolymorphicAction {
 public:
  explicit PolymorphicAction(const Impl& impl) : impl_(impl) {}

  template <typename F>
  operator Action<F>() const {
    return Action<F>(new MonomorphicImpl<F>(impl_));
  }
 private:
  template <typename F>
  class MonomorphicImpl : public ActionInterface<F> {
   public:
    typedef typename internal::Function<F>::Result Result;
    typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;

    explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}

    virtual Result Perform(const ArgumentTuple& args) {
      return impl_.template Perform<Result>(args);
    }

   private:
    Impl impl_;
  };

  Impl impl_;
};

When I change to 
template <size_t N, typename A, bool kIsProto>
class SetArgumentPointeeAction {
 public:
  // Constructs an action that sets the variable pointed to by the
  // N-th function argument to 'value'.
  explicit SetArgumentPointeeAction(const A& value) : value_(value) {}

  template <typename Result, typename ArgumentTuple>
    Result Perform(const ArgumentTuple& args) const {
    *::std::tr1::get<N>(args) = value_;
    return Result();
  }

which works for my program but is not the final solution as it needs to
work with void return types and default values.  I am working on a more
generic solution but just wanted to submit in case I was missing something
or doing something incorrectly or someone was already working on it.

Let me know.

Thanks.

Bruce

Original issue reported on code.google.com by ecurbks...@gmail.com on 25 Dec 2008 at 2:09

GoogleCodeExporter commented 9 years ago
Was rereading the docs and see a comment in the Section Combining Actions in 
Cookbook:
It says " Only the return value of the last action in the sequence will be 
used."

So I am thinking that the only way to correctly return an output param for a 
function
that returns a non void type is to use a DoAll with the SetArgumentPointee 
first in
the list of combined actions and the Return action last.  Makes sense when I 
think
about it and having looked at the code some more I see that is how it works.  
Looks
like this is not a problem afterall.

Original comment by ecurbks...@gmail.com on 25 Dec 2008 at 4:50

GoogleCodeExporter commented 9 years ago
So my corrected code would be:
#include <gmock/gmock.h>
#include <memory>

using testing::_;
using testing::Return;
using testing::Action;
using testing::ActionInterface;
using testing::MakeAction;
using testing::DoAll;
using testing::SetArgumentPointee;
using testing::internal::Function;
class Foo
{
public:
  virtual bool func(int*) = 0;
};

class MockFoo : public Foo
{
public:
  MOCK_METHOD1(func, bool(int*));
};

class Bar
{
public:
  explicit Bar(Foo* pFoo) : m_pFoo(pFoo)
  {
  }

  int CallIt()
  {
    int i = 0;
    m_pFoo->func(&i);
    return i;
  }
  Foo* m_pFoo;
};

TEST(Testitout, argpointee)
{
  MockFoo foo;
  EXPECT_CALL(foo, func(_))
    .WillOnce(DoAll(SetArgumentPointee<0>(5),Return(true)));

  Bar bar(&foo);

  EXPECT_EQ(5, bar.CallIt());
}

int main(int argc, char **argv) {

  std::cout << "Running main() from gtest_main.cc\n";
  testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}

Original comment by ecurbks...@gmail.com on 25 Dec 2008 at 4:56

GoogleCodeExporter commented 9 years ago
This is by design.  DoAll() is the intended solution.

Original comment by shiq...@gmail.com on 26 Dec 2008 at 6:56