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

with_side_effects() should provide ability to inspect arguments passed to a mocked function #295

Open
Kamil2000 opened this issue May 3, 2022 · 2 comments

Comments

@Kamil2000
Copy link

The with_side_effects() should create the constrain that allows user to browse the arguments of a function.
This could be relatively easily achieved by just passing a second argument to a user callback.

Expected feature:
void user_callback(void* data, Arguments* args) {
// here it is possible to inspect/interact with args
}

//using cb
expect(mocked_function, with_side_effect(&user_callback, &unimportant));

Such change should be backward-compatible, because same thing
was used by GTK+ extensively:
// old code, most important thing is that gtk_main_quit
// declares no parameters, receives two
// and despite all of this works like a charm.
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);

@thoni56
Copy link
Contributor

thoni56 commented May 13, 2022

This is a great idea!

I'm not familiar enough with GTK to see how they get away with this. Just calling a function/macro with more arguments than it has declared will surely fire error messages from most C compilers.

Or am I misunderstanding you? I would appreciate a more detailed sketch of how this would look.

@Kamil2000
Copy link
Author

Ok, I will try to explain this whole C function pointers magic above:

The most important thing is to handle two
function signatures with a one macro. This can be done
with little bit of casting. Take a look at this trivial program:
#include <stdio.h>

typedef void (*Func2)(int, int);
typedef void (*Func1)(int);
void func(void) {
printf("LaLa\n");
}
int main()
{
Func2 func2 = (Func2)&func;
Func1 func1 = (Func1)&func;
func2(4,5);
func1(5);
return 0;
}

It will compile and run on any platform. However, this doesn't mean this
is a C-compilant program, because standard doesn't define
such calls at any point.

For more information please visit:
https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
As one reply suggest, this is technically undefined behavior., but the second
one suggests that whole GNOME framework depends upon it, because of ABI
compatibility.

After some reconsideration I figured out we might use some other,
more standard C tricks to handle two types with a single macro.
In C11 there is a _Generic macro, which can be useful:
#include <stdio.h>

typedef void (*FuncA)(void);
typedef void (*FuncB)(int);

void funcA(void) {
printf("LaLa\n");
}
void funcB(int unused) {
(void)unused;
printf("TaTa\n");
}
void callA(FuncA a) {
a();
}
void callB(FuncB b) {
b(0);
}
#define CALL(x) _Generic(x, FuncA: callA, default: callB)(x)

int main()
{
CALL(funcA);
CALL(funcB);
return 0;
}

I personally like the second approach more sue to standard compliance
and cleaner error messages. If that approach is to be chosen sth like
with_parametrized_side_effects needs to be provided for for
older C versions.

Hope all is clear by now ;)

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

2 participants