#ifndef _UNITTEST_H
#define _UNITTEST_H 1
#include <libpmem.h>
#include <libpmemblk.h>
#include <libpmemlog.h>
#include <libpmemobj.h>
#include <libpmemcto.h>
#include <libpmempool.h>
#include <libvmem.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <setjmp.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/file.h>
#ifndef __FreeBSD__
#include <sys/mount.h>
#endif
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <dirent.h>
#include "os.h"
#include "os_thread.h"
#include "util.h"
int ut_get_uuid_str(char *);
#define UT_MAX_ERR_MSG 128
#define UT_POOL_HDR_UUID_STR_LEN 37
#define UT_POOL_HDR_UUID_GEN_FILE "/proc/sys/kernel/random/uuid"
void ut_strerror(int errnum, char *buff, size_t bufflen);
#ifdef _WIN32
static inline int ut_util_statW(const wchar_t *path,
os_stat_t *st_bufp) {
int retVal = _wstat64(path, st_bufp);
st_bufp->st_mode &= 0600;
return retVal;
}
#endif
void ut_start(const char *file, int line, const char *func,
int argc, char * const argv[], const char *fmt, ...)
__attribute__((format(printf, 6, 7)));
void ut_startW(const char *file, int line, const char *func,
int argc, wchar_t * const argv[], const char *fmt, ...)
__attribute__((format(printf, 6, 7)));
void ut_done(const char *file, int line, const char *func,
const char *fmt, ...)
__attribute__((format(printf, 4, 5)))
__attribute__((noreturn));
void ut_fatal(const char *file, int line, const char *func,
const char *fmt, ...)
__attribute__((format(printf, 4, 5)))
__attribute__((noreturn));
void ut_out(const char *file, int line, const char *func,
const char *fmt, ...)
__attribute__((format(printf, 4, 5)));
void ut_err(const char *file, int line, const char *func,
const char *fmt, ...)
__attribute__((format(printf, 4, 5)));
#ifndef _WIN32
#define START(argc, argv, ...)\
ut_start(__FILE__, __LINE__, __func__, argc, argv, __VA_ARGS__)
#else
#define START(argc, argv, ...)\
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);\
for (int i = 0; i < argc; i++) {\
argv[i] = ut_toUTF8(wargv[i]);\
if (argv[i] == NULL) {\
for (i--; i >= 0; i--)\
free(argv[i]);\
UT_FATAL("Error during arguments conversion\n");\
}\
}\
ut_start(__FILE__, __LINE__, __func__, argc, argv, __VA_ARGS__)
#endif
#define STARTW(argc, argv, ...)\
ut_startW(__FILE__, __LINE__, __func__, argc, argv, __VA_ARGS__)
#ifndef _WIN32
#define DONE(...)\
ut_done(__FILE__, __LINE__, __func__, __VA_ARGS__)
#else
#define DONE(...)\
for (int i = argc; i > 0; i--)\
free(argv[i - 1]);\
ut_done(__FILE__, __LINE__, __func__, __VA_ARGS__)
#endif
#define DONEW(...)\
ut_done(__FILE__, __LINE__, __func__, __VA_ARGS__)
#define UT_FATAL(...)\
ut_fatal(__FILE__, __LINE__, __func__, __VA_ARGS__)
#define UT_OUT(...)\
ut_out(__FILE__, __LINE__, __func__, __VA_ARGS__)
#define UT_ERR(...)\
ut_err(__FILE__, __LINE__, __func__, __VA_ARGS__)
#define UT_ASSERT_rt(cnd)\
((void)((cnd) || (ut_fatal(__FILE__, __LINE__, __func__,\
"assertion failure: %s", #cnd), 0)))
#define UT_ASSERTinfo_rt(cnd, info) \
((void)((cnd) || (ut_fatal(__FILE__, __LINE__, __func__,\
"assertion failure: %s (%s = %s)", #cnd, #info, info), 0)))
#define UT_ASSERTeq_rt(lhs, rhs)\
((void)(((lhs) == (rhs)) || (ut_fatal(__FILE__, __LINE__, __func__,\
"assertion failure: %s (0x%llx) == %s (0x%llx)", #lhs,\
(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
#define UT_ASSERTne_rt(lhs, rhs)\
((void)(((lhs) != (rhs)) || (ut_fatal(__FILE__, __LINE__, __func__,\
"assertion failure: %s (0x%llx) != %s (0x%llx)", #lhs,\
(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
#if defined(__CHECKER__)
#define UT_COMPILE_ERROR_ON(cond)
#define UT_ASSERT_COMPILE_ERROR_ON(cond)
#elif defined(_MSC_VER)
#define UT_COMPILE_ERROR_ON(cond) C_ASSERT(!(cond))
#define UT_ASSERT_COMPILE_ERROR_ON(cond) (void)(cond)
#else
#define UT_COMPILE_ERROR_ON(cond) ((void)sizeof(char[(cond) ? -1 : 1]))
#ifndef __cplusplus
#define UT_ASSERT_COMPILE_ERROR_ON(cond) UT_COMPILE_ERROR_ON(cond)
#else
#define UT_ASSERT_COMPILE_ERROR_ON(cond) UT_ASSERT_rt(!(cond))
#endif
#endif
#define UT_ASSERT(cnd)\
do {\
\
if (__builtin_constant_p(cnd))\
UT_ASSERT_COMPILE_ERROR_ON(cnd);\
UT_ASSERT_rt(cnd);\
} while (0)
#define UT_ASSERTinfo(cnd, info) \
do {\
\
if (__builtin_constant_p(cnd))\
UT_ASSERT_COMPILE_ERROR_ON(cnd);\
UT_ASSERTinfo_rt(cnd, info);\
} while (0)
#define UT_ASSERTeq(lhs, rhs)\
do {\
\
if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\
UT_ASSERT_COMPILE_ERROR_ON((lhs) == (rhs));\
UT_ASSERTeq_rt(lhs, rhs);\
} while (0)
#define UT_ASSERTne(lhs, rhs)\
do {\
\
if (__builtin_constant_p(lhs) && __builtin_constant_p(rhs))\
UT_ASSERT_COMPILE_ERROR_ON((lhs) != (rhs));\
UT_ASSERTne_rt(lhs, rhs);\
} while (0)
#define UT_ASSERTrange(ptr, start, size)\
((void)(((uintptr_t)(ptr) >= (uintptr_t)(start) &&\
(uintptr_t)(ptr) < (uintptr_t)(start) + (uintptr_t)(size)) ||\
(ut_fatal(__FILE__, __LINE__, __func__,\
"assert failure: %s (%p) is outside range [%s (%p), %s (%p))", #ptr,\
(void *)(ptr), #start, (void *)(start), #start"+"#size,\
(void *)((uintptr_t)(start) + (uintptr_t)(size))), 0)))
void *ut_malloc(const char *file, int line, const char *func, size_t size);
void *ut_calloc(const char *file, int line, const char *func,
size_t nmemb, size_t size);
void ut_free(const char *file, int line, const char *func, void *ptr);
void ut_aligned_free(const char *file, int line, const char *func, void *ptr);
void *ut_realloc(const char *file, int line, const char *func,
void *ptr, size_t size);
char *ut_strdup(const char *file, int line, const char *func,
const char *str);
void *ut_pagealignmalloc(const char *file, int line, const char *func,
size_t size);
void *ut_memalign(const char *file, int line, const char *func,
size_t alignment, size_t size);
void *ut_mmap_anon_aligned(const char *file, int line, const char *func,
size_t alignment, size_t size);
int ut_munmap_anon_aligned(const char *file, int line, const char *func,
void *start, size_t size);
#define MALLOC(size)\
ut_malloc(__FILE__, __LINE__, __func__, size)
#define CALLOC(nmemb, size)\
ut_calloc(__FILE__, __LINE__, __func__, nmemb, size)
#define ZALLOC(size)\
ut_calloc(__FILE__, __LINE__, __func__, 1, size)
#define FREE(ptr)\
ut_free(__FILE__, __LINE__, __func__, ptr)
#define ALIGNED_FREE(ptr)\
ut_aligned_free(__FILE__, __LINE__, __func__, ptr)
#define REALLOC(ptr, size)\
ut_realloc(__FILE__, __LINE__, __func__, ptr, size)
#define STRDUP(str)\
ut_strdup(__FILE__, __LINE__, __func__, str)
#define PAGEALIGNMALLOC(size)\
ut_pagealignmalloc(__FILE__, __LINE__, __func__, size)
#define MEMALIGN(alignment, size)\
ut_memalign(__FILE__, __LINE__, __func__, alignment, size)
#define MMAP_ANON_ALIGNED(size, alignment)\
ut_mmap_anon_aligned(__FILE__, __LINE__, __func__, alignment, size)
#define MUNMAP_ANON_ALIGNED(start, size)\
ut_munmap_anon_aligned(__FILE__, __LINE__, __func__, start, size)
int ut_open(const char *file, int line, const char *func, const char *path,
int flags, ...);
int ut_wopen(const char *file, int line, const char *func, const wchar_t *path,
int flags, ...);
int ut_close(const char *file, int line, const char *func, int fd);
FILE *ut_fopen(const char *file, int line, const char *func, const char *path,
const char *mode);
int ut_fclose(const char *file, int line, const char *func, FILE *stream);
int ut_unlink(const char *file, int line, const char *func, const char *path);
size_t ut_write(const char *file, int line, const char *func, int fd,
const void *buf, size_t len);
size_t ut_read(const char *file, int line, const char *func, int fd,
void *buf, size_t len);
os_off_t ut_lseek(const char *file, int line, const char *func, int fd,
os_off_t offset, int whence);
int ut_posix_fallocate(const char *file, int line, const char *func, int fd,
os_off_t offset, os_off_t len);
int ut_stat(const char *file, int line, const char *func, const char *path,
os_stat_t *st_bufp);
int ut_statW(const char *file, int line, const char *func, const wchar_t *path,
os_stat_t *st_bufp);
int ut_fstat(const char *file, int line, const char *func, int fd,
os_stat_t *st_bufp);
void *ut_mmap(const char *file, int line, const char *func, void *addr,
size_t length, int prot, int flags, int fd, os_off_t offset);
int ut_munmap(const char *file, int line, const char *func, void *addr,
size_t length);
int ut_mprotect(const char *file, int line, const char *func, void *addr,
size_t len, int prot);
int ut_ftruncate(const char *file, int line, const char *func,
int fd, os_off_t length);
#define OPEN(path, ...)\
ut_open(__FILE__, __LINE__, __func__, path, __VA_ARGS__)
#define WOPEN(path, ...)\
ut_wopen(__FILE__, __LINE__, __func__, path, __VA_ARGS__)
#define CLOSE(fd)\
ut_close(__FILE__, __LINE__, __func__, fd)
#define FOPEN(path, mode)\
ut_fopen(__FILE__, __LINE__, __func__, path, mode)
#define FCLOSE(stream)\
ut_fclose(__FILE__, __LINE__, __func__, stream)
#define UNLINK(path)\
ut_unlink(__FILE__, __LINE__, __func__, path)
#define WRITE(fd, buf, len)\
ut_write(__FILE__, __LINE__, __func__, fd, buf, len)
#define READ(fd, buf, len)\
ut_read(__FILE__, __LINE__, __func__, fd, buf, len)
#define LSEEK(fd, offset, whence)\
ut_lseek(__FILE__, __LINE__, __func__, fd, offset, whence)
#define POSIX_FALLOCATE(fd, off, len)\
ut_posix_fallocate(__FILE__, __LINE__, __func__, fd, off, len)
#define FSTAT(fd, st_bufp)\
ut_fstat(__FILE__, __LINE__, __func__, fd, st_bufp)
#define MMAP(addr, len, prot, flags, fd, offset)\
ut_mmap(__FILE__, __LINE__, __func__, addr, len, prot, flags, fd, offset);
#define MUNMAP(addr, length)\
ut_munmap(__FILE__, __LINE__, __func__, addr, length);
#define MPROTECT(addr, len, prot)\
ut_mprotect(__FILE__, __LINE__, __func__, addr, len, prot);
#define STAT(path, st_bufp)\
ut_stat(__FILE__, __LINE__, __func__, path, st_bufp)
#define STATW(path, st_bufp)\
ut_statW(__FILE__, __LINE__, __func__, path, st_bufp)
#define FTRUNCATE(fd, length)\
ut_ftruncate(__FILE__, __LINE__, __func__, fd, length)
#ifndef _WIN32
#define ut_jmp_buf_t sigjmp_buf
#define ut_siglongjmp(b) siglongjmp(b, 1)
#define ut_sigsetjmp(b) sigsetjmp(b, 1)
#else
#define ut_jmp_buf_t jmp_buf
#define ut_siglongjmp(b) longjmp(b, 1)
#define ut_sigsetjmp(b) setjmp(b)
static DWORD ErrMode;
static BOOL Suppressed = FALSE;
static UINT AbortBehave;
#endif
void ut_suppress_errmsg(void);
void ut_unsuppress_errmsg(void);
int ut_sigaction(const char *file, int line, const char *func,
int signum, struct sigaction *act, struct sigaction *oldact);
#define SIGACTION(signum, act, oldact)\
ut_sigaction(__FILE__, __LINE__, __func__, signum, act, oldact)
int ut_thread_create(const char *file, int line, const char *func,
os_thread_t *__restrict thread,
const os_thread_attr_t *__restrict attr,
void *(*start_routine)(void *), void *__restrict arg);
int ut_thread_join(const char *file, int line, const char *func,
os_thread_t *thread, void **value_ptr);
#define PTHREAD_CREATE(thread, attr, start_routine, arg)\
ut_thread_create(__FILE__, __LINE__, __func__,\
thread, attr, start_routine, arg)
#define PTHREAD_JOIN(thread, value_ptr)\
ut_thread_join(__FILE__, __LINE__, __func__, thread, value_ptr)
#ifdef _WIN32
intptr_t ut_spawnv(int argc, const char **argv, ...);
#endif
#ifndef _WIN32
#define _FUNC_REAL_DECL(name, ret_type, ...)\
ret_type __real_##name(__VA_ARGS__) __attribute__((unused));
#else
#define _FUNC_REAL_DECL(name, ret_type, ...)\
ret_type name(__VA_ARGS__);
#endif
#ifndef _WIN32
#define _FUNC_REAL(name)\
__real_##name
#else
#define _FUNC_REAL(name)\
name
#endif
#define RCOUNTER(name)\
_rcounter##name
#define FUNC_MOCK_RCOUNTER_SET(name, val)\
RCOUNTER(name) = val;
#define FUNC_MOCK(name, ret_type, ...)\
_FUNC_REAL_DECL(name, ret_type, ##__VA_ARGS__)\
static unsigned RCOUNTER(name);\
ret_type __wrap_##name(__VA_ARGS__);\
ret_type __wrap_##name(__VA_ARGS__) {\
switch (util_fetch_and_add32(&RCOUNTER(name), 1)) {
#define FUNC_MOCK_END\
}}
#define FUNC_MOCK_RUN(run)\
case run:
#define FUNC_MOCK_RUN_DEFAULT\
default:
#define FUNC_MOCK_RUN_RET(run, ret)\
case run: return (ret);
#define FUNC_MOCK_RUN_RET_DEFAULT_REAL(name, ...)\
default: return _FUNC_REAL(name)(__VA_ARGS__);
#define FUNC_MOCK_RUN_RET_DEFAULT(ret)\
default: return (ret);
#define FUNC_MOCK_RET_ALWAYS(name, ret_type, ret, ...)\
FUNC_MOCK(name, ret_type, __VA_ARGS__)\
FUNC_MOCK_RUN_RET_DEFAULT(ret);\
FUNC_MOCK_END
#define FUNC_MOCK_RET_ALWAYS_VOID(name, ...)\
FUNC_MOCK(name, void, __VA_ARGS__)\
default: return;\
FUNC_MOCK_END
extern unsigned long Ut_pagesize;
extern unsigned long long Ut_mmap_align;
extern os_mutex_t Sigactions_lock;
void ut_dump_backtrace(void);
void ut_sighandler(int);
void ut_register_sighandlers(void);
uint16_t ut_checksum(uint8_t *addr, size_t len);
char *ut_toUTF8(const wchar_t *wstr);
wchar_t *ut_toUTF16(const char *wstr);
struct test_case {
const char *name;
int (*func)(const struct test_case *tc, int argc, char *argv[]);
};
static inline const struct test_case *
get_tc(const char *name, const struct test_case *test_cases, size_t ntests)
{
for (size_t i = 0; i < ntests; i++) {
if (strcmp(name, test_cases[i].name) == 0)
return &test_cases[i];
}
return NULL;
}
static inline void
TEST_CASE_PROCESS(int argc, char *argv[],
const struct test_case *test_cases, size_t ntests)
{
if (argc < 2)
UT_FATAL("usage: %s <test case> [<args>]", argv[0]);
for (int i = 1; i < argc; i++) {
char *str_test = argv[i];
const int args_off = i + 1;
const struct test_case *tc = get_tc(str_test,
test_cases, ntests);
if (!tc)
UT_FATAL("unknown test case -- '%s'", str_test);
i += tc->func(tc, argc - args_off, &argv[args_off]);
}
}
#define TEST_CASE_DECLARE(_name)\
int \
_name(const struct test_case *tc, int argc, char *argv[])
#define TEST_CASE(_name)\
{\
.name = #_name,\
.func = _name,\
}
#define STR(x) #x
#define ASSERT_ALIGNED_BEGIN(type) do {\
size_t off = 0;\
const char *last = "(none)";\
type t;
#define ASSERT_ALIGNED_FIELD(type, field) do {\
if (offsetof(type, field) != off)\
UT_FATAL("%s: padding, missing field or fields not in order between "\
"'%s' and '%s' -- offset %lu, real offset %lu",\
STR(type), last, STR(field), off, offsetof(type, field));\
off += sizeof(t.field);\
last = STR(field);\
} while (0)
#define ASSERT_ALIGNED_CHECK(type)\
if (off != sizeof(type))\
UT_FATAL("%s: missing field or padding after '%s': "\
"sizeof(%s) = %lu, fields size = %lu",\
STR(type), last, STR(type), sizeof(type), off);\
} while (0)
#ifdef __clang__
#if __has_feature(address_sanitizer)
#define UT_DEFINE_ASAN_POISON
#endif
#else
#ifdef __SANITIZE_ADDRESS__
#define UT_DEFINE_ASAN_POISON
#endif
#endif
#ifdef UT_DEFINE_ASAN_POISON
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
#define ASAN_POISON_MEMORY_REGION(addr, size) \
__asan_poison_memory_region((addr), (size))
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
__asan_unpoison_memory_region((addr), (size))
#else
#define ASAN_POISON_MEMORY_REGION(addr, size) \
((void)(addr), (void)(size))
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
((void)(addr), (void)(size))
#endif
#ifdef __cplusplus
}
#endif
#endif