silentbicycle / greatest

A C testing library in 1 file. No dependencies, no dynamic allocation. ISC licensed.
ISC License
1.48k stars 108 forks source link

Add _FMT for every assertions? #114

Open markand opened 2 years ago

markand commented 2 years ago

Hi,

For the moment, ASSERT_GTE does only print that the assertion fails with the given argument without expansion so in a debugging purpose it's not convenient as you always have to finally add some printf's or to start debugging:

* Suite basics:
F
FAIL example: x < y (main.c:18)

On the other hand ASSERT_EQ_FMT has the opportunity to print the different by expanding their values. Shouldn't we add _FMT for every assertion macros?

I think that may clutter the number of macros but unfortunately in C we don't have a good template mechanism to print values without specifying the format string (we could use _Generic but that's limited and requires C11).

We could also use some kind of literals macros:

silentbicycle commented 2 years ago

You're right, it is convenient, but I've generally favored keeping it smaller (there's a self-imposed 1000 LOC limit guiding the design) and avoiding any non-portable constructs because I want it to be usable in any context C could be -- it's been used to drive testing of OS kernels, OS-less code running on embedded systems, etc. ASSERT_GT_FMT etc. could be implemented on top of the existing macros if you need it.

markand commented 2 years ago

I understand your point. It's just that each time I get the "x < y" message I have either to start a debugger, print the variable before the assertion (thus editing the code, which isn't handy). Maybe changing the default formatting to print those values would be a reasonable suggestion?

silentbicycle commented 2 years ago

I would be happy to, but haven't yet figured out a way to do so portably, and without evaluating the arguments multiple times like GREATEST_ASSERT_EQ_FMTm does, which been an ongoing source of bugs and misleading results when printing test output. Evaluating and saving the arguments with typeof is non-portable, unfortunately; while the macro could conditionally expand to use it when supported by the compiler, that could lead to very subtle/confusing behavior. intmax_t isn't available in C89, and that kind of numeric conversion can lead to UB, especially signed/unsigned conversion.

I'm definitely not opposed, though! If there's a way to do it portably, I would add the format string as an argument (like ASSERT_LT(x, y, "%lu")), but because that's an interface change it would have to wait for the 2.0.0 release.