2019-04-14 11:16:55 +02:00
|
|
|
/*
|
|
|
|
|
* Tests for Basic Functionality
|
|
|
|
|
*
|
|
|
|
|
* This runs same basic verification that each feature does what we expect it
|
|
|
|
|
* to do. More elaborate tests and/or stress-tests are not included here.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#undef NDEBUG
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/eventfd.h>
|
|
|
|
|
#include "c-stdaux.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Tests for all remaining helpers
|
|
|
|
|
*/
|
|
|
|
|
static void test_misc(int non_constant_expr) {
|
|
|
|
|
int foo;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test the C_EXPR_ASSERT() macro to work in static and non-static
|
|
|
|
|
* environments, and evaluate exactly to its passed expression.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
static int v = C_EXPR_ASSERT(1, true, "");
|
|
|
|
|
|
|
|
|
|
c_assert(v == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test stringify/concatenation helpers. Also make sure to test that
|
|
|
|
|
* the passed arguments are evaluated first, before they're stringified
|
|
|
|
|
* and/or concatenated.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
#define TEST_TOKEN foobar
|
|
|
|
|
c_assert(!strcmp("foobar", C_STRINGIFY(foobar)));
|
|
|
|
|
c_assert(!strcmp("foobar", C_STRINGIFY(TEST_TOKEN)));
|
|
|
|
|
c_assert(!strcmp("foobar", C_STRINGIFY(C_CONCATENATE(foo, bar))));
|
|
|
|
|
c_assert(!strcmp("foobarfoobar", C_STRINGIFY(C_CONCATENATE(TEST_TOKEN, foobar))));
|
|
|
|
|
c_assert(!strcmp("foobarfoobar", C_STRINGIFY(C_CONCATENATE(foobar, TEST_TOKEN))));
|
|
|
|
|
#undef TEST_TOKEN
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test tuple expansion. This is used to strip tuple-wrappers in the
|
|
|
|
|
* pre-processor.
|
|
|
|
|
* We make sure that it works with {0,1,2}-tuples, as well as only
|
|
|
|
|
* strips a single layer.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* strcmp() might be a macro, so make sure we get a proper C
|
|
|
|
|
* expression below. Otherwise, C_EXPAND() cannot be used that
|
|
|
|
|
* way (since it would evaluate to a single macro argument).
|
|
|
|
|
*/
|
|
|
|
|
int (*f) (const char *, const char *) = strcmp;
|
|
|
|
|
|
|
|
|
|
c_assert(!f(C_EXPAND(()) "foobar", "foo" "bar"));
|
|
|
|
|
c_assert(!f(C_EXPAND(("foobar")), "foo" "bar"));
|
|
|
|
|
c_assert(!f(C_EXPAND(("foobar", "foo" "bar"))));
|
|
|
|
|
c_assert(!f C_EXPAND((("foobar", "foo" "bar"))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test C_VAR() macro. It's sole purpose is to create a valid C
|
|
|
|
|
* identifier given a single argument (which itself must be a valid
|
|
|
|
|
* identifier).
|
|
|
|
|
* Just test that we can declare variables with it and use it in
|
|
|
|
|
* expressions.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
int C_VAR(sub, UNIQUE) = 5;
|
|
|
|
|
/* make sure the variable name does not clash */
|
|
|
|
|
int sub = 12, subUNIQUE = 12, UNIQUEsub = 12;
|
|
|
|
|
|
|
|
|
|
c_assert(7 + C_VAR(sub, UNIQUE) == sub);
|
|
|
|
|
c_assert(sub == subUNIQUE);
|
|
|
|
|
c_assert(sub == UNIQUEsub);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Make sure both produce different names, even though they're
|
|
|
|
|
* exactly the same expression.
|
|
|
|
|
*/
|
|
|
|
|
_c_unused_ int C_VAR(sub, __COUNTER__), C_VAR(sub, __COUNTER__);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
/* verify C_VAR() with single argument works line-based */
|
|
|
|
|
int C_VAR(sub); C_VAR(sub) = 5; c_assert(C_VAR(sub) == 5);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
/* verify C_VAR() with no argument works line-based */
|
|
|
|
|
int C_VAR(); C_VAR() = 5; c_assert(C_VAR() == 5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test array-size helper. This simply computes the number of elements
|
|
|
|
|
* of an array, instead of the binary size.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int bar[8];
|
|
|
|
|
|
|
|
|
|
static_assert(C_ARRAY_SIZE(bar) == 8, "");
|
|
|
|
|
c_assert(__builtin_constant_p(C_ARRAY_SIZE(bar)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test decimal-representation calculator. Make sure it is
|
|
|
|
|
* type-independent and just uses the size of the type to calculate how
|
|
|
|
|
* many bytes are needed to print that integer in decimal form. Also
|
|
|
|
|
* verify that it is a constant expression.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
static_assert(C_DECIMAL_MAX(char) == 4, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(signed char) == 4, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(unsigned char) == 4, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(unsigned long) == (sizeof(long) == 8 ? 21 : 11), "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(unsigned long long) == 21, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(int32_t) == 11, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(uint32_t) == 11, "");
|
|
|
|
|
static_assert(C_DECIMAL_MAX(uint64_t) == 21, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_container_of(). We cannot test for type-safety, nor for
|
|
|
|
|
* other invalid uses, as they'd require negative compile-testing.
|
|
|
|
|
* However, we can test that the macro yields the correct values under
|
|
|
|
|
* normal use.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
struct foobar {
|
|
|
|
|
int a;
|
|
|
|
|
char b;
|
|
|
|
|
} sub = {};
|
|
|
|
|
|
|
|
|
|
c_assert(&sub == c_container_of(&sub.a, struct foobar, a));
|
|
|
|
|
c_assert(&sub == c_container_of(&sub.b, struct foobar, b));
|
|
|
|
|
c_assert(&sub == c_container_of((const char *)&sub.b, struct foobar, b));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test min/max macros. Especially check that macro arguments are never
|
|
|
|
|
* evaluated multiple times, and if both arguments are constant, the
|
|
|
|
|
* return value is constant as well.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
foo = 0;
|
|
|
|
|
c_assert(c_max(1, 5) == 5);
|
|
|
|
|
c_assert(c_max(-1, 5) == 5);
|
|
|
|
|
c_assert(c_max(-1, -5) == -1);
|
|
|
|
|
c_assert(c_max(foo++, -1) == 0);
|
|
|
|
|
c_assert(foo == 1);
|
|
|
|
|
c_assert(c_max(foo++, foo++) > 0);
|
|
|
|
|
c_assert(foo == 3);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_max(1, 5)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_max(1, non_constant_expr)));
|
|
|
|
|
|
|
|
|
|
foo = 0;
|
|
|
|
|
c_assert(c_min(1, 5) == 1);
|
|
|
|
|
c_assert(c_min(-1, 5) == -1);
|
|
|
|
|
c_assert(c_min(-1, -5) == -5);
|
|
|
|
|
c_assert(c_min(foo++, 1) == 0);
|
|
|
|
|
c_assert(foo == 1);
|
|
|
|
|
c_assert(c_min(foo++, foo++) > 0);
|
|
|
|
|
c_assert(foo == 3);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_min(1, 5)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_min(1, non_constant_expr)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_less_by(), c_clamp(). Make sure they
|
|
|
|
|
* evaluate arguments exactly once, and yield a constant expression,
|
|
|
|
|
* if all arguments are constant.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
foo = 8;
|
|
|
|
|
c_assert(c_less_by(1, 5) == 0);
|
|
|
|
|
c_assert(c_less_by(5, 1) == 4);
|
|
|
|
|
c_assert(c_less_by(foo++, 1) == 7);
|
|
|
|
|
c_assert(foo == 9);
|
|
|
|
|
c_assert(c_less_by(foo++, foo++) >= 0);
|
|
|
|
|
c_assert(foo == 11);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_less_by(1, 5)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_less_by(1, non_constant_expr)));
|
|
|
|
|
|
|
|
|
|
foo = 8;
|
|
|
|
|
c_assert(c_clamp(foo, 1, 5) == 5);
|
|
|
|
|
c_assert(c_clamp(foo, 9, 20) == 9);
|
|
|
|
|
c_assert(c_clamp(foo++, 1, 5) == 5);
|
|
|
|
|
c_assert(foo == 9);
|
|
|
|
|
c_assert(c_clamp(foo++, foo++, foo++) >= 0);
|
|
|
|
|
c_assert(foo == 12);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_clamp(0, 1, 5)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_clamp(1, 0, non_constant_expr)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Div Round Up: Normal division, but round up to next integer, instead
|
|
|
|
|
* of clipping. Also verify that it does not suffer from the integer
|
2020-07-04 11:37:01 +03:00
|
|
|
* overflow in the prevalent, alternative implementation:
|
2019-04-14 11:16:55 +02:00
|
|
|
* [(x + y - 1) / y].
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
#define TEST_ALT_DIV(_x, _y) (((_x) + (_y) - 1) / (_y))
|
|
|
|
|
foo = 8;
|
|
|
|
|
c_assert(c_div_round_up(0, 5) == 0);
|
|
|
|
|
c_assert(c_div_round_up(1, 5) == 1);
|
|
|
|
|
c_assert(c_div_round_up(5, 5) == 1);
|
|
|
|
|
c_assert(c_div_round_up(6, 5) == 2);
|
|
|
|
|
c_assert(c_div_round_up(foo++, 1) == 8);
|
|
|
|
|
c_assert(foo == 9);
|
|
|
|
|
c_assert(c_div_round_up(foo++, foo++) >= 0);
|
|
|
|
|
c_assert(foo == 11);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_div_round_up(1, 5)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_div_round_up(1, non_constant_expr)));
|
|
|
|
|
|
|
|
|
|
/* alternative calculation is [(x + y - 1) / y], but it may overflow */
|
|
|
|
|
for (i = 0; i <= 0xffff; ++i) {
|
|
|
|
|
for (j = 1; j <= 0xff; ++j)
|
|
|
|
|
c_assert(c_div_round_up(i, j) == TEST_ALT_DIV(i, j));
|
|
|
|
|
for (j = 0xff00; j <= 0xffff; ++j)
|
|
|
|
|
c_assert(c_div_round_up(i, j) == TEST_ALT_DIV(i, j));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make sure it doesn't suffer from high overflow */
|
|
|
|
|
c_assert(UINT32_C(0xfffffffa) % 10 == 0);
|
|
|
|
|
c_assert(UINT32_C(0xfffffffa) / 10 == UINT32_C(429496729));
|
|
|
|
|
c_assert(c_div_round_up(UINT32_C(0xfffffffa), 10) == UINT32_C(429496729));
|
|
|
|
|
c_assert(TEST_ALT_DIV(UINT32_C(0xfffffffa), 10) == 0); /* overflow */
|
|
|
|
|
|
|
|
|
|
c_assert(UINT32_C(0xfffffffd) % 10 == 3);
|
|
|
|
|
c_assert(UINT32_C(0xfffffffd) / 10 == UINT32_C(429496729));
|
|
|
|
|
c_assert(c_div_round_up(UINT32_C(0xfffffffd), 10) == UINT32_C(429496730));
|
|
|
|
|
c_assert(TEST_ALT_DIV(UINT32_C(0xfffffffd), 10) == 0);
|
|
|
|
|
#undef TEST_ALT_DIV
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Align to multiple of: Test the alignment macro. Check that it does
|
|
|
|
|
* not suffer from incorrect integer overflows, neither should it
|
|
|
|
|
* exceed the boundaries of the input type.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0), 1) == 0);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0), 2) == 0);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0), 4) == 0);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0), 8) == 0);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(1), 8) == 8);
|
|
|
|
|
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0xffffffff), 8) == 0);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0xfffffff1), 8) == 0xfffffff8);
|
|
|
|
|
c_assert(c_align_to(UINT32_C(0xfffffff1), 8) == 0xfffffff8);
|
|
|
|
|
|
|
|
|
|
c_assert(__builtin_constant_p(c_align_to(16, 8)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_align_to(non_constant_expr, 8)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_align_to(16, non_constant_expr)));
|
|
|
|
|
c_assert(!__builtin_constant_p(c_align_to(16, non_constant_expr ? 8 : 16)));
|
|
|
|
|
c_assert(__builtin_constant_p(c_align_to(16, 7 + 1)));
|
|
|
|
|
c_assert(c_align_to(15, non_constant_expr ? 8 : 16) == 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_assert(). Make sure side-effects are always evaluated, and
|
|
|
|
|
* variables are marked as used regardless of NDEBUG.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int v1 = 0, v2 = 0;
|
|
|
|
|
|
|
|
|
|
#define NDEBUG 1
|
|
|
|
|
c_assert(!v1);
|
|
|
|
|
if (v1)
|
|
|
|
|
abort();
|
|
|
|
|
c_assert(++v1);
|
|
|
|
|
if (v1 != 1)
|
|
|
|
|
abort();
|
|
|
|
|
#undef NDEBUG
|
|
|
|
|
c_assert(!v2);
|
|
|
|
|
if (v2)
|
|
|
|
|
abort();
|
|
|
|
|
c_assert(++v2);
|
|
|
|
|
if (v2 != 1)
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_errno(). Simply verify that the correct value is returned. It
|
|
|
|
|
* must always be >0 and equivalent to `errno' if set.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
c_assert(c_errno() > 0);
|
|
|
|
|
|
|
|
|
|
close(-1);
|
|
|
|
|
c_assert(c_errno() == errno);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
c_assert(c_errno() != errno);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Tests for:
|
|
|
|
|
* - c_free*()
|
|
|
|
|
* - c_close*()
|
|
|
|
|
* - c_fclose*()
|
|
|
|
|
* - c_closedir*()
|
|
|
|
|
*/
|
|
|
|
|
static void test_destructors(void) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Verify that c_free*() works as expected. Since we want to support
|
|
|
|
|
* running under valgrind, there is no easy way to verify the
|
|
|
|
|
* correctness of free(). Hence, we simply rely on valgrind to catch
|
|
|
|
|
* the leaks.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
|
|
|
_c_cleanup_(c_freep) void *foo;
|
|
|
|
|
_c_cleanup_(c_freep) int **bar; /* supports any type */
|
|
|
|
|
size_t sz = 128 * 1024;
|
|
|
|
|
|
|
|
|
|
foo = malloc(sz);
|
|
|
|
|
c_assert(foo);
|
|
|
|
|
|
|
|
|
|
bar = malloc(sz);
|
|
|
|
|
c_assert(bar);
|
|
|
|
|
bar = c_free(bar);
|
|
|
|
|
c_assert(!bar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c_assert(c_free(NULL) == NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_close*(), rely on sparse FD allocation. Make sure all the
|
|
|
|
|
* helpers actually close the fd, and cope fine with negative numbers.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
fd = eventfd(0, EFD_CLOEXEC);
|
|
|
|
|
c_assert(fd >= 0);
|
|
|
|
|
|
|
|
|
|
/* verify c_close() returns -1 */
|
|
|
|
|
c_assert(c_close(fd) == -1);
|
|
|
|
|
|
|
|
|
|
/* verify c_close() deals fine with negative fds */
|
|
|
|
|
c_assert(c_close(-1) == -1);
|
|
|
|
|
c_assert(c_close(-16) == -1);
|
|
|
|
|
|
|
|
|
|
/* make sure c_closep() deals fine with negative FDs */
|
|
|
|
|
{
|
|
|
|
|
_c_cleanup_(c_closep) int t = 0;
|
|
|
|
|
t = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure the c_close() earlier worked, by allocating the
|
|
|
|
|
* FD again and relying on the same FD number to be reused. Do
|
|
|
|
|
* this twice, to verify that the c_closep() in the cleanup
|
|
|
|
|
* path works as well.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < 2; ++i) {
|
|
|
|
|
_c_cleanup_(c_closep) int t = -1;
|
|
|
|
|
|
|
|
|
|
t = eventfd(0, EFD_CLOEXEC);
|
|
|
|
|
c_assert(t >= 0);
|
|
|
|
|
c_assert(t == fd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test c_fclose() and c_fclosep(). This uses the same logic as the
|
|
|
|
|
* tests for c_close() (i.e., sparse FD allocation).
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
FILE *f;
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
fd = eventfd(0, EFD_CLOEXEC);
|
|
|
|
|
c_assert(fd >= 0);
|
|
|
|
|
|
|
|
|
|
f = fdopen(fd, "r");
|
|
|
|
|
c_assert(f);
|
|
|
|
|
|
|
|
|
|
/* verify c_fclose() returns NULL */
|
|
|
|
|
f = c_fclose(f);
|
|
|
|
|
c_assert(!f);
|
|
|
|
|
|
|
|
|
|
/* verify c_fclose() deals fine with NULL */
|
|
|
|
|
c_assert(!c_fclose(NULL));
|
|
|
|
|
|
|
|
|
|
/* make sure c_flosep() deals fine with NULL */
|
|
|
|
|
{
|
|
|
|
|
_c_cleanup_(c_fclosep) FILE *t = (void *)0xdeadbeef;
|
|
|
|
|
t = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure the c_fclose() earlier worked, by allocating the
|
|
|
|
|
* FD again and relying on the same FD number to be reused. Do
|
|
|
|
|
* this twice, to verify that the c_fclosep() in the cleanup
|
|
|
|
|
* path works as well.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < 2; ++i) {
|
|
|
|
|
_c_cleanup_(c_fclosep) FILE *t = NULL;
|
|
|
|
|
int tfd;
|
|
|
|
|
|
|
|
|
|
tfd = eventfd(0, EFD_CLOEXEC);
|
|
|
|
|
c_assert(tfd >= 0);
|
|
|
|
|
c_assert(tfd == fd); /* the same as before */
|
|
|
|
|
|
|
|
|
|
t = fdopen(tfd, "r");
|
|
|
|
|
c_assert(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
|
test_misc(argc);
|
|
|
|
|
test_destructors();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|