views:

119

answers:

4

Hi all, I am working with a unit-testing suite that hijacks function calls and tests expected output values.

The normal layout requires one block of unit-testing code for each expected value.

Since my code makes use of a large number of enums, I would like to automate the automated-testing with some for loop / macro magic, and I'm looking for some advice with writing it.

Here is a block of the test code that I need to duplicate X number of times:

START_TEST("test_CallbackFn");

EXPECTED_CALLS("{{function1(param_type)#default}{function2(param_type)#default}}");

CallbackFn();

END_CALLS();
END_TEST();

Now, here is what I would envision occuring

for (int i = 0; i < 10; i++)
{
  RUN_TEST(i)
}

Now, I would like to define RUN_TEST with the code I mentioned above, except I need to replace the string default with the current value of i. What is throwing me off is the quotes and #'s that are present in the existing EXPECTED_CALLS macro.

+2  A: 

I think I would look at using a separate macro processor rather than trying to beat the C preprocessor into submission. The classic example that people point to is m4, but for this, you might do better with awk or perl or python or something similar.

Jonathan Leffler
Agreed, we use python to generate a lot of the boiler plate C code from config files - we could probably do it all with templates now but it's nice to be able to see what code is actually generated before it dissapears into the compiler
Martin Beckett
A: 

I'm not sure I fully understand the question, but if you want EXPECTED_CALLS to recieve a string where default is replaced with the string value of whatever default is you need to remove the #default from the string. i.e.

EXPECTED_CALLS("{{function1(param_type)#default}{function2(param_type)#default}}"); 

should be

EXPECTED_CALLS("{{function1(param_type)"#default"}{function2(param_type)"#default"}}"); 
torak
+2  A: 

In my experiences, "complex" + "macro" = "don't do it!"

The C preprocessor was not designed to do anything this powerful. While you may be able to do some kung-fu and hack something together that works, it would be much easier to use a scripting language to generate the C code for you (it's also easier to debug since you can read through the generated code and make sure it is correct). Personally, I have used Ruby to do this several times but Python, Perl, bash (etc etc) should also work.

bta
A: 

It's probably possible: Boost.Preprocessor is quite impressive as it is.

For an enum it may be a bit more difficult, but there are for each loops in Boost.Preprocessor, etc..

The problem of the generative approach using external scripts is that it may require to externalize more than just the tests. Unless you plan on implementing a C++ parser which is known to be tricky at the best of times...

So you would need to generate the enums (store them in json for exemple) to be able to generate the tests for these enums afterward... and things begin to get hairy :/

Matthieu M.