I use Gmock for a method call, that returns an element of the QList heightsFromCsvResult as out parameter. Here is the currently working code:
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(0)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(1)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(2)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(3)), Return(true)));
The first parameter lineNumber from
getGeometryHeightValues(int lineNumber, QPair<QString, QString>)
is the index for heightsFromCsvResult.at(lineNumber).
Now I try to use Gmock in a more generic way:
int* mockLineNumber = new int;
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.Times(4)
.WillRepeatedly(DoAll(SaveArg<0>(mockLineNumber), SetArgReferee<1>(heightsFromCsvResult.at(*(mockLineNumber))), Return(true)));
But this code does not work, because mockLineNumber is never written by Gmock. But the EXPECT_CALL is satisfied.
Does anyone see the problem in the code?
Using a variable set with SaveArg within the same EXPECT_CALL does not seem to be working, what you could do instead is to go through a custom action that sets the second argument using argument 0 as index on the passed container.
ACTION_P(SetArg1WithValueFromPassedArgumentUsingArg0AsIndex, param)
{
arg1 = param.at(arg0);
}
int* mockLineNumber = new int;
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.Times(4)
.WillRepeatedly(DoAll(SaveArg<0>(mockLineNumber), SetArg1WithValueFromPassedArgumentUsingArg0AsIndex(heightsFromCsvResult), Return(true)));
Unless you need mockLineNumber for something else you could remove that part.
Related
I am trying to figure out how to assign a message field in protobuf2 in C++. Here is a small snippet of the code.
message Sub {
optional double x = 1 [[default = 46.0];
}
message Master {
optional Sub sub_message;
}
Now when I try to initialize a Master message, I got the following error:
Master msg;
msg.mutable_sub_message() = new Sub();
error: expression is not assignable
However, the following code works, and the sub_message is set to default values:
Master msg;
msg.set_sub_message(new Sub());
Can anyone kindly explain why mutable_sub_message() can not be used for assignment?
msg.mutable_sub_message() returns a pointer to the field, i.e. a Sub*. The idea is that you use that pointer to manipulate the field as you need.
Assigning a different pointer to it wouldn't change the value inside the class, it would at most change the temporary pointer that was returned, which doesn't make sense. I guess it could be made to work if mutable_sub_message returned something like a Sub*& (not even sure that syntax is right), but that's not how the library was written.
In a more practical note, calling mutable_sub_message will initialize the subfield, you don't need to do that explicitly. That means you'd usually set a nested field using
Master msg;
msg.mutable_sub_message()->set_x(4.0);
Also, it's always safe to call getters even if a field isn't set, in that case they will always return a default instance. In other words:
double use_field(const Master& msg) {
// This is always safe, and will return the default even if
// sub_message isn't set.
return msg.sub_message().x();
}
I got an array of functions to be called later as callbacks:
std::vector<std::function<void(void*)>> callbacks;
I do need to insert different kind of functions to this vector, that's why I choose void* to be the argument.
In one of these functions I needed an int, so I did like that:
void MyObject::MyTestCb(void* params) {
int i = *(int*)params;
...
}
...
callbacks.push_back(std::bind(&MyObject::MyTestCb, this, std::placeholders::_1));
When I call those callbacks, first I tried like this:
int index = 73;
void* params = (void*)&index;
callbacks[x](params);
But sometimes I wasn't received the value in the callback function! Most of the time were obtaining zero. May it is related due to being on a 64 bits machine?
Anyway, I tried this way then:
void* params = new int(73);
callbacks[x](params);
delete params;
And after some testing I didn't find any problem at all. However, is this last way the correct way to do it? Should it support any type as argument?
I have the following code:
void MyClass::create_msg(MyTime timestamp) {
// do things here ...
}
and I tried to create a std::bind for the above function:
MyMsg MyClass::getResult(MyTime timestamp) {
// do things here ...
std::bind(create_msg(), timestamp);
// do things ...
}
But got the following error:
error: too few arguments to function call, single argument 'timestamp' was not specified
std::bind(create_msg(), timestamp);
~~~~~~~~~~ ^
MyClass.cpp:381:1: note: 'create_msg' declared here
void MyClass::create_msg(MyTime timestamp) {
^
1 error generated.
What did I do wrong in this case? Thanks!
By the way, same error if I do:
std::bind(&MyClass::create_msg(), this, timestamp);
There are three issues here.
First, the argument you're giving to std::bind as your function is currently create_msg(). This means "call create_msg, take whatever result it produces, and pass that in as the first argument to std::bind." That's not what you want - you instead meant "take create_msg and pass it as the first parameter to std::bind." Since create_msg is a member function, you'll need to get a pointer to it like this:
std::bind(&MyClass::create_msg, /* ... */)
That will address one issue, but there's another one that will then pop up. When you use std::bind with a member function pointer, you need to prove std::bind with an extra parameter corresponding to the receiver object to use when calling that member function. I believe that in your case you want the current object to be the receiver, which would look like this:
std::bind(&MyClass::create_msg, this, timestamp)
That should work properly.
However, one could argue that there's a third issue here - rather than using std::bind, why not just use a lambda expression?
[timestamp, this] { create_msg(timestamp); }
I am using Gmock in my project. I have the following mock function.
MOCK_METHOD2(helper,
bool(const std::string&, std::string*));
Goal is to set value of parameter 1 to parameter 2 for all mock calls.
I did the following.
std::string temp;
EXPECT_CALL(
MockObj,
helper(_,_))
.WillRepeatedly(
DoAll(SaveArg<0>(&temp), //Save first arg to temp
SetArgPointee<1>(temp), //assign it to second arg
Return(true)));
However I see that parameter 2 is set to the original value of tmp rather than the value saved. Is there any other way to solve this? I want to make this EXPECT_CALL dynamic rather than doing SetArgPointee<1>("testval").
Standard actions do not support what you need. You will need to write a custom matcher:
ACTION(AssignArg0ToArg1) {
*arg1 = arg0;
}
And you can then use it in combination with Return(true). More information on custom actions can be found at https://github.com/google/googlemock/blob/master/googlemock/docs/DesignDoc.md.
I need to register a member function using luabind which is supposed to take a lua-function as parameter. For any normal function I would usually just do this:
int SomeLuaFunction(lua_State *l)
{
luaL_checkfunction(l,1);
int fc = luaL_ref(l,LUA_REGISTRYINDEX);
[...]
}
Luabind however uses the parameter list, so I'm unsure how to tell it I'm expecting a function:
void Lua_ALSound_CallOnStateChanged(lua_State *l,boost::shared_ptr<ALSound> pAl,<function-parameter?>)
{
[...]
}
lua_bind(luabind::class_<ALSound COMMA boost::shared_ptr<ALSound>>("ALSound")
.def("CallOnStateChanged",&Lua_ALSound_CallOnStateChanged)
);
(Only the relevant part of the code is shown here, lua_bind is using luabind::module)
lua-example of what I'm trying to accomplish:
local al = ALSound() -- I'm aware this wouldn't work since I haven't defined a constructor
al:CallOnStateChanged(function()
[...]
end)
Perhaps there is a way to add additional functions to an already registered class without luabind? Any suggestions would be appreciated.
If you want to be able to have a function that takes Lua objects as parameters, you should have the function take a luabind::object as a parameter. Then you can check to see if it's a function and call it if it is.