Any advice on how to mock variadic functions like printf()?

886 views
Skip to first unread message

Nolan Hergert

unread,
Jan 6, 2021, 1:44:48 PM1/6/21
to cpputest
For my use case right now, I'm not needing to test printf() all over the place thankfully, but it's a similar style of function.

I've tried hunting around the MockActualCall.cpp and am not finding anything.

As a backup I'm going to use hard-coded getData custom variables (CHAR16 *arg1, CHAR16 *arg2, etc), but that's a really hacky patch for these things since it prevents using the same function with a variable number of different arguments and types.

Much appreciated!

Ryan Hartlage

unread,
Jan 6, 2021, 6:50:42 PM1/6/21
to cpputest
Is there any reason you can't programmatically build up the expected call as you iterate over the varargs? It seems like you should be able to save the result of mock.actualCall() in a temporary and continue to call .withParameter(...) based on the deduced type of each argument.

Ryan

--
You received this message because you are subscribed to the Google Groups "cpputest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cpputest+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cpputest/250dd406-75aa-4d1d-acc6-d961d40a8d3fn%40googlegroups.com.

Nolan Hergert

unread,
Jan 6, 2021, 10:26:22 PM1/6/21
to cpputest
That is a great first start. I have the temporary variable set up, but it looks like all the .withParameter() calls require me to know the variable name ahead of time. I think I can theoretically know the type based on the format string. Any chance I can pop off a stack somewhere?

Ryan Hartlage

unread,
Jan 7, 2021, 7:08:18 AM1/7/21
to cpputest
> but it looks like all the .withParameter() calls require me to know the variable name ahead of time

You need to give the parameter a name, but you don't necessarily need to "know" the parameter's name. All of the parameters are positional so you can "name" them positionally. For example, the first parameter can be named "1", the second parameter can be named "2", etc. The only real requirement is that the parameter names provided in the mock expected call match those provided in the mock actual call.

> I think I can theoretically know the type based on the format string. Any chance I can pop off a stack somewhere?

Yes, you'll need to use the facilities provided by stdarg.h:

Can you share more about what you're trying to do? Mocking the function directly may not be the best way to approach the problem. For example, if you're actually trying to mock printf, it may be better to forward the variadic arguments to sprintf and make the mocked call using the resulting string.

Ryan


Nolan Hergert

unread,
Jan 7, 2021, 11:49:09 AM1/7/21
to cpputest
Great, works for me!

Yep, sprintf() would work very elegantly for the "printf" scenario, agreed. In my case I'm doing a vanilla ConsolePrint(String1, String2, String3....NULL) to a console output formatter, so I don't have a sprintf() to fall back on technically. However, the positionally-named argument solution you proposed above works good enough for my case and I think simplifies CppUMock's implementation as well.

Thanks for the help!

Ryan Hartlage

unread,
Jan 7, 2021, 2:09:53 PM1/7/21
to cpputest
Great, glad I could help!

Ryan

MrMOSFET

unread,
Nov 7, 2024, 10:57:53 AM11/7/24
to cpputest
Hi, I don't mean to open an old thread but this topic is relevant.

Do you happen to have an example of how you solved this problem? I don't exactly follow your solution.

    int ioctl (int __fd, unsigned long int __request, ...) __THROW
    {
        return mock()
            .actualCall("ioctl")
            .withIntParameter("__fd", __fd)
            .withUnsignedLongIntParameter("__request", __request)
            // What to do for the varargs?
            .returnIntValue();
    }


This is my mock for "ioctl" but I have no idea how to do a "withParameter" because 1. It doesn't have a name, and 2. The type is different for different ioctl calls.

Any help would be greatly appreciated.

Bas Vodde

unread,
Nov 7, 2024, 11:03:30 AM11/7/24
to CppUTest

Hi,

I would probably use the setData interface for that, which can handle whatever key-value paid.

Bas


Ryan Hartlage

unread,
Nov 7, 2024, 11:14:10 AM11/7/24
to cppu...@googlegroups.com
It'a also possible to create named arguments that don't exist. Something like this:

if(__request == <something>) {
  return mock()
    .actualCall("ioctl")
    .withIntParameter("__fd", __fd)
    .withUnsignedLongIntParameter("__request", __request)
    .withParameter("foo", <first varargs argument>)
    .withParameter("bar", <second varargs argument>)
    ...
    .returnIntValue();
}

There's no requirement within CppUMock that your named parameters actually exist as named parameters, they just have to match between the expected and actual calls.

Ryan

James W Grenning

unread,
Nov 7, 2024, 11:21:04 AM11/7/24
to 'Bas Vodde' via cpputest

I would suggest a design change. Add an intention revealing interface for what the ioctl call is intended to do. Make an adaptor that implements the interface and does the needed ioctl. Use the adapter during production. During test, fake the intention revealing interface.

Cheers, James

Reply all
Reply to author
Forward
0 new messages