I declare a function
void MyFunction(const std::wstring& inParameter, std::wstring& outParamater);
The first parameter is a passed in parameter, the second one is the value out parameter, the value I want to get by the function will pass it out by outParameter.
Now I Gmock it
MOCK_METHOD2(MyFunction, void(const std::wstring&, std::wstring&));
However, when I use this mock function:
std::wstring firstStr = L"firstStr";
std::wstring test = L"test";
EXPECT_CALL(*myGmockInstance, MyFunction(firstStr, _)).Times(1).WillOnce(DoAll(firstStr, SetArgReferee<1>(test)));
It doesn't work.
I also tried
EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(_, SetArgReferee<1>(test)));
or
EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(firstStr, SetArgReferee<1>(test)));
or
EXPECT_CALL(*myGmockInstance, MyFunction(_, _)).Times(1).WillOnce(DoAll(SetArgReferee<0>(firstStr), SetArgReferee<1>(test)));
I understand that the inParameter is const, so I cannot use SetArgReferee for it. But how to set its value and at the same time I can set value for outParameter?
I think that the title of your question is quite misleading. From what I understand, you just want to assign some arbitrary value to your function's second argument (the output argument). This is how you can do it using Invoke:
using ::testing::_;
void assignStringToArg(const std::wstring&, std::wstring& outputStr,
const std::wstring expectedStr) {
outputStr = expectedStr;
}
class SomeMock {
public:
MOCK_METHOD2(MyFunction, void(const std::wstring&, std::wstring&));
};
TEST(xxx, yyy) {
SomeMock someMock;
std::wstring firstStr(L"aaabbbccc");
std::wstring secondStr(L"I should change upon MyFunction call ...");
std::wstring expectedSecondStr(L"xxxyyyzzz");
EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(Invoke(std::bind(
&assignStringToArg,
std::placeholders::_1,
std::placeholders::_2,
expectedSecondStr)));
someMock.MyFunction(firstStr, secondStr);
ASSERT_EQ(expectedSecondStr, secondStr);
}
Note that the function provided to Invoke must have the same signature as the function that you expect to be called (that's why I use bind). You can achieve the same result using google macro ACTION_P. I prefer to use Invoke only because it looks more clean to me.
Since your case is rather simple, you can also do it using SetArgReferee like you tried before:
EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(
SetArgReferee<1>(L"something"));
someMock.MyFunction(firstStr, secondStr);
ASSERT_EQ(L"something", secondStr);
I just see no point using DoAll if you only want to do one action. But ... if you really insist:
EXPECT_CALL(someMock, MyFunction(firstStr, _)).Times(1).WillOnce(
DoAll(SetArgReferee<1>(L"something1"), SetArgReferee<1>(L"something2")));
someMock.MyFunction(firstStr, secondStr);
ASSERT_EQ(L"something2", secondStr);
It is rather stupid example, because it set's the output variable to L"something1" and then immediately to L"something2".
Related
I hope there is an easier way to do this... I need to capture the string which is passed as an argument to a mock.
The mock
class web_api_mock : public iweb_api
{
public:
MOCK_METHOD(
(bool),
http_post,
(const etl_normal_string &, const char*),
(override));
};
I want to capture the char * passed to the mock as second argument. I need to construct some json structure from it, and I want to check if a certain element has a certain value.
I had to spend a lot of time to get it to work, eventually copying the trick from here. This brilliant mind figured out you can rely on the gmock's Invoke.
The EXPECT_CALL
http_post_args args;
EXPECT_CALL(_web_api_mock, http_post(etl_string_equals(url), _))
.WillOnce(
DoAll(
Invoke(&args, &http_post_args::capture),
Return(true)));
Here I am invoking all arguments of the mock to a struct which I defined as follows
struct http_post_args
{
void capture(etl_normal_string url, const char * p)
{
payload = std::string(p);
}
std::string payload;
};
And finally, I get my hands on the char * and do whatever I want afterwards.
It seems awfully complicated to save an argument when it's of the type char *.
My first attempt was the obvious mistake I guess many before (and after) me made: using the SaveArgPointee which will copy only the first element of the string and gives me with a string where the first character is correct, but the remaining string is filled with random mem.
My second attempt was to define an ACTION_P. This "almost" worked. In the callstack I could see the string I am interested in until the very last stackframe, where the args simply seem not to be passed to the actual implementation of my custom ACTION_P.
ACTION_P2(capture_string, url, payload)
{
/* if I break in the debugger, and go 1 stackframe up,
I can see that gmock holds my string in varargs as second element
But I couldn't find a way to access it here*/
}
I also tried the ACTION_TEMPLATE but I am not c++ enough to understand what they are trying to explain me on gmock cookbook.
So my final question: is the above working trick with http_post_args struct really "the only way" to capture a const char * being passed as an argument to a mock?
If it SHOULD be possible using ACTION_P or ACTION_TEMPLATE would somebody be so kind to provide an actual working example with a const char *?
You could simply use a lambda, like so (live example):
TEST(SomeTest, Foo)
{
std::string payload;
web_api_mock m;
EXPECT_CALL(m, http_post(Eq("url"), _))
.WillOnce([&](const std::string &, const char* p){
payload = p;
return true;
});
m.http_post("url", "foo string");
EXPECT_THAT(payload, Eq("foo string"));
}
No additional http_post_args or actions etc required.
Of course, you could also change the payload to a const char* if you want to "capture" the raw char pointer. But be careful with the lifetime of the pointed to characters, in this case.
You hinted that your real code will need to parse the payload string as json and check for a certain element. It might lead to more readable tests when you create a dedicated matcher that does this. To show a rough draft (live example):
MATCHER_P(ContainsJsonElement, expectedElement, "")
{
const char * payload = arg;
// Parse payload as json, check for element, etc.
const bool foundElement = std::string(payload) == expectedElement;
return foundElement;
}
TEST(SomeTest, Foo)
{
web_api_mock m;
EXPECT_CALL(m, http_post(Eq("url"), ContainsJsonElement("foo string")));
m.http_post("url", "foo string");
}
EDIT:
I have modified the example API so it better reflects the real API I am dealing with. The way the API get's the message argument passed to it is by user input so the message argument cannot be used to pass additional data.
I am dealing with a very frustrating API that uses callback routines that don't take "void* userarg" pointers.
Assuming the function that uses the callback routine as defined by the API expects a string argument (that will be assigned by user input), is there ANY possible way to get more data into my callback routine without using global variables?
Here is a simplified example of what the API might look like:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// ASSUME EVERYTHING IN THIS SECTION IS PART OF AN API AND IS NOT MY OWN CODE...
// I DO NOT HAVE THE SOURCE AND IT CANNOT BE MODIFIED
typedef void (*CALLBACK)(string message);
void call_callback(CALLBACK cb) {
// Gets a message from user input
string message = "hello"; // pretend this is user input
cb(message);
}
////////////////////////////////////////////////////////////////////////////////
int data = 42;
void callback_function(string message) {
// I want to access "data" here WITHOUT it being global
cout << message << ' ' << data << endl;
}
int main(int argc, char** argv) {
call_callback(&callback_function);
}
Typically an API that uses callbacks would also pass a "void* userarg" argument into the callback routine so you could pass additional data of any type, but that is not the case here.
This API is used extensively throughout our whole codebase and it is 100% necessary to pass a lot more data in every case where it is used. The current way we get more data in *prepare to cringe* is by storing practically all of our data in singletons so nearly everything is global and can be accessed from literally anywhere in the program.
This whole concept seems EVIL to me, but without a better API I can't figure out any better way to get the data into the callback. I have already contacted the vendor and asked that they fix their API to make it accept a "void* userarg" argument, but it doesn't look like it will be fixed anytime in the near future...
All I am hoping for is ANY better way of doing things than we are now.
If it is really an std::string which is an argument to the callback (and not something else) and you really have access to the argument (as in your sample code which invokes call_callback with supplied string) you can put an entity-serialized pointer to your allocated object into std::string (which is allowed to have arbitrary data in it) and invoke call_callback with it.
One challenge here would be the fact that you'd than have to manually manage this pointer.
My most straightforward idea would be to provide unique strings in place of the void* you would normally expect. You'd then have one map singleton that maps the strings to your callbacks.
So something like this:
class Dispatcher
{
public:
// TODO: Thread safety etc.
std::string makeCallback(std::function<void()> callback)
{
std::string uid = std::to_string(_index);
_callbacks[uid] = std::move(callback);
_index++;
return uid;
}
void runCallback(std::string uid)
{
_callbacks[uid]();
}
private:
size_t _index = 0;
std::map<std::string, std::function<void()>> _callbacks;
};
void leaveAPI(std::string uid)
{
getSingleton<Dispatcher>()->runCallback(uid);
}
void enterAPI(std::function<void()> userCallback)
{
std::string uid = getSingleton<Dispatcher>()->makeCallback(userCallback);
call_callback(leaveAPI, uid);
}
Demo
You just count up a number every time you call the API and use its string version as the callback parameter. The class also maps each of those strings to the callback you wanted called. You could remove the map entries or do any number of performance optimizations, but this is the gist of it.
(This would work just as well with const char* if you figure out the ownership/lifetime questions that it opens.)
You should really petition the writers of the API to use std::function instead of raw pointers to functions.
Then you can easily use e.g. std::bind or lambda expressions to be able to call functions taking more arguments than the callback takes.
For example:
// The callback is a function taking one string argument, and return nothing
using CALLBACK = std::function<void(std::string)>;
// Do some processing and then call the callback function
void call_callback(CALLBACK cb, std::string message)
{
// ...
cb(message);
}
// Our callback takes a string *and* an integer argument
void callback_function(std::string message, int data)
{
std::cout << message << ' ' << data << '\n';
}
int main()
{
int local_data = 42;
// Using std::bind...
using namespace std::placeholders; // for _1, _2, _3...
call_callback(std::bind(&callback_function, _1, local_data), "Foobar");
// Using lambdas...
call_callback([local_data](std::string message)
{
callback_function(message, local_data);
}, "Foobar");
}
Using std::function also makes it easy to use member functions as callbacks as well, not only non-member functions (or static member functions).
However, if you can't modify the API, or the creator of it won't change it and it have to use C-style plain pointers to non-member functions, you can still solve it with lambdas, but you can't have any captures for the lambda:
call_callback([/*empty!*/](std::string message)
{
// Call the function as defined in the previous snippet
callback_function(message, 42); // Pass the value directly
}, "Foobar");
Say that you define a callback function as such:
typedef std::function<void(float)> Callback;
And you have a function as such:
void ImAFunction(float a)
{
//Do something with a
}
Is there a way to be able to store a function without an argument then pass one to it at a later time?
Such as this:
//Define the Callback storage
Callback storage;
storage = std::bind(ImAFunction, this);
//Do some things
storage(5);
This wont work which I explain with some of my real code below.
I can get close to what I wan't if I bind the value in with the std::bind function. Such as:
//Change
//storage = std::bind(ImAFunction, this);
storage = std::bind(ImAFunction, this, 5.0); //5.0 is a float passed
This works but when I go to pass a value through the function the outcome is whatever I set it to before:
storage(100); //Output is still 5
I am basing the fact that I think this is possible on this article.
http://www.cprogramming.com/tutorial/function-pointers.html
It doesn't use the function or bind functions but it does pass pointer arguments and performs exactly what I need. The reason I don't just skip the bind function is because I am trying to store the function in a class (private) and I can't store it if it's a template because it's created with the class.
The error produced above comes from this code:
struct BindInfo {
Callback keyCallback;
int bindType;
bool isDown;
bool held;
std::string name;
};
template <class T1>
void bindEvent(int bindType, T1* keydownObj, void(T1::*keydownF)(float), std::string name)
{
BindInfo newKeyInfo = { std::bind(keydownF, keydownObj), bindType, false, false, name };
inputBindings.insert(std::pair<int, BindInfo>(BIND_NULL, newKeyInfo));
};
The error is:
No viable conversion from '__bind<void(Main::*&)(float), Main *&>' to 'Callback' (aka 'function<void (float)>'
Is this possible? Thanks in advance.
You can include a placeholder for an unbound argument:
std::bind(&Main::ImAFunction, this, std::placeholders::_1);
If you find that a bit of a mouthful, a lambda might be more readable:
[this](float a){ImAFunction(a);}
It sounds like what you're looking for is a function pointer. While I don't have a lot of experience using them in C++ I have used them in C so: Yes, it is possible. Perhaps something like this:
void (*IAmAFunctionPointer)(float) = &IAmAFunction;
The best way to think about that line is, that IAmAFunctionPointer is a pointer (hence the *), it returns a void, and takes a float. Then later:
float a = 5;
IAmAFunctionPointer(a);
You could even design it so that the callback function is passed into the method (I assume this is what you're looking for).
void DoStuffThenCallback(float a, void (*callback)(float))
{
//DoStuff
callback(a);
}
further reading: http://www.cprogramming.com/tutorial/function-pointers.html
void printOutput(std::string text);
void printOutput(std::string& text);
Both functions print some text out to the console, but I wanted to handle each case where:
std::string testOutput = "asdf";
output->printOutput(testOutput); // Gives the error as it can use either function
In some cases I may want to:
output->printOutput("asdf"); // Only the first function can be used
Rather new to all this, is there a way I can handle this?
Pass by const reference:
void printOutput(const std::string &text);
Both forms can bind to that, and you shouldn't have to modify what you print.
Unless you're planning to modify the string passed in by reference, a single
void printOutput(std::string const& text);
will work.
Or are you hoping to do something different in each version?
I have need for a function pointer that takes two arguments and returns a string.
I would like to pass an adapter that wraps a function that takes one argument, and returns the string (i.e. discard one of the arguments).
I can trivially build my own adapter, that takes the 2 arguments, calls the wrapped function passing just the one argument through.
But I'd much rather have a simple way to create an adapter on the fly, if there is an easy way to do so in C++/boost?
Here's some details to make this a bit more concrete:
typedef boost::function<CString (int,int)> TooltipTextFn;
class MyCtrl
{
public:
MyCtrl(TooltipTextFn callback = boost::bind(&MyCtrl::GetCellText, this, _1, _2)) : m_callback(callback) { }
// QUESTION: how to trivially wrapper GetRowText to conform to TooltipTextFn by just discarding _2 ?!
void UseRowText() { m_callback = boost::bind(&MyCtrl::GetRowText, this, _1, ??); }
private:
CString GetCellText(int row, int column);
CString GetRowText(int row);
TooltipTextFn m_callback;
}
Obviously, I can supply a member that adapts GetRowText to take two arguments and only passes the first to GetRowText() itself.
But is there already a boost binder / adapter that lets me do that?
By only providing _1, it will ignore the 2nd parameter given to m_callback and call MyCtrl::GetRowText with one int parameter.
void UseRowText() { m_callback = boost::bind(&MyCtrl::GetRowText, this, _1); }
On the other hand,
void UseRowText() { m_callback = boost::bind(&MyCtrl::GetRowText, this, _2); }
is also valid, where we send the 2nd parameter passed to m_callback into the 1st parameter of MyCtrl::GetRowText.