-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wire up support for selftests #102
Conversation
eb1eb99
to
ad46565
Compare
26ec063
to
a041ee9
Compare
a041ee9
to
8f76ae8
Compare
2dd6ec9
to
e088b4d
Compare
e088b4d
to
926cddd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally I think this makes sense - I just had a few notes. The "how do we deal with the pointer test" I think is an interesting question. We could just accept the UB and move on, assuming that nobody's going to build clar on an AS/400. But I wonder if there's something that do that's more useful (or if I misunderstood the invalid pointer rule).
clar.c
Outdated
@@ -211,7 +211,7 @@ static void clar_abort(const char *msg, ...) | |||
va_start(argp, msg); | |||
clar_print_onabortv(msg, argp); | |||
va_end(argp); | |||
exit(-1); | |||
exit(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that probably we should define exit codes then be consistent. I don't think that this is something that we need to address in this PR, just something for us to consider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of this has been superseded with the introduction of clar_abort()
anyway, which does provide some consistency here. So there's only two cases left, and here we could think about specific error codes in a future MR indeed.
@@ -25,4 +25,9 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) | |||
if(BUILD_TESTING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is if(BUILD_TESTING)
but this is option(BUILD_TEST ...
above.
I noticed because we introduce the option(BUILD_EXAMPLE ...
below. I think we should have the option
s specified in the same place, and that we probably want BUILD_TEST
, not BUILD_TESTING
. (I would actually prefer BUILD_TESTS
and BUILD_EXAMPLES
, as plural, but I wouldn't block over that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ethomson BUILD_TESTING
is actually set up via include(CTest)
, so it is what CMake itself declares to be the official option. So personally I'd agree that BUILD_TEST
is saner, but CMake disagrees with both of us :/
But yeah, you're right, we still have the old BUILD_TESTS
in here, which has in fact been introduced via f255c0b (ci: convert to use CMake, 2024-09-05). Let me drop that.
const char *actual = "expected"; | ||
cl_assert_equal_p(actual, actual); /* pointers to same object */ | ||
cl_assert_equal_p(&actual, actual); | ||
void *p1 = (void *)0x1, *p2 = (void *)0x2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that technically this is UB. http://www.cs.man.ac.uk/~pjj/cs211/c_rationale/node12.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you refer to the following quote, right?
Since pointers and integers are now considered incommensurate, the only integer that can be safely converted to a pointer is the constant 0. The result of converting any other integer to a pointer is machine dependent.
And the following makes clear that even the comparison of invalid pointers is UB:
Regardless how an invalid pointer is created, any use of it yields undefined behavior. Even assignment, comparison with a null pointer constant, or comparison with itself, might on some systems result in an exception.
One alternative would be to use intptr_t
instead, but that's an optional extension to C99, only. So I'm inclined to just leave this as-is, as it works just fine in practice on most systems, unless you have a better idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I think that's the pragmatic approach. It is after all, the tests for the tests, so a little questionably UB behavior probably won't hurt too bad.
test/main.c
Outdated
#endif | ||
{ | ||
if (argc < 2) { | ||
fprintf(stderr, "USAGE: %s <SELFTEST_SUITE_EXECUTABLE> <OPTIONS>\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this not shout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure :)
We explicitly declare a `BUILD_TESTS` option. This option is unused as we use `BUILD_TESTING` instead, which is what the CTest module brings with it. Drop the `BUILD_TESTS` option.
When raising an error we print the current file, line and function where the error was raised. This is of course quite helpful to users, but it stands in the way of testing the clar because they make the output of executables dependent on the developer's setup. Add the ability to override these with fixed constants via a new `CLAR_SELFTEST` macro.
We use `exit(-1)` in two places. Exit codes should be in the range of [0, 255] though, so the resulting behaviour is not defined and depends on the platform. Fix this by using `exit(1)` instead.
The "%p" formatter has platform-specific behaviour. On Windows for example it prints as a zero-padded integer, whereas on glibc systems it prints as non-zero-padded integer with "0x" prepended. Address this by instead using PRIxPTR and casting the pointers to the `uintptr_t` type.
The examples are closely coupled with our selftests, which makes it hard to iterate on both. Split them out into their own standalone directory as a prerequisite for wiring up proper testing of the clar.
We are about to wire up proper testing of clar via CI. This will be done by executing the "clar_test" binary we already have in another clar test binary. This requires us to move the current "clar_test" into its own subdirectory such that "generate.py" can then generate the "clar.suite" for each of these two test binaries independently.
The global test counter has been added as a demonstration for how it is possible to modify global resources. Now that we have moved examples into their own directory though it no longer serves that purpose. In fact, it now stands in our way as we are about to introduce testing of the clar itself with various different options. But as we assert that the counter is "8" after all tests have ran, we wouldn't be able to exclude some tests from running. Drop the counter altogether to prepare for the change.
The output for the test that exercise `cl_assert_equal_p()` is indeterministic because we compare on-stack addresses, which naturally change between executions. Adapt the test to instead use fixed values.
While we have had the "clar_test" binary for a very long time already, it was more for demonstration purposes than for real testing of the clar. It could serve as sort of a smoke test if the developer remembered to execute it, but that's about it. In the preceding commits we have moved the "clar_test" into a separate directory, renamed it to "selftest_suite" and made its output deterministic. We can thus now wire up proper testing of the clar by exercising the "selftest_suite" binary via a new "selftest" binary. These tests run the "selftest_test" binary with various different arguments and check both its return code as well as its output.
Wire up support for testing in our CI now that we have proper self tests.
Rebased and addressed feedback. |
Thanks! |
Depends on CMake support added via #100.