The following changes since commit aae515f4e1cb0b3c003e127200d344d807032a79: io_uring: Enable io_uring ioengine on aarch64 arch (2019-12-25 08:02:57 -0700) are available in the Git repository at: git://git.kernel.dk/fio.git master for you to fetch changes up to 235b09b68d9bbc5150891faca47f5397d7e806bb: Merge branch 'master' of https://github.com/bvanassche/fio (2020-01-03 21:00:17 -0700) ---------------------------------------------------------------- Bart Van Assche (9): Micro-optimize __load_ioengine() Suppress a Coverity taint warning in check_status_file() Makefile: Build more test code Use CLOCK_MONOTONIC for condition variables used by pthread_cond_timedwait() t/read-to-pipe-async: Use the monotonic clock when measuring time intervals Fix a potential deadlock in helper_do_stat() .appveyor.yml: Convert to ASCII Only build t/read-to-pipe-async if pread() is available Improve the pthread_condattr_setclock() test Jens Axboe (5): Merge branch 'unit1' of https://github.com/kusumi/fio Merge branch 'master' of https://github.com/bvanassche/fio Revert "Fix a potential deadlock in helper_do_stat()" Merge branch 'master' of https://github.com/kenbarr1/fio Merge branch 'master' of https://github.com/bvanassche/fio Ken Barr (1): io_u: fix rate limiting to handle file wrap-around Tomohiro Kusumi (2): unittests: add unittest suite for oslib/strcasestr.c unittests: add unittest suite for oslib/strsep.c .appveyor.yml | 2 +- Makefile | 11 +++++ configure | 45 ++++++++++++++++++ fio_sem.c | 11 +++-- helper_thread.c | 17 ++++--- idletime.c | 16 ++++++- io_u.c | 2 +- ioengines.c | 11 ++--- pshared.c | 9 ++++ stat.c | 3 ++ t/read-to-pipe-async.c | 68 +++++++++++++++++---------- unittests/oslib/strcasestr.c | 87 +++++++++++++++++++++++++++++++++++ unittests/oslib/strsep.c | 107 +++++++++++++++++++++++++++++++++++++++++++ unittests/unittest.c | 2 + unittests/unittest.h | 2 + 15 files changed, 348 insertions(+), 45 deletions(-) create mode 100644 unittests/oslib/strcasestr.c create mode 100644 unittests/oslib/strsep.c --- Diff of recent changes: diff --git a/.appveyor.yml b/.appveyor.yml index f6934096..4fb0a90d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -14,7 +14,7 @@ environment: install: - '%CYG_ROOT%\setup-x86_64.exe --quiet-mode --no-shortcuts --only-site --site "%CYG_MIRROR%" --packages "mingw64-%PACKAGE_ARCH%-zlib,mingw64-%PACKAGE_ARCH%-CUnit" > NUL' - - SET PATH=C:\Python38-x64;%CYG_ROOT%\bin;%PATH% #Â NB: Changed env variables persist to later sections + - SET PATH=C:\Python38-x64;%CYG_ROOT%\bin;%PATH% # NB: Changed env variables persist to later sections - python.exe -m pip install scipy build_script: diff --git a/Makefile b/Makefile index 4a07fab3..dd26afca 100644 --- a/Makefile +++ b/Makefile @@ -313,6 +313,13 @@ T_TEST_PROGS += $(T_GEN_RAND_PROGS) T_PROGS += $(T_BTRACE_FIO_PROGS) T_PROGS += $(T_DEDUPE_PROGS) T_PROGS += $(T_VS_PROGS) +T_TEST_PROGS += $(T_MEMLOCK_PROGS) +ifdef CONFIG_PREAD +T_TEST_PROGS += $(T_PIPE_ASYNC_PROGS) +endif +ifneq (,$(findstring Linux,$(CONFIG_TARGET_OS))) +T_TEST_PROGS += $(T_IOU_RING_PROGS) +endif PROGS += $(T_PROGS) @@ -322,10 +329,14 @@ UT_OBJS += unittests/lib/memalign.o UT_OBJS += unittests/lib/strntol.o UT_OBJS += unittests/oslib/strlcat.o UT_OBJS += unittests/oslib/strndup.o +UT_OBJS += unittests/oslib/strcasestr.o +UT_OBJS += unittests/oslib/strsep.o UT_TARGET_OBJS = lib/memalign.o UT_TARGET_OBJS += lib/strntol.o UT_TARGET_OBJS += oslib/strlcat.o UT_TARGET_OBJS += oslib/strndup.o +UT_TARGET_OBJS += oslib/strcasestr.o +UT_TARGET_OBJS += oslib/strsep.o UT_PROGS = unittests/unittest else UT_OBJS = diff --git a/configure b/configure index a1279693..3a675a46 100755 --- a/configure +++ b/configure @@ -704,6 +704,28 @@ if compile_prog "" "$LIBS" "posix_pshared" ; then fi print_config "POSIX pshared support" "$posix_pshared" +########################################## +# POSIX pthread_condattr_setclock() probe +if test "$pthread_condattr_setclock" != "yes" ; then + pthread_condattr_setclock="no" +fi +cat > $TMPC <<EOF +#include <pthread.h> +int main(void) +{ + pthread_condattr_t condattr; + pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); + return 0; +} +EOF +if compile_prog "" "$LIBS" "pthread_condattr_setclock" ; then + pthread_condattr_setclock=yes +elif compile_prog "" "$LIBS -lpthread" "pthread_condattr_setclock" ; then + pthread_condattr_setclock=yes + LIBS="$LIBS -lpthread" +fi +print_config "pthread_condattr_setclock()" "$pthread_condattr_setclock" + ########################################## # solaris aio probe if test "$solaris_aio" != "yes" ; then @@ -1091,6 +1113,23 @@ if compile_prog "" "" "fdatasync"; then fi print_config "fdatasync" "$fdatasync" +########################################## +# pread() probe +if test "$pread" != "yes" ; then + pread="no" +fi +cat > $TMPC << EOF +#include <unistd.h> +int main(int argc, char **argv) +{ + return pread(0, NULL, 0, 0); +} +EOF +if compile_prog "" "" "pread"; then + pread="yes" +fi +print_config "pread()" "$pread" + ########################################## # sync_file_range() probe if test "$sync_file_range" != "yes" ; then @@ -2456,6 +2495,9 @@ fi if test "$posix_pshared" = "yes" ; then output_sym "CONFIG_PSHARED" fi +if test "$pthread_condattr_setclock" = "yes" ; then + output_sym "CONFIG_PTHREAD_CONDATTR_SETCLOCK" +fi if test "$have_asprintf" = "yes" ; then output_sym "CONFIG_HAVE_ASPRINTF" fi @@ -2471,6 +2513,9 @@ fi if test "$fdatasync" = "yes" ; then output_sym "CONFIG_FDATASYNC" fi +if test "$pread" = "yes" ; then + output_sym "CONFIG_PREAD" +fi if test "$sync_file_range" = "yes" ; then output_sym "CONFIG_SYNC_FILE_RANGE" fi diff --git a/fio_sem.c b/fio_sem.c index 3b48061c..c34d8bf7 100644 --- a/fio_sem.c +++ b/fio_sem.c @@ -85,16 +85,19 @@ static bool sem_timed_out(struct timespec *t, unsigned int msecs) int fio_sem_down_timeout(struct fio_sem *sem, unsigned int msecs) { - struct timeval tv_s; struct timespec base; struct timespec t; int ret = 0; assert(sem->magic == FIO_SEM_MAGIC); - gettimeofday(&tv_s, NULL); - base.tv_sec = t.tv_sec = tv_s.tv_sec; - base.tv_nsec = t.tv_nsec = tv_s.tv_usec * 1000; +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &t); +#else + clock_gettime(CLOCK_REALTIME, &t); +#endif + + base = t; t.tv_sec += msecs / 1000; t.tv_nsec += ((msecs * 1000000ULL) % 1000000000); diff --git a/helper_thread.c b/helper_thread.c index f0c717f5..eba2898a 100644 --- a/helper_thread.c +++ b/helper_thread.c @@ -78,15 +78,16 @@ static void *helper_thread_main(void *data) { struct helper_data *hd = data; unsigned int msec_to_next_event, next_log, next_ss = STEADYSTATE_MSEC; - struct timeval tv; struct timespec ts, last_du, last_ss; int ret = 0; sk_out_assign(hd->sk_out); - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif memcpy(&last_du, &ts, sizeof(ts)); memcpy(&last_ss, &ts, sizeof(ts)); @@ -101,9 +102,11 @@ static void *helper_thread_main(void *data) pthread_mutex_lock(&hd->lock); pthread_cond_timedwait(&hd->cond, &hd->lock, &ts); - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif if (hd->reset) { memcpy(&last_du, &ts, sizeof(ts)); diff --git a/idletime.c b/idletime.c index 2f59f510..fc1df8e9 100644 --- a/idletime.c +++ b/idletime.c @@ -186,6 +186,7 @@ void fio_idle_prof_init(void) int i, ret; struct timespec ts; pthread_attr_t tattr; + pthread_condattr_t cattr; struct idle_prof_thread *ipt; ipc.nr_cpus = cpus_online(); @@ -194,6 +195,13 @@ void fio_idle_prof_init(void) if (ipc.opt == IDLE_PROF_OPT_NONE) return; + ret = pthread_condattr_init(&cattr); + assert(ret == 0); +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); + assert(ret == 0); +#endif + if ((ret = pthread_attr_init(&tattr))) { log_err("fio: pthread_attr_init %s\n", strerror(ret)); return; @@ -239,7 +247,7 @@ void fio_idle_prof_init(void) break; } - if ((ret = pthread_cond_init(&ipt->cond, NULL))) { + if ((ret = pthread_cond_init(&ipt->cond, &cattr))) { ipc.status = IDLE_PROF_STATUS_ABORT; log_err("fio: pthread_cond_init %s\n", strerror(ret)); break; @@ -282,7 +290,11 @@ void fio_idle_prof_init(void) pthread_mutex_lock(&ipt->init_lock); while ((ipt->state != TD_EXITED) && (ipt->state!=TD_INITIALIZED)) { - fio_gettime(&ts, NULL); +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif ts.tv_sec += 1; pthread_cond_timedwait(&ipt->cond, &ipt->init_lock, &ts); } diff --git a/io_u.c b/io_u.c index b5c31335..4a0c725a 100644 --- a/io_u.c +++ b/io_u.c @@ -644,7 +644,7 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) uint64_t now; assert(ddir_rw(ddir)); - now = utime_since_now(&td->start); + now = utime_since_now(&td->epoch); /* * if rate_next_io_time is in the past, need to catch up to rate diff --git a/ioengines.c b/ioengines.c index 9e3fcc9f..b9200ba9 100644 --- a/ioengines.c +++ b/ioengines.c @@ -121,18 +121,15 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td, return ops; } -static struct ioengine_ops *__load_ioengine(const char *name) +static struct ioengine_ops *__load_ioengine(const char *engine) { - char engine[64]; - - snprintf(engine, sizeof(engine), "%s", name); - /* * linux libaio has alias names, so convert to what we want */ if (!strncmp(engine, "linuxaio", 8)) { - dprint(FD_IO, "converting ioengine name: %s -> libaio\n", name); - strcpy(engine, "libaio"); + dprint(FD_IO, "converting ioengine name: %s -> libaio\n", + engine); + engine = "libaio"; } dprint(FD_IO, "load ioengine %s\n", engine); diff --git a/pshared.c b/pshared.c index 74812ede..21192556 100644 --- a/pshared.c +++ b/pshared.c @@ -21,6 +21,15 @@ int cond_init_pshared(pthread_cond_t *cond) return ret; } #endif + +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); + if (ret) { + log_err("pthread_condattr_setclock: %s\n", strerror(ret)); + return ret; + } +#endif + ret = pthread_cond_init(cond, &cattr); if (ret) { log_err("pthread_cond_init: %s\n", strerror(ret)); diff --git a/stat.c b/stat.c index 05663e07..e2bc8ddb 100644 --- a/stat.c +++ b/stat.c @@ -2123,6 +2123,9 @@ static int check_status_file(void) } if (temp_dir == NULL) temp_dir = "/tmp"; +#ifdef __COVERITY__ + __coverity_tainted_data_sanitize__(temp_dir); +#endif snprintf(fio_status_file_path, sizeof(fio_status_file_path), "%s/%s", temp_dir, FIO_STATUS_FILE); diff --git a/t/read-to-pipe-async.c b/t/read-to-pipe-async.c index ebdd8f10..69799336 100644 --- a/t/read-to-pipe-async.c +++ b/t/read-to-pipe-async.c @@ -20,6 +20,7 @@ * Copyright (C) 2016 Jens Axboe * */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -100,13 +101,13 @@ struct work_item { static struct reader_thread reader_thread; static struct writer_thread writer_thread; -uint64_t utime_since(const struct timeval *s, const struct timeval *e) +uint64_t utime_since(const struct timespec *s, const struct timespec *e) { long sec, usec; uint64_t ret; sec = e->tv_sec - s->tv_sec; - usec = e->tv_usec - s->tv_usec; + usec = (e->tv_nsec - s->tv_nsec) / 1000; if (sec > 0 && usec < 0) { sec--; usec += 1000000; @@ -218,12 +219,12 @@ static void add_lat(struct stats *s, unsigned int us, const char *name) static int write_work(struct work_item *work) { - struct timeval s, e; + struct timespec s, e; ssize_t ret; - gettimeofday(&s, NULL); + clock_gettime(CLOCK_MONOTONIC, &s); ret = write(STDOUT_FILENO, work->buf, work->buf_size); - gettimeofday(&e, NULL); + clock_gettime(CLOCK_MONOTONIC, &e); assert(ret == work->buf_size); add_lat(&work->writer->s, utime_since(&s, &e), "write"); @@ -269,13 +270,13 @@ static void *writer_fn(void *data) static void reader_work(struct work_item *work) { - struct timeval s, e; + struct timespec s, e; ssize_t ret; size_t left; void *buf; off_t off; - gettimeofday(&s, NULL); + clock_gettime(CLOCK_MONOTONIC, &s); left = work->buf_size; buf = work->buf; @@ -294,7 +295,7 @@ static void reader_work(struct work_item *work) buf += ret; } - gettimeofday(&e, NULL); + clock_gettime(CLOCK_MONOTONIC, &e); add_lat(&work->reader->s, utime_since(&s, &e), "read"); @@ -461,8 +462,17 @@ static void show_latencies(struct stats *s, const char *msg) static void init_thread(struct thread_data *thread) { - pthread_cond_init(&thread->cond, NULL); - pthread_cond_init(&thread->done_cond, NULL); + pthread_condattr_t cattr; + int ret; + + ret = pthread_condattr_init(&cattr); + assert(ret == 0); +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); + assert(ret == 0); +#endif + pthread_cond_init(&thread->cond, &cattr); + pthread_cond_init(&thread->done_cond, &cattr); pthread_mutex_init(&thread->lock, NULL); pthread_mutex_init(&thread->done_lock, NULL); thread->exit = 0; @@ -479,12 +489,14 @@ static void exit_thread(struct thread_data *thread, pthread_mutex_lock(&thread->done_lock); if (fn) { - struct timeval tv; struct timespec ts; - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec + 1; - ts.tv_nsec = tv.tv_usec * 1000ULL; +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif + ts.tv_sec++; pthread_cond_timedwait(&thread->done_cond, &thread->done_lock, &ts); fn(wt); @@ -562,7 +574,8 @@ static void prune_done_entries(struct writer_thread *wt) int main(int argc, char *argv[]) { - struct timeval s, re, we; + pthread_condattr_t cattr; + struct timespec s, re, we; struct reader_thread *rt; struct writer_thread *wt; unsigned long rate; @@ -570,6 +583,7 @@ int main(int argc, char *argv[]) size_t bytes; off_t off; int fd, seq; + int ret; if (parse_options(argc, argv)) return 1; @@ -605,13 +619,19 @@ int main(int argc, char *argv[]) seq = 0; bytes = 0; - gettimeofday(&s, NULL); + ret = pthread_condattr_init(&cattr); + assert(ret == 0); +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); + assert(ret == 0); +#endif + + clock_gettime(CLOCK_MONOTONIC, &s); while (sb.st_size) { struct work_item *work; size_t this_len; struct timespec ts; - struct timeval tv; prune_done_entries(wt); @@ -627,14 +647,16 @@ int main(int argc, char *argv[]) work->seq = ++seq; work->writer = wt; work->reader = rt; - pthread_cond_init(&work->cond, NULL); + pthread_cond_init(&work->cond, &cattr); pthread_mutex_init(&work->lock, NULL); queue_work(rt, work); - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000ULL; +#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif ts.tv_nsec += max_us * 1000ULL; if (ts.tv_nsec >= 1000000000ULL) { ts.tv_nsec -= 1000000000ULL; @@ -651,10 +673,10 @@ int main(int argc, char *argv[]) } exit_thread(&rt->thread, NULL, NULL); - gettimeofday(&re, NULL); + clock_gettime(CLOCK_MONOTONIC, &re); exit_thread(&wt->thread, prune_done_entries, wt); - gettimeofday(&we, NULL); + clock_gettime(CLOCK_MONOTONIC, &we); show_latencies(&rt->s, "READERS"); show_latencies(&wt->s, "WRITERS"); diff --git a/unittests/oslib/strcasestr.c b/unittests/oslib/strcasestr.c new file mode 100644 index 00000000..19a2de37 --- /dev/null +++ b/unittests/oslib/strcasestr.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 Tomohiro Kusumi <tkusumi@xxxxxxxxxx> + */ +#include "../unittest.h" + +#ifndef CONFIG_STRCASESTR +#include "../../oslib/strcasestr.h" +#else +#include <string.h> +#endif + +static void test_strcasestr_1(void) +{ + const char *haystack = "0123456789"; + const char *p; + + p = strcasestr(haystack, "012"); + CU_ASSERT_EQUAL(p, haystack); + + p = strcasestr(haystack, "12345"); + CU_ASSERT_EQUAL(p, haystack + 1); + + p = strcasestr(haystack, "1234567890"); + CU_ASSERT_EQUAL(p, NULL); + + p = strcasestr(haystack, ""); + CU_ASSERT_EQUAL(p, haystack); /* is this expected ? */ +} + +static void test_strcasestr_2(void) +{ + const char *haystack = "ABCDEFG"; + const char *p; + + p = strcasestr(haystack, "ABC"); + CU_ASSERT_EQUAL(p, haystack); + + p = strcasestr(haystack, "BCD"); + CU_ASSERT_EQUAL(p, haystack + 1); + + p = strcasestr(haystack, "ABCDEFGH"); + CU_ASSERT_EQUAL(p, NULL); + + p = strcasestr(haystack, ""); + CU_ASSERT_EQUAL(p, haystack); /* is this expected ? */ +} + +static void test_strcasestr_3(void) +{ + const char *haystack = "ABCDEFG"; + const char *p; + + p = strcasestr(haystack, "AbC"); + CU_ASSERT_EQUAL(p, haystack); + + p = strcasestr(haystack, "bCd"); + CU_ASSERT_EQUAL(p, haystack + 1); + + p = strcasestr(haystack, "AbcdEFGH"); + CU_ASSERT_EQUAL(p, NULL); + + p = strcasestr(haystack, ""); + CU_ASSERT_EQUAL(p, haystack); /* is this expected ? */ +} + +static struct fio_unittest_entry tests[] = { + { + .name = "strcasestr/1", + .fn = test_strcasestr_1, + }, + { + .name = "strcasestr/2", + .fn = test_strcasestr_2, + }, + { + .name = "strcasestr/3", + .fn = test_strcasestr_3, + }, + { + .name = NULL, + }, +}; + +CU_ErrorCode fio_unittest_oslib_strcasestr(void) +{ + return fio_unittest_add_suite("oslib/strcasestr.c", NULL, NULL, tests); +} diff --git a/unittests/oslib/strsep.c b/unittests/oslib/strsep.c new file mode 100644 index 00000000..7f645f40 --- /dev/null +++ b/unittests/oslib/strsep.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2019 Tomohiro Kusumi <tkusumi@xxxxxxxxxx> + */ +#include "../unittest.h" + +#ifndef CONFIG_STRSEP +#include "../../oslib/strsep.h" +#else +#include <string.h> +#endif + +/* + * strsep(3) - "If *stringp is NULL, the strsep() function returns NULL and does + * nothing else." + */ +static void test_strsep_1(void) +{ + char *string = NULL; + const char *p; + + p = strsep(&string, ""); + CU_ASSERT_EQUAL(p, NULL); + CU_ASSERT_EQUAL(string, NULL); + + p = strsep(&string, "ABC"); + CU_ASSERT_EQUAL(p, NULL); + CU_ASSERT_EQUAL(string, NULL); +} + +/* + * strsep(3) - "In case no delimiter was found, the token is taken to be the + * entire string *stringp, and *stringp is made NULL." + */ +static void test_strsep_2(void) +{ + char src[] = "ABCDEFG"; + char *string = src; + const char *p; + + p = strsep(&string, ""); + CU_ASSERT_EQUAL(p, src); + CU_ASSERT_EQUAL(*p, 'A'); + CU_ASSERT_EQUAL(string, NULL); + + string = src; + p = strsep(&string, "@"); + CU_ASSERT_EQUAL(p, src); + CU_ASSERT_EQUAL(*p, 'A'); + CU_ASSERT_EQUAL(string, NULL); +} + +/* + * strsep(3) - "This token is terminated with a '\0' character (by overwriting + * the delimiter) and *stringp is updated to point past the token." + */ +static void test_strsep_3(void) +{ + char src[] = "ABCDEFG"; + char *string = src; + const char *p; + + p = strsep(&string, "ABC"); + CU_ASSERT_EQUAL(p, &src[0]); + CU_ASSERT_EQUAL(*p, '\0'); + CU_ASSERT_EQUAL(strcmp(string, "BCDEFG"), 0); + CU_ASSERT_EQUAL(*string, 'B'); + + p = strsep(&string, "ABC"); + CU_ASSERT_EQUAL(p, &src[1]); + CU_ASSERT_EQUAL(*p, '\0'); + CU_ASSERT_EQUAL(strcmp(string, "CDEFG"), 0); + CU_ASSERT_EQUAL(*string, 'C'); + + p = strsep(&string, "ABC"); + CU_ASSERT_EQUAL(p, &src[2]); + CU_ASSERT_EQUAL(*p, '\0'); + CU_ASSERT_EQUAL(strcmp(string, "DEFG"), 0); + CU_ASSERT_EQUAL(*string, 'D'); + + p = strsep(&string, "ABC"); + CU_ASSERT_EQUAL(p, &src[3]); + CU_ASSERT_EQUAL(*p, 'D'); + CU_ASSERT_EQUAL(string, NULL); +} + +static struct fio_unittest_entry tests[] = { + { + .name = "strsep/1", + .fn = test_strsep_1, + }, + { + .name = "strsep/2", + .fn = test_strsep_2, + }, + { + .name = "strsep/3", + .fn = test_strsep_3, + }, + { + .name = NULL, + }, +}; + +CU_ErrorCode fio_unittest_oslib_strsep(void) +{ + return fio_unittest_add_suite("oslib/strsep.c", NULL, NULL, tests); +} diff --git a/unittests/unittest.c b/unittests/unittest.c index 1166e6ef..66789e4f 100644 --- a/unittests/unittest.c +++ b/unittests/unittest.c @@ -62,6 +62,8 @@ int main(void) fio_unittest_register(fio_unittest_lib_strntol); fio_unittest_register(fio_unittest_oslib_strlcat); fio_unittest_register(fio_unittest_oslib_strndup); + fio_unittest_register(fio_unittest_oslib_strcasestr); + fio_unittest_register(fio_unittest_oslib_strsep); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); diff --git a/unittests/unittest.h b/unittests/unittest.h index d3e3822f..bbc49613 100644 --- a/unittests/unittest.h +++ b/unittests/unittest.h @@ -22,5 +22,7 @@ CU_ErrorCode fio_unittest_lib_memalign(void); CU_ErrorCode fio_unittest_lib_strntol(void); CU_ErrorCode fio_unittest_oslib_strlcat(void); CU_ErrorCode fio_unittest_oslib_strndup(void); +CU_ErrorCode fio_unittest_oslib_strcasestr(void); +CU_ErrorCode fio_unittest_oslib_strsep(void); #endif