You are not logged in.
Hello, everyone,
I'm writing a small unit testing library for myself for various C projects I've got on the go at the moment. Right now, it just consists of one function which accepts an array of tests (structs) and runs each one. The problem is that the array seems to disappear once I pass it in to the library function.
The library's only test code at the moment is:
#include "test.h"
enum TestResult testPass();
enum TestResult testFail();
int main()
{
struct Test tests[] = {
{"pass", testPass},
{"fail", testFail},
};
testRun(tests);
return 0;
}
enum TestResult testPass()
{
return PASS;
}
enum TestResult testFail()
{
return FAIL;
}
test.h:
#ifndef TEST_H
#define TEST_H
enum TestResult
{
PASS,
FAIL,
};
struct Test
{
char* name;
enum TestResult (*test)();
};
void testRun(struct Test*);
#endif /* TEST_H */
And test.c, which compiles to libtest.so:
#include <stdio.h>
#include "test.h"
#define ARRAY_LENGTH(array) ((int) (sizeof(array) / sizeof(*array)))
void testRun(struct Test* tests)
{
enum TestResult result;
int i;
for(i = 0; i < ARRAY_LENGTH(tests); i++)
if((result = tests[i].test()) == PASS)
fprintf(stderr, ".");
else if(result == FAIL)
fprintf(stderr, "F");
else
fprintf(stderr, "?");
fprintf(stderr, "\n");
}
I get a single newline as output for running the test code. (that last fprintf() call). In other words, ARRAY_LENGTH(tests) == 0.
I've tried several different ways of making the array accessible to the library, including making an extern variable in test.h (couldn't use the automatic array sizing declaration), making a static variable in test.c and initializing it with a function (the array still disappeared), and just passing it in to the function, as shown. What am I overlooking? The way I figure, an array is a pointer, meaning they (arrays) are always passed by reference, and I can therefore declare testRun() as taking a struct Test* without any using any complicated data structures to preserve the contents and make the client interface as simple as possible.
Last edited by Michael C. (2010-04-10 21:28:02)
Offline
I would pass a pointer to the first element of the array and an integer with the length of the array.
Offline
Your ARRAY_LENGTH macro doesn't work. You can't compute the size of an array dynamically with such a macro.
In fact ARRAY_LENGTH will be replaced at compile time:
sizeof(array) will be replaced by 4, because array is a pointer (assuming you're on a 32bits),
sizeof(*array) by the size of an element, which is 8.
So sizeof(array) / sizeof(*array) == 4 / 8 == 0.
As wuischke said, you should give to testRun the size of your array, like this:
void testRun(struct Test* tests, size_t tests_len);
Offline
Another widely used way of doing it, without having to pass the size, is to use null-terminated arrays.
You probably know that strings are null-terminated arrays of characters?
Well you can do the same with arrays that you define.
You would have something like:
struct Test tests[] = {
{"pass", testPass},
{"fail", testFail},
{NULL, NULL},
};
Then instead of using the size of the array, you just loop on its elements until you have the null element, then break.
You just have to make sure you always put this null element at the end of your arrays. And that the null element is really a null element, I mean you can choose anything but of course it shouldn't be a possible normal value of the array.
Offline
Thank you, everyone. Your solutions worked perfectly. I ended up using the NULL-terminated array approach, as it seemed to present the simplest interface.
Offline