1

I want to extend minunit to be more useful, with the macro.

#define mu_assert_equal(actual, expected) do {                                            \
  if (actual != expected) {                                                               \
    char *message = malloc(MAX_ERROR_MESSAGE_LENGTH);                                     \
    if (message == NULL) { printf("malloc failed"); exit(1); }                            \
    snprintf(message, MAX_ERROR_MESSAGE_LENGTH, "required: %s != %s, reality: %s == %lu", \
    #actual, #expected, #actual, actual);                                                 \
    return message;                                                                       \
  }                                                                                       \
} while (0)

invoked with:

mu_assert_equal(bytes_parsed, 1);

but the macro above only works for unsigned long values.

How I can I find the type of the macro arguments, and more importantly, their printf specifiers.

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 1
    this is possible with C11 generics; not possible in C99 or older – M.M Jan 16 '15 at 09:04
  • 1
    For the C11 generic solution see [this answer](http://stackoverflow.com/a/17290414/1505939), but change the descriptive strings to be the appropriate format specifier – M.M Jan 16 '15 at 09:07

2 Answers2

2

You can't, in C before C11 (which adds generics).

There's no way to compute the type of an expression in C, which is what you would need to do. If it were possible, then printf() wouldn't need to have static specifiers in the first place, more or less.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Thanks, there's a follow-up question: http://stackoverflow.com/questions/27981317/how-to-make-a-macro-return-characters-rather-than-a-string – fadedbee Jan 16 '15 at 09:56
1

Without generics, perhaps the best would be different macros for your different types:

#define mu_assert_equal(actual, expected, test, fmt) do {                                 \
  if ( test ) {                                                                           \
    char *message = malloc(MAX_ERROR_MESSAGE_LENGTH);                                     \
    if (message == NULL) { printf("malloc failed"); exit(1); }                            \
    snprintf(message, MAX_ERROR_MESSAGE_LENGTH, "required: %s != %s, reality: %s == " fmt,\
    #actual, #expected, #actual, actual);                                                 \
    return message;                                                                       \
  }                                                                                       \
} while (0)

#define mu_assert_equal_int(actual, expected) \
        mu_assert_equal(actual, expected, actual != expected, "%lu")
#define mu_assert_equal_str(actual, expected) \
        mu_assert_equal(actual, expected, strcmp( actual, expected ), "%s")

and invoke as:

mu_assert_equal_str( test_str, "abcde" ) ;
mu_assert_equal_int( test_int, 12345 ) ;

(Edited in light of comment to also pass the test to the "generic" test).

TripeHound
  • 2,721
  • 23
  • 37
  • `mu_assert_equal_str` has a bug - it just compares the memory addresses of strings - whereas what is usually needed is a strcmp/strncmp to compare their content. – fadedbee Jan 23 '15 at 09:44
  • You're right, sorry. I was focusing on not having to duplicate the whole macro several times. Will update. – TripeHound Jan 23 '15 at 10:26