From 9c5a6f31ebff6de4c4745bd18795585e51c24c74 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 7 Jun 2019 14:30:57 +0200 Subject: [PATCH] tests: use GLib for library test cases and bats for gpio-tools This replaces the custom hand-crafted testing suite with well-known open-source tools while keeping the same coverage. The core library is now tested using the GLib unit testing framework. The gpio-tools are now tested in bash using the bats testing system instead of being invoked from a C program. This simplifies and shrinks the testing code and makes it less prone to bugs. Signed-off-by: Bartosz Golaszewski --- TODO | 12 - configure.ac | 16 +- tests/Makefile.am | 16 +- tests/gpiod-test.c | 1127 +++++------------------------------- tests/gpiod-test.h | 199 +++---- tests/tests-chip.c | 471 ++++++++------- tests/tests-ctxless.c | 434 +++++++------- tests/tests-event.c | 373 ++++++------ tests/tests-gpiodetect.c | 50 -- tests/tests-gpiofind.c | 69 --- tests/tests-gpioget.c | 122 ---- tests/tests-gpioinfo.c | 141 ----- tests/tests-gpiomon.c | 378 ------------ tests/tests-gpioset.c | 289 --------- tests/tests-iter.c | 115 ++-- tests/tests-line.c | 787 ++++++++++++------------- tests/tests-misc.c | 31 +- tools/Makefile.am | 8 + tools/gpio-tools-test.bats | 869 +++++++++++++++++++++++++++ 19 files changed, 2185 insertions(+), 3322 deletions(-) delete mode 100644 tests/tests-gpiodetect.c delete mode 100644 tests/tests-gpiofind.c delete mode 100644 tests/tests-gpioget.c delete mode 100644 tests/tests-gpioinfo.c delete mode 100644 tests/tests-gpiomon.c delete mode 100644 tests/tests-gpioset.c create mode 100755 tools/gpio-tools-test.bats diff --git a/TODO b/TODO index 6f1cd65..f857fea 100644 --- a/TODO +++ b/TODO @@ -25,18 +25,6 @@ and is partially functional. ---------- -* porting the unit tests of core libgpiod library to using GLib - -Once libgpiod-test is ready, we can think about reusing existing testing -frameworks instead of using a custom solution. - -For the core C library a good candidate would be the GLib unit testing library. -GLib already provides a significant number of functionalities we currently use -like starting sub-processes, reading files, assertions plus it also offers a -range of output formatting and report generation options. - ----------- - * use a proper unit testing framework for C++ bindings and reuse libgpiod-test The actual framework for testing is TBD but libgpiod-test could be reused as is diff --git a/configure.ac b/configure.ac index e24b96d..8f0eb38 100644 --- a/configure.ac +++ b/configure.ac @@ -122,12 +122,24 @@ AC_DEFUN([FUNC_NOT_FOUND_TESTS], if test "x$with_tests" = xtrue then - AC_CHECK_FUNC([qsort], [], [FUNC_NOT_FOUND_TESTS([qsort])]) - AC_CHECK_FUNC([regexec], [], [FUNC_NOT_FOUND_TESTS([regexec])]) AC_CHECK_HEADERS([linux/version.h], [], [HEADER_NOT_FOUND_TESTS([linux/version.h])]) + # For libgpiomockup + AC_CHECK_FUNC([qsort], [], [FUNC_NOT_FOUND_TESTS([qsort])]) PKG_CHECK_MODULES([KMOD], [libkmod >= 18]) PKG_CHECK_MODULES([UDEV], [libudev >= 215]) + + # For core library tests + PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.50]) + + if test "x$with_tools" = xtrue + then + AC_CHECK_PROG([has_bats], [bats], [true], [false]) + if test "x$has_bats" = "xflase" + then + AC_MSG_NOTICE(["bats not found - gpio-tools tests cannot be run]) + fi + fi fi # ABI version for libgpiomockup (we need this since it can be installed if we diff --git a/tests/Makefile.am b/tests/Makefile.am index f24b966..6e6d823 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,10 +10,11 @@ SUBDIRS = mockup AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/mockup/ AM_CFLAGS += -include $(top_builddir)/config.h -AM_CFLAGS += -Wall -Wextra -g +AM_CFLAGS += -Wall -Wextra -g $(GLIB_CFLAGS) AM_LDFLAGS = -pthread LDADD = $(top_builddir)/lib/libgpiod.la LDADD += $(top_builddir)/tests/mockup/libgpiomockup.la +LDADD += $(GLIB_LIBS) bin_PROGRAMS = gpiod-test @@ -26,20 +27,9 @@ gpiod_test_SOURCES = gpiod-test.c \ tests-line.c \ tests-misc.c -if WITH_TOOLS - -gpiod_test_SOURCES += tests-gpiodetect.c \ - tests-gpiofind.c \ - tests-gpioget.c \ - tests-gpioinfo.c \ - tests-gpiomon.c \ - tests-gpioset.c - -endif - all-local: gpiod-test @echo " ********************************************************" - @echo " * Tests have been built as tests/gpiod-test. *" + @echo " * Core tests have been built as tests/gpiod-test. *" @echo " * *" @echo " * They require a recent linux kernel version and the *" @echo " * gpio-mockup module (must not be built-in). *" diff --git a/tests/gpiod-test.c b/tests/gpiod-test.c index d003c1c..9eb5d61 100644 --- a/tests/gpiod-test.c +++ b/tests/gpiod-test.c @@ -2,1079 +2,256 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski * Copyright (C) 2019 Bartosz Golaszewski */ -#include #include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include #include -#include #include #include "gpiod-test.h" -#define NORETURN __attribute__((noreturn)) -#define MALLOC __attribute__((malloc)) - -static const unsigned int min_kern_major = 5; -static const unsigned int min_kern_minor = 1; -static const unsigned int min_kern_release = 0; - -struct event_thread { - pthread_t thread_id; - pthread_mutex_t lock; - pthread_cond_t cond; - bool running; - bool should_stop; - unsigned int chip_index; - unsigned int line_offset; - unsigned int freq; -}; - -struct gpiotool_proc { - pid_t pid; - bool running; - int stdin_fd; - int stdout_fd; - int stderr_fd; - char *stdout; - char *stderr; - int sig_fd; - int exit_status; -}; - -struct test_context { - size_t num_chips; - bool test_failed; - char *failed_msg; - char *custom_str; - struct event_thread event; - struct gpiotool_proc tool_proc; - bool running; +#define MIN_KERNEL_MAJOR 5 +#define MIN_KERNEL_MINOR 1 +#define MIN_KERNEL_RELEASE 0 +#define MIN_KERNEL_VERSION KERNEL_VERSION(MIN_KERNEL_MAJOR, \ + MIN_KERNEL_MINOR, \ + MIN_KERNEL_RELEASE) + +struct gpiod_test_event_thread { + GThread *id; + GMutex lock; + GCond cond; + gboolean should_stop; + guint chip_index; + guint line_offset; + guint freq; }; static struct { - struct _test_case *test_list_head; - struct _test_case *test_list_tail; - unsigned int num_tests; - unsigned int tests_failed; + _GpiodTestCase *test_list_head; + _GpiodTestCase *test_list_tail; + guint num_tests; struct gpio_mockup *mockup; - struct test_context test_ctx; - pid_t main_pid; - int pipesize; - char *pipebuf; - char *toolpath; } globals; -enum { - CNORM = 0, - CGREEN, - CRED, - CREDBOLD, - CYELLOW, -}; - -static const char *const term_colors[] = { - "\033[0m", - "\033[32m", - "\033[31m", - "\033[1m\033[31m", - "\033[33m", -}; - -static void set_color(int color) -{ - fprintf(stderr, "%s", term_colors[color]); -} - -static void reset_color(void) -{ - fprintf(stderr, "%s", term_colors[CNORM]); -} - -static void pr_raw_v(const char *fmt, va_list va) -{ - vfprintf(stderr, fmt, va); -} - -static TEST_PRINTF(1, 2) void pr_raw(const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - pr_raw_v(fmt, va); - va_end(va); -} - -static void print_header(const char *hdr, int color) -{ - char buf[9]; - - snprintf(buf, sizeof(buf), "[%s]", hdr); - - set_color(color); - pr_raw("%-8s", buf); - reset_color(); -} - -static void vmsgn(const char *hdr, int hdr_clr, const char *fmt, va_list va) -{ - print_header(hdr, hdr_clr); - pr_raw_v(fmt, va); -} - -static void vmsg(const char *hdr, int hdr_clr, const char *fmt, va_list va) -{ - vmsgn(hdr, hdr_clr, fmt, va); - pr_raw("\n"); -} - -static TEST_PRINTF(1, 2) void msg(const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - vmsg("INFO", CGREEN, fmt, va); - va_end(va); -} - -static TEST_PRINTF(1, 2) void err(const char *fmt, ...) -{ - va_list va; - - va_start(va, fmt); - vmsg("ERROR", CRED, fmt, va); - va_end(va); -} - -static void die_test_cleanup(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - int rv; - - if (proc->running) { - kill(proc->pid, SIGKILL); - waitpid(proc->pid, &rv, 0); - } - - if (globals.test_ctx.running) - pr_raw("\n"); -} - -static TEST_PRINTF(1, 2) NORETURN void die(const char *fmt, ...) -{ - va_list va; - - die_test_cleanup(); - - va_start(va, fmt); - vmsg("FATAL", CRED, fmt, va); - va_end(va); - - exit(EXIT_FAILURE); -} - -static TEST_PRINTF(1, 2) NORETURN void die_perr(const char *fmt, ...) -{ - va_list va; - - die_test_cleanup(); - - va_start(va, fmt); - vmsgn("FATAL", CRED, fmt, va); - pr_raw(": %s\n", strerror(errno)); - va_end(va); - - exit(EXIT_FAILURE); -} - -static MALLOC void *xmalloc(size_t size) -{ - void *ptr; - - ptr = malloc(size); - if (!ptr) - die("out of memory"); - - return ptr; -} - -static MALLOC void *xzalloc(size_t size) -{ - void *ptr; - - ptr = xmalloc(size); - memset(ptr, 0, size); - - return ptr; -} - -static MALLOC void *xcalloc(size_t nmemb, size_t size) -{ - void *ptr; - - ptr = calloc(nmemb, size); - if (!ptr) - die("out of memory"); - - return ptr; -} - -static MALLOC char *xstrdup(const char *str) -{ - char *ret; - - ret = strdup(str); - if (!ret) - die("out of memory"); - - return ret; -} - -static TEST_PRINTF(2, 3) char *xappend(char *str, const char *fmt, ...) -{ - char *new, *ret; - va_list va; - int rv; - - va_start(va, fmt); - rv = vasprintf(&new, fmt, va); - va_end(va); - if (rv < 0) - die_perr("vasprintf"); - - if (!str) - return new; - - ret = realloc(str, strlen(str) + strlen(new) + 1); - if (!ret) - die("out of memory"); - - strcat(ret, new); - free(new); - - return ret; -} - -static int get_pipesize(void) -{ - int pipe_fds[2], rv; - - rv = pipe(pipe_fds); - if (rv < 0) - die_perr("unable to create a pipe"); - - /* - * Since linux v2.6.11 the default pipe capacity is 16 system pages. - * We make an assumption here that gpio-tools won't output more than - * that, so we can read everything after the program terminated. If - * they did output more than the pipe capacity however, the write() - * system call would block and the process would be killed by the - * testing framework. - */ - rv = fcntl(pipe_fds[0], F_GETPIPE_SZ); - if (rv < 0) - die_perr("unable to retrieve the pipe capacity"); - - close(pipe_fds[0]); - close(pipe_fds[1]); - - return rv; -} - -static void check_chip_index(unsigned int index) -{ - if (index >= globals.test_ctx.num_chips) - die("invalid chip number requested from test code"); -} - -static void cleanup_func(void) -{ - /* Don't cleanup from child processes. */ - if (globals.main_pid != getpid()) - return; - - msg("cleaning up"); - - free(globals.pipebuf); - if (globals.toolpath) - free(globals.toolpath); - - if (globals.mockup) - gpio_mockup_unref(globals.mockup); -} - -static void event_lock(void) -{ - pthread_mutex_lock(&globals.test_ctx.event.lock); -} - -static void event_unlock(void) -{ - pthread_mutex_unlock(&globals.test_ctx.event.lock); -} - -static void *event_worker(void *data TEST_UNUSED) -{ - struct event_thread *ev = &globals.test_ctx.event; - struct timeval tv_now, tv_add, tv_res; - struct timespec ts; - int rv, i; - - for (i = 0;; i++) { - event_lock(); - if (ev->should_stop) { - event_unlock(); - break; - } - - gettimeofday(&tv_now, NULL); - tv_add.tv_sec = 0; - tv_add.tv_usec = ev->freq * 1000; - timeradd(&tv_now, &tv_add, &tv_res); - ts.tv_sec = tv_res.tv_sec; - ts.tv_nsec = tv_res.tv_usec * 1000; - - rv = pthread_cond_timedwait(&ev->cond, &ev->lock, &ts); - if (rv == ETIMEDOUT) { - rv = gpio_mockup_set_pull(globals.mockup, ev->chip_index, - ev->line_offset, i % 2); - if (rv) - die_perr("error generating line event"); - } else if (rv != 0) { - die("error waiting for conditional variable: %s", - strerror(rv)); - } - - event_unlock(); - } - - return NULL; -} - -static void gpiotool_proc_make_pipes(int *in_fds, int *out_fds, int *err_fds) -{ - int rv, i, *fds[3]; - - fds[0] = in_fds; - fds[1] = out_fds; - fds[2] = err_fds; - - for (i = 0; i < 3; i++) { - rv = pipe(fds[i]); - if (rv < 0) - die_perr("unable to create a pipe"); - } -} - -static void gpiotool_proc_dup_fds(int in_fd, int out_fd, int err_fd) -{ - int old_fds[3], new_fds[3], i, rv; - - old_fds[0] = in_fd; - old_fds[1] = out_fd; - old_fds[2] = err_fd; - - new_fds[0] = STDIN_FILENO; - new_fds[1] = STDOUT_FILENO; - new_fds[2] = STDERR_FILENO; - - for (i = 0; i < 3; i++) { - rv = dup2(old_fds[i], new_fds[i]); - if (rv < 0) - die_perr("unable to duplicate a file descriptor"); - - close(old_fds[i]); - } -} - -static NORETURN void gpiotool_proc_exec(const char *path, va_list va) -{ - size_t num_args; - unsigned int i; - char **argv; - va_list va2; - - va_copy(va2, va); - for (num_args = 2; va_arg(va2, char *) != NULL; num_args++) - ; - va_end(va2); - - argv = xcalloc(num_args, sizeof(char *)); - - argv[0] = (char *)path; - for (i = 1; i < num_args; i++) - argv[i] = va_arg(va, char *); - va_end(va); - - execv(path, argv); - die_perr("unable to exec '%s'", path); -} - -static void gpiotool_proc_cleanup(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - - if (proc->stdout) - free(proc->stdout); - - if (proc->stderr) - free(proc->stderr); - - proc->stdout = proc->stderr = NULL; -} - -void test_tool_signal(int signum) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - int rv; - - rv = kill(proc->pid, signum); - if (rv) - die_perr("unable to send signal to process %d", proc->pid); -} - -void test_tool_stdin_write(const char *fmt, ...) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - ssize_t written; - va_list va; - char *in; - int rv; - - va_start(va, fmt); - rv = vasprintf(&in, fmt, va); - va_end(va); - if (rv < 0) - die_perr("error building string"); - - written = write(proc->stdin_fd, in, rv); - free(in); - if (written < 0) - die_perr("error writing to child process' stdin"); - if (written != rv) - die("unable to write all data to child process' stdin"); -} - -void test_tool_run(char *tool, ...) -{ - int in_fds[2], out_fds[2], err_fds[2], rv; - struct gpiotool_proc *proc; - sigset_t sigmask; - char *path; - va_list va; - - proc = &globals.test_ctx.tool_proc; - if (proc->running) - die("unable to start %s - another tool already running", tool); - - if (proc->pid) - gpiotool_proc_cleanup(); - - event_lock(); - if (globals.test_ctx.event.running) - die("refusing to fork when the event thread is running"); - if (!globals.toolpath) - die("asked to run tests for gpio-tools, but the executables were not found"); - - gpiotool_proc_make_pipes(in_fds, out_fds, err_fds); - - path = xappend(NULL, "%s/%s", globals.toolpath, tool); - rv = access(path, R_OK | X_OK); - if (rv) - die_perr("unable to execute '%s'", path); - - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGCHLD); - - rv = sigprocmask(SIG_BLOCK, &sigmask, NULL); - if (rv) - die_perr("unable to block SIGCHLD"); - - proc->sig_fd = signalfd(-1, &sigmask, 0); - if (proc->sig_fd < 0) - die_perr("unable to create signalfd"); - - proc->pid = fork(); - if (proc->pid < 0) { - die_perr("unable to fork"); - } else if (proc->pid == 0) { - /* Child process. */ - close(proc->sig_fd); - gpiotool_proc_dup_fds(in_fds[0], out_fds[1], err_fds[1]); - va_start(va, tool); - gpiotool_proc_exec(path, va); - } else { - /* Parent process. */ - close(in_fds[0]); - proc->stdin_fd = in_fds[1]; - close(out_fds[1]); - proc->stdout_fd = out_fds[0]; - close(err_fds[1]); - proc->stderr_fd = err_fds[0]; - - proc->running = true; - } - - event_unlock(); - free(path); -} - -static void gpiotool_readall(int fd, char **out) -{ - ssize_t rd; - int i; - - memset(globals.pipebuf, 0, globals.pipesize); - rd = read(fd, globals.pipebuf, globals.pipesize); - if (rd < 0) { - die_perr("error reading output from subprocess"); - } else if (rd == 0) { - *out = NULL; - } else { - for (i = 0; i < rd; i++) { - if (!isascii(globals.pipebuf[i])) - die("GPIO tool program printed a non-ASCII character"); - } - - *out = xzalloc(rd + 1); - memcpy(*out, globals.pipebuf, rd); - } -} - -void test_tool_wait(void) -{ - struct signalfd_siginfo sinfo; - struct gpiotool_proc *proc; - struct pollfd pfd; - sigset_t sigmask; - ssize_t rd; - int rv; - - proc = &globals.test_ctx.tool_proc; - - if (!proc->running) - die("gpiotool process not running"); - - pfd.fd = proc->sig_fd; - pfd.events = POLLIN | POLLPRI; - - rv = poll(&pfd, 1, 5000); - if (rv == 0) - die("tool program is taking too long to terminate"); - else if (rv < 0) - die_perr("error when polling the signalfd"); - - rd = read(proc->sig_fd, &sinfo, sizeof(sinfo)); - close(proc->sig_fd); - if (rd < 0) - die_perr("error reading signal info"); - else if (rd != sizeof(sinfo)) - die("invalid size of signal info"); - - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGCHLD); - - rv = sigprocmask(SIG_UNBLOCK, &sigmask, NULL); - if (rv) - die_perr("unable to unblock SIGCHLD"); - - gpiotool_readall(proc->stdout_fd, &proc->stdout); - gpiotool_readall(proc->stderr_fd, &proc->stderr); - - waitpid(proc->pid, &proc->exit_status, 0); - - close(proc->stdin_fd); - close(proc->stdout_fd); - close(proc->stderr_fd); - - proc->running = false; -} - -const char *test_tool_stdout(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - - return proc->stdout; -} - -const char *test_tool_stderr(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - - return proc->stderr; -} - -bool test_tool_exited(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - - return WIFEXITED(proc->exit_status); -} - -int test_tool_exit_status(void) -{ - struct gpiotool_proc *proc = &globals.test_ctx.tool_proc; - - return WEXITSTATUS(proc->exit_status); -} - static void check_kernel(void) { - unsigned int major, minor, release; + guint major, minor, release; struct utsname un; - int rv; + gint ret; - msg("checking the linux kernel version"); + g_debug("checking linux kernel version"); - rv = uname(&un); - if (rv) - die_perr("uname"); + ret = uname(&un); + if (ret) + g_error("unable to read the kernel release version: %s", + g_strerror(errno)); - rv = sscanf(un.release, "%u.%u.%u", &major, &minor, &release); - if (rv != 3) - die("error reading kernel release version"); + ret = sscanf(un.release, "%u.%u.%u", &major, &minor, &release); + if (ret != 3) + g_error("error reading kernel release version"); - if (major < min_kern_major) { - goto bad_version; - } else if (major > min_kern_major) { - goto good_version; - } else { - if (minor < min_kern_minor) { - goto bad_version; - } else if (minor > min_kern_minor) { - goto good_version; - } else { - if (release < min_kern_release) - goto bad_version; - else - goto good_version; - } - } + if (KERNEL_VERSION(major, minor, release) < MIN_KERNEL_VERSION) + g_error("linux kernel version must be at least v%u.%u.%u - got v%u.%u.%u", + MIN_KERNEL_MAJOR, MIN_KERNEL_MINOR, MIN_KERNEL_RELEASE, + major, minor, release); -good_version: - msg("kernel release is v%u.%u.%u - ok to run tests", - major, minor, release); + g_debug("kernel release is v%u.%u.%u - ok to run tests", + major, minor, release); return; - -bad_version: - die("linux kernel version must be at least v%u.%u.%u - got v%u.%u.%u", - min_kern_major, min_kern_minor, min_kern_release, - major, minor, release); } -static void check_tool_path(void) +static void test_func_wrapper(gconstpointer data) { - /* - * Let's check gpiodetect only and assume all the other tools are in - * the same directory. - */ - static const char *const tool = "gpiodetect"; - - char *progpath, *progdir, *toolpath, *pathenv, *tok; - - /* First check if we're running the from the top source directory. */ - progpath = xstrdup(program_invocation_name); - progdir = dirname(progpath); + const _GpiodTestCase *test = data; + gint ret, flags = 0; - toolpath = xappend(NULL, "%s/../../tools/%s", progdir, tool); - if (access(toolpath, R_OK | X_OK) == 0) { - free(progpath); - goto out; - } - free(toolpath); - - /* Is the tool in the same directory maybe? */ - toolpath = xappend(NULL, "%s/%s", progdir, tool); - free(progpath); - if (access(toolpath, R_OK | X_OK) == 0) - goto out; - free(toolpath); - - /* Next iterate over directories in $PATH. */ - pathenv = getenv("PATH"); - if (!pathenv) - return; - - progpath = xstrdup(pathenv); - tok = strtok(progpath, ":"); - while (tok) { - toolpath = xappend(NULL, "%s/%s", tok, tool); - if (access(toolpath, R_OK) == 0) { - free(progpath); - goto out; - } - - free(toolpath); - tok = strtok(NULL, ":"); - } - - free(progpath); - toolpath = NULL; - -out: - if (toolpath) { - toolpath = dirname(toolpath); - msg("using gpio-tools from '%s'", toolpath); - globals.toolpath = toolpath; - } -} - -static void prepare_test(struct _test_chip_descr *descr) -{ - unsigned int *chip_sizes, i; - struct test_context *ctx; - int rv, flags = 0; - - ctx = &globals.test_ctx; - memset(ctx, 0, sizeof(*ctx)); - ctx->num_chips = descr->num_chips; - pthread_mutex_init(&ctx->event.lock, NULL); - pthread_cond_init(&ctx->event.cond, NULL); - - /* Don't try to load the module if we don't need any chips. */ - if (!ctx->num_chips) - return; - - chip_sizes = calloc(ctx->num_chips, sizeof(unsigned int)); - if (!chip_sizes) - die("out of memory"); - - for (i = 0; i < ctx->num_chips; i++) - chip_sizes[i] = descr->num_lines[i]; - - if (descr->flags & TEST_FLAG_NAMED_LINES) + if (test->flags & GPIOD_TEST_FLAG_NAMED_LINES) flags |= GPIO_MOCKUP_FLAG_NAMED_LINES; - rv = gpio_mockup_probe(globals.mockup, - ctx->num_chips, chip_sizes, flags); - if (rv) - die_perr("unable to load gpio-mockup kernel module"); - - free(chip_sizes); -} + ret = gpio_mockup_probe(globals.mockup, test->num_chips, + test->chip_sizes, flags); + if (ret) + g_error("unable to probe gpio-mockup: %s", g_strerror(errno)); -static void run_test(struct _test_case *test) -{ - errno = 0; - - print_header("TEST", CYELLOW); - pr_raw("'%s': ", test->name); - - globals.test_ctx.running = true; test->func(); - globals.test_ctx.running = false; - if (globals.test_ctx.test_failed) { - globals.tests_failed++; - set_color(CREDBOLD); - pr_raw("FAILED:"); - reset_color(); - set_color(CRED); - pr_raw("\n\t\t'%s': %s\n", - test->name, globals.test_ctx.failed_msg); - reset_color(); - free(globals.test_ctx.failed_msg); - } else { - set_color(CGREEN); - pr_raw("PASS\n"); - reset_color(); - } + ret = gpio_mockup_remove(globals.mockup); + if (ret) + g_error("unable to remove gpio_mockup: %s", g_strerror(errno)); } -static void teardown_test(void) +static void unref_mockup(void) { - struct gpiotool_proc *tool_proc; - struct test_context *ctx; - struct event_thread *ev; - int rv; - - ctx = &globals.test_ctx; - - event_lock(); - ev = &ctx->event; - - if (ev->running) { - ev->should_stop = true; - pthread_cond_broadcast(&ev->cond); - event_unlock(); - - rv = pthread_join(ctx->event.thread_id, NULL); - if (rv != 0) - die("error joining event thread: %s", - strerror(rv)); - - pthread_mutex_destroy(&ctx->event.lock); - pthread_cond_destroy(&ctx->event.cond); - } else { - event_unlock(); - } - - tool_proc = &ctx->tool_proc; - if (tool_proc->running) { - test_tool_signal(SIGKILL); - test_tool_wait(); - } - - if (tool_proc->pid) - gpiotool_proc_cleanup(); - - if (ctx->custom_str) - free(ctx->custom_str); - - if (!ctx->num_chips) - return; - - rv = gpio_mockup_remove(globals.mockup); - if (rv) - die_perr("unable to remove gpio-mockup kernel module"); + gpio_mockup_unref(globals.mockup); } -int main(int argc TEST_UNUSED, char **argv TEST_UNUSED) +int main(gint argc, gchar **argv) { - struct _test_case *test; + _GpiodTestCase *test; - globals.main_pid = getpid(); - globals.pipesize = get_pipesize(); - globals.pipebuf = xmalloc(globals.pipesize); - atexit(cleanup_func); + g_test_init(&argc, &argv, NULL); + g_test_set_nonfatal_assertions(); - msg("libgpiod test suite"); - msg("%u tests registered", globals.num_tests); + g_debug("running libgpiod test suite"); + g_debug("%u tests registered", globals.num_tests); + /* + * Setup libgpiomockup first so that it runs its own kernel version + * check before we tell the user our local requirements are met as + * well. + */ globals.mockup = gpio_mockup_new(); if (!globals.mockup) - die_perr("error checking the availability of gpio-mockup"); + g_error("unable to initialize gpio-mockup library: %s", + g_strerror(errno)); + atexit(unref_mockup); check_kernel(); - check_tool_path(); - msg("running tests"); + for (test = globals.test_list_head; test; test = test->_next) + g_test_add_data_func(test->path, test, test_func_wrapper); - for (test = globals.test_list_head; test; test = test->_next) { - prepare_test(&test->chip_descr); - run_test(test); - teardown_test(); - } - - if (!globals.tests_failed) - msg("all tests passed"); - else - err("%u out of %u tests failed", - globals.tests_failed, globals.num_tests); - - return globals.tests_failed ? EXIT_FAILURE : EXIT_SUCCESS; -} - -void test_close_chip(struct gpiod_chip **chip) -{ - if (*chip) - gpiod_chip_close(*chip); + return g_test_run(); } -void test_line_close_chip(struct gpiod_line **line) +void _gpiod_test_register(_GpiodTestCase *test) { - if (*line) - gpiod_line_close_chip(*line); -} + _GpiodTestCase *tmp; -void test_free_chip_iter(struct gpiod_chip_iter **iter) -{ - if (*iter) - gpiod_chip_iter_free(*iter); -} - -void test_free_line_iter(struct gpiod_line_iter **iter) -{ - if (*iter) - gpiod_line_iter_free(*iter); -} + if (!globals.test_list_head) { + globals.test_list_head = globals.test_list_tail = test; + test->_next = NULL; + } else { + tmp = globals.test_list_tail; + globals.test_list_tail = test; + test->_next = NULL; + tmp->_next = test; + } -void test_free_chip_iter_noclose(struct gpiod_chip_iter **iter) -{ - if (*iter) - gpiod_chip_iter_free_noclose(*iter); + globals.num_tests++; } -const char *test_chip_path(unsigned int index) +const gchar *gpiod_test_chip_path(guint index) { - check_chip_index(index); + const gchar *path; - return gpio_mockup_chip_path(globals.mockup, index); -} - -const char *test_chip_name(unsigned int index) -{ - check_chip_index(index); + path = gpio_mockup_chip_path(globals.mockup, index); + if (!path) + g_error("unable to retrieve the chip path: %s", + g_strerror(errno)); - return gpio_mockup_chip_name(globals.mockup, index); + return path; } -unsigned int test_chip_num(unsigned int index) +const gchar *gpiod_test_chip_name(guint index) { - int chip_num; + const gchar *name; - check_chip_index(index); + name = gpio_mockup_chip_name(globals.mockup, index); + if (!name) + g_error("unable to retrieve the chip name: %s", + g_strerror(errno)); - chip_num = gpio_mockup_chip_num(globals.mockup, index); - if (chip_num < 0) - die_perr("error getting the chip number"); - - return chip_num; + return name; } -int test_debugfs_get_value(unsigned int chip_index, unsigned int line_offset) +gint gpiod_test_chip_num(unsigned int index) { - int rv; - - rv = gpio_mockup_get_value(globals.mockup, chip_index, line_offset); - if (rv < 0) - die_perr("error reading the debugfs line attribute"); + gint num; - return rv; -} - -void test_debugfs_set_value(unsigned int chip_index, - unsigned int line_offset, int val) -{ - int rv; + num = gpio_mockup_chip_num(globals.mockup, index); + if (num < 0) + g_error("unable to retrieve the chip number: %s", + g_strerror(errno)); - rv = gpio_mockup_set_pull(globals.mockup, chip_index, - line_offset, val); - if (rv) - die_perr("error writing to the debugfs line attribute"); + return num; } -void _test_register(struct _test_case *test) +gint gpiod_test_chip_get_value(guint chip_index, guint line_offset) { - struct _test_case *tmp; + gint ret; - if (!globals.test_list_head) { - globals.test_list_head = globals.test_list_tail = test; - test->_next = NULL; - } else { - tmp = globals.test_list_tail; - globals.test_list_tail = test; - test->_next = NULL; - tmp->_next = test; - } + ret = gpio_mockup_get_value(globals.mockup, chip_index, line_offset); + if (ret < 0) + g_error("unable to read line value from gpio-mockup: %s", + g_strerror(errno)); - globals.num_tests++; + return ret; } -void _test_print_failed(const char *fmt, ...) +void gpiod_test_chip_set_pull(guint chip_index, guint line_offset, gint pull) { - va_list va; - int rv; - - va_start(va, fmt); - rv = vasprintf(&globals.test_ctx.failed_msg, fmt, va); - va_end(va); - if (rv < 0) - die_perr("vasprintf"); + gint ret; - globals.test_ctx.test_failed = true; + ret = gpio_mockup_set_pull(globals.mockup, chip_index, + line_offset, pull); + if (ret) + g_error("unable to set line pull in gpio-mockup: %s", + g_strerror(errno)); } -void test_set_event(unsigned int chip_index, - unsigned int line_offset, unsigned int freq) +static gpointer event_worker_func(gpointer data) { - struct event_thread *ev = &globals.test_ctx.event; - int rv; - - event_lock(); - - if (!ev->running) { - rv = pthread_create(&ev->thread_id, NULL, event_worker, NULL); - if (rv != 0) - die("error creating event thread: %s", - strerror(rv)); - - ev->running = true; - } - - ev->chip_index = chip_index; - ev->line_offset = line_offset; - ev->freq = freq; + GpiodTestEventThread *thread = data; + gboolean signalled; + gint64 end_time; + gint i; - pthread_cond_broadcast(&ev->cond); + for (i = 0;; i++) { + g_mutex_lock(&thread->lock); + if (thread->should_stop) { + g_mutex_unlock(&thread->lock); + break; + } - event_unlock(); -} + end_time = g_get_monotonic_time() + thread->freq * 1000; -void test_trigger_event(unsigned int chip_index, unsigned int line_offset) -{ - int val, rv; + signalled = g_cond_wait_until(&thread->cond, + &thread->lock, end_time); + if (!signalled) + gpiod_test_chip_set_pull(thread->chip_index, + thread->line_offset, i % 2); - val = gpio_mockup_get_value(globals.mockup, chip_index, line_offset); - if (val < 0) - die_perr("error reading GPIO value from debugfs"); + g_mutex_unlock(&thread->lock); + } - rv = gpio_mockup_set_pull(globals.mockup, chip_index, - line_offset, val ? 0 : 1); - if (rv) - die_perr("error setting GPIO line pull over debugfs"); + return NULL; } -bool test_regex_match(const char *str, const char *pattern) +GpiodTestEventThread * +gpiod_test_start_event_thread(guint chip_index, guint line_offset, guint freq) { - char errbuf[128]; - regex_t regex; - bool ret; - int rv; + GpiodTestEventThread *thread = g_malloc0(sizeof(*thread)); - rv = regcomp(®ex, pattern, REG_EXTENDED | REG_NEWLINE); - if (rv) { - regerror(rv, ®ex, errbuf, sizeof(errbuf)); - die("unable to compile regex '%s': %s", pattern, errbuf); - } + g_mutex_init(&thread->lock); + g_cond_init(&thread->cond); - rv = regexec(®ex, str, 0, 0, 0); - if (rv == REG_NOERROR) { - ret = true; - } else if (rv == REG_NOMATCH) { - ret = false; - } else { - regerror(rv, ®ex, errbuf, sizeof(errbuf)); - die("unable to run a regex match: %s", errbuf); - } + thread->chip_index = chip_index; + thread->line_offset = line_offset; + thread->freq = freq; - regfree(®ex); + thread->id = g_thread_new("event-worker", event_worker_func, thread); - return ret; + return thread; } -const char *test_build_str(const char *fmt, ...) +void gpiod_test_stop_event_thread(GpiodTestEventThread *thread) { - va_list va; - char *str; - int rv; - - if (globals.test_ctx.custom_str) - free(globals.test_ctx.custom_str); - - va_start(va, fmt); - rv = vasprintf(&str, fmt, va); - va_end(va); - if (rv < 0) - die_perr("error creating custom string"); + g_mutex_lock(&thread->lock); + thread->should_stop = TRUE; + g_cond_broadcast(&thread->cond); + g_mutex_unlock(&thread->lock); - globals.test_ctx.custom_str = str; + (void)g_thread_join(thread->id); - return str; + g_mutex_clear(&thread->lock); + g_cond_clear(&thread->cond); + g_free(thread); } diff --git a/tests/gpiod-test.h b/tests/gpiod-test.h index 1815c65..bb0f8be 100644 --- a/tests/gpiod-test.h +++ b/tests/gpiod-test.h @@ -2,165 +2,106 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski * Copyright (C) 2019 Bartosz Golaszewski */ -/* Testing framework - functions and definitions used by test cases. */ +/* + * Testing framework for the core library. + * + * This file contains functions and definitions extending the GLib unit testing + * framework with functionalities necessary to test the libgpiod core C API as + * well as the kernel-to-user-space interface. + */ #ifndef __GPIOD_TEST_H__ #define __GPIOD_TEST_H__ +#include #include -#include - -#define TEST_CONSUMER "gpiod-test" -#define TEST_INIT __attribute__((constructor)) -#define TEST_UNUSED __attribute__((unused)) -#define TEST_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg))) -#define TEST_CLEANUP(func) __attribute__((cleanup(func))) -#define TEST_BIT(nr) (1UL << (nr)) - -#define TEST_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +/* + * These typedefs are needed to make g_autoptr work - it doesn't accept + * regular 'struct typename' syntax. + */ +typedef struct gpiod_chip gpiod_chip_struct; +typedef struct gpiod_chip_iter gpiod_chip_iter_struct; +typedef struct gpiod_line_iter gpiod_line_iter_struct; -typedef void (*_test_func)(void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_close); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_iter_struct, gpiod_chip_iter_free); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_line_iter_struct, gpiod_line_iter_free); -struct _test_chip_descr { - unsigned int num_chips; - unsigned int *num_lines; - int flags; -}; +/* There are private definitions and should not be used directly. */ +typedef void (*_gpiod_test_func)(void); -struct _test_case { - struct _test_case *_next; +typedef struct _gpiod_test_case _GpiodTestCase; +struct _gpiod_test_case { + _GpiodTestCase *_next; - const char *name; - _test_func func; + const gchar *path; + _gpiod_test_func func; - struct _test_chip_descr chip_descr; + guint num_chips; + guint *chip_sizes; + gint flags; }; -void _test_register(struct _test_case *test); -void _test_print_failed(const char *fmt, ...) TEST_PRINTF(1, 2); +void _gpiod_test_register(_GpiodTestCase *test); + +#define _GPIOD_TEST_PATH(_name) \ + "/gpiod/" GPIOD_TEST_GROUP "/" G_STRINGIFY(_name) enum { - TEST_FLAG_NAMED_LINES = TEST_BIT(0), + /* Dummy lines for this test case should have names assigned. */ + GPIOD_TEST_FLAG_NAMED_LINES = (1 << 0), }; /* - * This macro should be used for code brevity instead of manually declaring - * the _test_case structure. - * - * The macro accepts the following arguments: - * _a_func: name of the test function - * _a_name: name of the test case (will be shown to user) - * _a_flags: various switches for the test case - * - * The last argument must be an array of unsigned integers specifying the - * number of GPIO lines in each subsequent mockup chip. The size of this - * array will at the same time specify the number of gpiochips to create. + * Register a test case function. The last argument is the array of numbers + * of lines per mockup chip. */ -#define TEST_DEFINE(_a_func, _a_name, _a_flags, ...) \ - static unsigned int _##_a_func##_lines[] = __VA_ARGS__; \ - static struct _test_case _##_a_func##_descr = { \ - .name = _a_name, \ - .func = _a_func, \ - .chip_descr = { \ - .num_chips = TEST_ARRAY_SIZE( \ - _##_a_func##_lines), \ - .num_lines = _##_a_func##_lines, \ - .flags = _a_flags, \ - }, \ +#define GPIOD_TEST_CASE(_name, _flags, ...) \ + static void _name(void); \ + static guint _##_name##_chip_sizes[] = __VA_ARGS__; \ + static _GpiodTestCase _##_name##_test_case = { \ + .path = _GPIOD_TEST_PATH(_name), \ + .func = _name, \ + .num_chips = G_N_ELEMENTS(_##_name##_chip_sizes), \ + .chip_sizes = _##_name##_chip_sizes, \ + .flags = _flags, \ }; \ - static TEST_INIT void _test_register_##_a_func##_test(void) \ + static __attribute__((constructor)) void \ + _##_name##_test_register(void) \ { \ - _test_register(&_##_a_func##_descr); \ + _gpiod_test_register(&_##_name##_test_case); \ } \ - static int _test_##_a_func##_sentinel TEST_UNUSED - -/* - * We want libgpiod tests to co-exist with gpiochips created by other GPIO - * drivers. For that reason we can't just use hardcoded device file paths or - * gpiochip names. - * - * The test suite detects the chips that were exported by the gpio-mockup - * module and stores them in the internal test context structure. Test cases - * should use the routines declared below to access the gpiochip path, name - * or number by index corresponding with the order in which the mockup chips - * were requested in the TEST_DEFINE() macro. - */ -const char *test_chip_path(unsigned int index); -const char *test_chip_name(unsigned int index); -unsigned int test_chip_num(unsigned int index); - -int test_debugfs_get_value(unsigned int chip_index, unsigned int line_offset); -void test_debugfs_set_value(unsigned int chip_index, - unsigned int line_offset, int val); + static void _name(void) -/* Last argument is the delay between line value switches in microseconds. */ -void test_set_event(unsigned int chip_index, - unsigned int line_offset, unsigned int freq); +#define GPIOD_TEST_CONSUMER "gpiod-test" -void test_trigger_event(unsigned int chip_index, unsigned int line_offset); - -void test_tool_run(char *tool, ...); -void test_tool_wait(void); -const char *test_tool_stdout(void); -const char *test_tool_stderr(void); -bool test_tool_exited(void); -int test_tool_exit_status(void); -void test_tool_signal(int signum); -void test_tool_stdin_write(const char *fmt, ...) TEST_PRINTF(1, 2); - -/* - * Every TEST_ASSERT_*() macro expansion can make a test function return, so - * it would be quite difficult to keep track of every resource allocation. At - * the same time we don't want any deliberate memory leaks as we also use this - * test suite to find actual memory leaks in the library with valgrind. - * - * For this reason, the tests should generally always use the TEST_CLEANUP() - * macro for dynamically allocated variables and objects that need closing. - * - * The functions below can be reused by different tests for common use cases. - */ -void test_close_chip(struct gpiod_chip **chip); -void test_line_close_chip(struct gpiod_line **line); -void test_free_chip_iter(struct gpiod_chip_iter **iter); -void test_free_chip_iter_noclose(struct gpiod_chip_iter **iter); -void test_free_line_iter(struct gpiod_line_iter **iter); - -#define TEST_CLEANUP_CHIP TEST_CLEANUP(test_close_chip) - -bool test_regex_match(const char *str, const char *pattern); - -/* - * Return a custom string built according to printf() formatting rules. The - * returned string is valid until the next call to this routine. - */ -const char *test_build_str(const char *fmt, ...) TEST_PRINTF(1, 2); - -#define TEST_ASSERT(statement) \ +#define gpiod_test_return_if_failed() \ do { \ - if (!(statement)) { \ - _test_print_failed( \ - "assertion failed (%s:%d): '%s'", \ - __FILE__, __LINE__, #statement); \ + if (g_test_failed()) \ return; \ - } \ } while (0) -#define TEST_ASSERT_FALSE(statement) TEST_ASSERT(!(statement)) -#define TEST_ASSERT_NOT_NULL(ptr) TEST_ASSERT((ptr) != NULL) -#define TEST_ASSERT_RET_OK(status) TEST_ASSERT((status) == 0) -#define TEST_ASSERT_NULL(ptr) TEST_ASSERT((ptr) == NULL) -#define TEST_ASSERT_ERRNO_IS(errnum) TEST_ASSERT(errno == (errnum)) -#define TEST_ASSERT_EQ(a1, a2) TEST_ASSERT((a1) == (a2)) -#define TEST_ASSERT_NOTEQ(a1, a2) TEST_ASSERT((a1) != (a2)) -#define TEST_ASSERT_STR_EQ(s1, s2) TEST_ASSERT(strcmp(s1, s2) == 0) -#define TEST_ASSERT_STR_CONTAINS(s, p) TEST_ASSERT(strstr(s, p) != NULL) -#define TEST_ASSERT_STR_NOTCONT(s, p) TEST_ASSERT(strstr(s, p) == NULL) -#define TEST_ASSERT_REGEX_MATCH(s, p) TEST_ASSERT(test_regex_match(s, p)) -#define TEST_ASSERT_REGEX_NOMATCH(s, p) TEST_ASSERT(!test_regex_match(s, p)) +/* Wrappers around libgpiomockup helpers. */ +const gchar *gpiod_test_chip_path(guint index); +const gchar *gpiod_test_chip_name(guint index); +gint gpiod_test_chip_num(guint index); +gint gpiod_test_chip_get_value(guint chip_index, guint line_offset); +void gpiod_test_chip_set_pull(guint chip_index, guint line_offset, gint pull); + +/* Helpers for triggering line events in a separate thread. */ +struct gpiod_test_event_thread; +typedef struct gpiod_test_event_thread GpiodTestEventThread; + +GpiodTestEventThread * +gpiod_test_start_event_thread(guint chip_index, + guint line_offset, guint freq); +void gpiod_test_stop_event_thread(GpiodTestEventThread *thread); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GpiodTestEventThread, + gpiod_test_stop_event_thread); #endif /* __GPIOD_TEST_H__ */ diff --git a/tests/tests-chip.c b/tests/tests-chip.c index 0acb5c7..6edb61c 100644 --- a/tests/tests-chip.c +++ b/tests/tests-chip.c @@ -2,335 +2,324 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski + * Copyright (C) 2019 Bartosz Golaszewski */ -/* Test cases for GPIO chip handling. */ - #include -#include #include "gpiod-test.h" -static void chip_open_good(void) +#define GPIOD_TEST_GROUP "chip" + +GPIOD_TEST_CASE(open_good, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); } -TEST_DEFINE(chip_open_good, - "gpiod_chip_open() - good", - 0, { 8 }); -static void chip_open_nonexistent(void) +GPIOD_TEST_CASE(open_nonexistent, 0, { 8 }) { struct gpiod_chip *chip; chip = gpiod_chip_open("/dev/nonexistent_gpiochip"); - TEST_ASSERT_NULL(chip); - TEST_ASSERT_ERRNO_IS(ENOENT); + g_assert_null(chip); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(chip_open_nonexistent, - "gpiod_chip_open() - nonexistent chip", - 0, { 8 }); -static void chip_open_notty(void) +GPIOD_TEST_CASE(open_notty, 0, { 8 }) { struct gpiod_chip *chip; chip = gpiod_chip_open("/dev/null"); - TEST_ASSERT_NULL(chip); - TEST_ASSERT_ERRNO_IS(ENOTTY); + g_assert_null(chip); + g_assert_cmpint(errno, ==, ENOTTY); } -TEST_DEFINE(chip_open_notty, - "gpiod_chip_open() - notty", - 0, { 8 }); -static void chip_open_by_name_good(void) +GPIOD_TEST_CASE(open_by_name_good, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; - chip = gpiod_chip_open_by_name(test_chip_name(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open_by_name(gpiod_test_chip_name(0)); + g_assert_nonnull(chip); } -TEST_DEFINE(chip_open_by_name_good, - "gpiod_chip_open_by_name() - good", - 0, { 8 }); -static void chip_open_by_number_good(void) +GPIOD_TEST_CASE(open_by_number_good, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; - chip = gpiod_chip_open_by_number(test_chip_num(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open_by_number(gpiod_test_chip_num(0)); + g_assert_nonnull(chip); } -TEST_DEFINE(chip_open_by_number_good, - "gpiod_chip_open_by_number() - good", - 0, { 8 }); -static void chip_open_lookup(void) +GPIOD_TEST_CASE(open_by_label_good, 0, { 4, 4, 4, 4, 4 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip_by_label = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip_by_name = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip_by_path = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip_by_num = NULL; - - chip_by_name = gpiod_chip_open_lookup(test_chip_name(1)); - chip_by_path = gpiod_chip_open_lookup(test_chip_path(1)); - chip_by_num = gpiod_chip_open_lookup( - test_build_str("%u", test_chip_num(1))); - chip_by_label = gpiod_chip_open_lookup("gpio-mockup-B"); - - TEST_ASSERT_NOT_NULL(chip_by_name); - TEST_ASSERT_NOT_NULL(chip_by_path); - TEST_ASSERT_NOT_NULL(chip_by_num); - TEST_ASSERT_NOT_NULL(chip_by_label); + g_autoptr(gpiod_chip_struct) chip = NULL; - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip_by_name), test_chip_name(1)); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip_by_path), test_chip_name(1)); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip_by_num), test_chip_name(1)); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip_by_label), test_chip_name(1)); + chip = gpiod_chip_open_by_label("gpio-mockup-D"); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); + g_assert_cmpstr(gpiod_chip_name(chip), ==, gpiod_test_chip_name(3)); } -TEST_DEFINE(chip_open_lookup, - "gpiod_chip_open_lookup() - good", - 0, { 8, 8, 8 }); -static void chip_open_by_label_good(void) +GPIOD_TEST_CASE(open_by_label_bad, 0, { 4, 4, 4, 4, 4 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + struct gpiod_chip *chip; - chip = gpiod_chip_open_by_label("gpio-mockup-D"); - TEST_ASSERT_NOT_NULL(chip); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip), test_chip_name(3)); + chip = gpiod_chip_open_by_label("nonexistent_gpio_chip"); + g_assert_null(chip); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(chip_open_by_label_good, - "gpiod_chip_open_by_label() - good", - 0, { 4, 4, 4, 4, 4 }); -static void chip_open_by_label_bad(void) +GPIOD_TEST_CASE(open_lookup_good, 0, { 8, 8, 8}) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip_by_label = NULL; + g_autoptr(gpiod_chip_struct) chip_by_name = NULL; + g_autoptr(gpiod_chip_struct) chip_by_path = NULL; + g_autoptr(gpiod_chip_struct) chip_by_num = NULL; + g_autofree gchar *chip_num_str = g_strdup_printf( + "%u", gpiod_test_chip_num(1)); + + chip_by_name = gpiod_chip_open_lookup(gpiod_test_chip_name(1)); + chip_by_path = gpiod_chip_open_lookup(gpiod_test_chip_path(1)); + chip_by_num = gpiod_chip_open_lookup(chip_num_str); + chip_by_label = gpiod_chip_open_lookup("gpio-mockup-B"); - chip = gpiod_chip_open_by_label("nonexistent_gpio_chip"); - TEST_ASSERT_NULL(chip); - TEST_ASSERT_ERRNO_IS(ENOENT); + g_assert_nonnull(chip_by_name); + g_assert_nonnull(chip_by_path); + g_assert_nonnull(chip_by_num); + g_assert_nonnull(chip_by_label); + gpiod_test_return_if_failed(); + + g_assert_cmpstr(gpiod_chip_name(chip_by_name), + ==, gpiod_test_chip_name(1)); + g_assert_cmpstr(gpiod_chip_name(chip_by_path), + ==, gpiod_test_chip_name(1)); + g_assert_cmpstr(gpiod_chip_name(chip_by_num), + ==, gpiod_test_chip_name(1)); + g_assert_cmpstr(gpiod_chip_name(chip_by_label), + ==, gpiod_test_chip_name(1)); } -TEST_DEFINE(chip_open_by_label_bad, - "gpiod_chip_open_by_label() - bad", - 0, { 4, 4, 4, 4, 4 }); -static void chip_name(void) +GPIOD_TEST_CASE(get_name, 0, { 8, 8, 8}) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip0 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip1 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip2 = NULL; - - chip0 = gpiod_chip_open(test_chip_path(0)); - chip1 = gpiod_chip_open(test_chip_path(1)); - chip2 = gpiod_chip_open(test_chip_path(2)); - TEST_ASSERT_NOT_NULL(chip0); - TEST_ASSERT_NOT_NULL(chip1); - TEST_ASSERT_NOT_NULL(chip2); - - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip0), test_chip_name(0)); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip1), test_chip_name(1)); - TEST_ASSERT_STR_EQ(gpiod_chip_name(chip2), test_chip_name(2)); + g_autoptr(gpiod_chip_struct) chip0 = NULL; + g_autoptr(gpiod_chip_struct) chip1 = NULL; + g_autoptr(gpiod_chip_struct) chip2 = NULL; + + chip0 = gpiod_chip_open(gpiod_test_chip_path(0)); + chip1 = gpiod_chip_open(gpiod_test_chip_path(1)); + chip2 = gpiod_chip_open(gpiod_test_chip_path(2)); + + g_assert_nonnull(chip0); + g_assert_nonnull(chip1); + g_assert_nonnull(chip2); + gpiod_test_return_if_failed(); + + g_assert_cmpstr(gpiod_chip_name(chip0), ==, gpiod_test_chip_name(0)); + g_assert_cmpstr(gpiod_chip_name(chip1), ==, gpiod_test_chip_name(1)); + g_assert_cmpstr(gpiod_chip_name(chip2), ==, gpiod_test_chip_name(2)); } -TEST_DEFINE(chip_name, - "gpiod_chip_name()", - 0, { 8, 8, 8 }); -static void chip_label(void) +GPIOD_TEST_CASE(get_label, 0, { 8, 8, 8}) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip0 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip1 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip2 = NULL; - - chip0 = gpiod_chip_open(test_chip_path(0)); - chip1 = gpiod_chip_open(test_chip_path(1)); - chip2 = gpiod_chip_open(test_chip_path(2)); - TEST_ASSERT_NOT_NULL(chip0); - TEST_ASSERT_NOT_NULL(chip1); - TEST_ASSERT_NOT_NULL(chip2); - - TEST_ASSERT_STR_EQ(gpiod_chip_label(chip0), "gpio-mockup-A"); - TEST_ASSERT_STR_EQ(gpiod_chip_label(chip1), "gpio-mockup-B"); - TEST_ASSERT_STR_EQ(gpiod_chip_label(chip2), "gpio-mockup-C"); + g_autoptr(gpiod_chip_struct) chip0 = NULL; + g_autoptr(gpiod_chip_struct) chip1 = NULL; + g_autoptr(gpiod_chip_struct) chip2 = NULL; + + chip0 = gpiod_chip_open(gpiod_test_chip_path(0)); + chip1 = gpiod_chip_open(gpiod_test_chip_path(1)); + chip2 = gpiod_chip_open(gpiod_test_chip_path(2)); + + g_assert_nonnull(chip0); + g_assert_nonnull(chip1); + g_assert_nonnull(chip2); + gpiod_test_return_if_failed(); + + g_assert_cmpstr(gpiod_chip_label(chip0), ==, "gpio-mockup-A"); + g_assert_cmpstr(gpiod_chip_label(chip1), ==, "gpio-mockup-B"); + g_assert_cmpstr(gpiod_chip_label(chip2), ==, "gpio-mockup-C"); } -TEST_DEFINE(chip_label, - "gpiod_chip_label()", - 0, { 8, 8, 8 }); -static void chip_num_lines(void) +GPIOD_TEST_CASE(num_lines, 0, { 1, 4, 8, 16, 32 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip0 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip1 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip2 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip3 = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip4 = NULL; - - chip0 = gpiod_chip_open(test_chip_path(0)); - chip1 = gpiod_chip_open(test_chip_path(1)); - chip2 = gpiod_chip_open(test_chip_path(2)); - chip3 = gpiod_chip_open(test_chip_path(3)); - chip4 = gpiod_chip_open(test_chip_path(4)); - TEST_ASSERT_NOT_NULL(chip0); - TEST_ASSERT_NOT_NULL(chip1); - TEST_ASSERT_NOT_NULL(chip2); - TEST_ASSERT_NOT_NULL(chip3); - TEST_ASSERT_NOT_NULL(chip4); - - TEST_ASSERT_EQ(gpiod_chip_num_lines(chip0), 1); - TEST_ASSERT_EQ(gpiod_chip_num_lines(chip1), 4); - TEST_ASSERT_EQ(gpiod_chip_num_lines(chip2), 8); - TEST_ASSERT_EQ(gpiod_chip_num_lines(chip3), 16); - TEST_ASSERT_EQ(gpiod_chip_num_lines(chip4), 32); + g_autoptr(gpiod_chip_struct) chip0 = NULL; + g_autoptr(gpiod_chip_struct) chip1 = NULL; + g_autoptr(gpiod_chip_struct) chip2 = NULL; + g_autoptr(gpiod_chip_struct) chip3 = NULL; + g_autoptr(gpiod_chip_struct) chip4 = NULL; + + chip0 = gpiod_chip_open(gpiod_test_chip_path(0)); + chip1 = gpiod_chip_open(gpiod_test_chip_path(1)); + chip2 = gpiod_chip_open(gpiod_test_chip_path(2)); + chip3 = gpiod_chip_open(gpiod_test_chip_path(3)); + chip4 = gpiod_chip_open(gpiod_test_chip_path(4)); + + g_assert_nonnull(chip0); + g_assert_nonnull(chip1); + g_assert_nonnull(chip2); + g_assert_nonnull(chip3); + g_assert_nonnull(chip4); + gpiod_test_return_if_failed(); + + g_assert_cmpuint(gpiod_chip_num_lines(chip0), ==, 1); + g_assert_cmpuint(gpiod_chip_num_lines(chip1), ==, 4); + g_assert_cmpuint(gpiod_chip_num_lines(chip2), ==, 8); + g_assert_cmpuint(gpiod_chip_num_lines(chip3), ==, 16); + g_assert_cmpuint(gpiod_chip_num_lines(chip4), ==, 32); } -TEST_DEFINE(chip_num_lines, - "gpiod_chip_num_lines()", - 0, { 1, 4, 8, 16, 32 }); -static void chip_get_lines(void) +GPIOD_TEST_CASE(get_line, 0, { 16 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; - struct gpiod_line_bulk bulk; - unsigned int offsets[4]; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); + + line = gpiod_chip_get_line(chip, 3); + g_assert_nonnull(line); + g_assert_cmpuint(gpiod_line_offset(line), ==, 3); +} + +GPIOD_TEST_CASE(get_lines, 0, { 16 }) +{ + struct gpiod_line *line0, *line1, *line2, *line3; + g_autoptr(gpiod_chip_struct) chip = NULL; + struct gpiod_line_bulk bulk; + guint offsets[4]; + gint ret; + + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); offsets[0] = 1; offsets[1] = 3; offsets[2] = 4; offsets[3] = 7; - rv = gpiod_chip_get_lines(chip, offsets, 4, &bulk); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(gpiod_line_bulk_num_lines(&bulk), 4); - line = gpiod_line_bulk_get_line(&bulk, 0); - TEST_ASSERT_EQ(gpiod_line_offset(line), 1); - line = gpiod_line_bulk_get_line(&bulk, 1); - TEST_ASSERT_EQ(gpiod_line_offset(line), 3); - line = gpiod_line_bulk_get_line(&bulk, 2); - TEST_ASSERT_EQ(gpiod_line_offset(line), 4); - line = gpiod_line_bulk_get_line(&bulk, 3); - TEST_ASSERT_EQ(gpiod_line_offset(line), 7); + ret = gpiod_chip_get_lines(chip, offsets, 4, &bulk); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpuint(gpiod_line_bulk_num_lines(&bulk), ==, 4); + gpiod_test_return_if_failed(); + + line0 = gpiod_line_bulk_get_line(&bulk, 0); + line1 = gpiod_line_bulk_get_line(&bulk, 1); + line2 = gpiod_line_bulk_get_line(&bulk, 2); + line3 = gpiod_line_bulk_get_line(&bulk, 3); + + g_assert_cmpuint(gpiod_line_offset(line0), ==, 1); + g_assert_cmpuint(gpiod_line_offset(line1), ==, 3); + g_assert_cmpuint(gpiod_line_offset(line2), ==, 4); + g_assert_cmpuint(gpiod_line_offset(line3), ==, 7); } -TEST_DEFINE(chip_get_lines, - "gpiod_chip_get_lines()", - 0, { 16 }); -static void chip_get_all_lines(void) +GPIOD_TEST_CASE(get_all_lines, 0, { 4 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + struct gpiod_line *line0, *line1, *line2, *line3; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk; - struct gpiod_line *line; - int rv; - - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); - - rv = gpiod_chip_get_all_lines(chip, &bulk); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(gpiod_line_bulk_num_lines(&bulk), 4); - line = gpiod_line_bulk_get_line(&bulk, 0); - TEST_ASSERT_EQ(gpiod_line_offset(line), 0); - line = gpiod_line_bulk_get_line(&bulk, 1); - TEST_ASSERT_EQ(gpiod_line_offset(line), 1); - line = gpiod_line_bulk_get_line(&bulk, 2); - TEST_ASSERT_EQ(gpiod_line_offset(line), 2); - line = gpiod_line_bulk_get_line(&bulk, 3); - TEST_ASSERT_EQ(gpiod_line_offset(line), 3); + int ret; + + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); + + ret = gpiod_chip_get_all_lines(chip, &bulk); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpuint(gpiod_line_bulk_num_lines(&bulk), ==, 4); + gpiod_test_return_if_failed(); + + line0 = gpiod_line_bulk_get_line(&bulk, 0); + line1 = gpiod_line_bulk_get_line(&bulk, 1); + line2 = gpiod_line_bulk_get_line(&bulk, 2); + line3 = gpiod_line_bulk_get_line(&bulk, 3); + + g_assert_cmpuint(gpiod_line_offset(line0), ==, 0); + g_assert_cmpuint(gpiod_line_offset(line1), ==, 1); + g_assert_cmpuint(gpiod_line_offset(line2), ==, 2); + g_assert_cmpuint(gpiod_line_offset(line3), ==, 3); } -TEST_DEFINE(chip_get_all_lines, - "gpiod_chip_get_all_lines()", - 0, { 4 }); -static void chip_find_line_good(void) +GPIOD_TEST_CASE(find_line_good, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - chip = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_find_line(chip, "gpio-mockup-B-4"); - TEST_ASSERT_NOT_NULL(line); - TEST_ASSERT_EQ(gpiod_line_offset(line), 4); - TEST_ASSERT_STR_EQ(gpiod_line_name(line), "gpio-mockup-B-4"); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + g_assert_cmpuint(gpiod_line_offset(line), ==, 4); + g_assert_cmpstr(gpiod_line_name(line), ==, "gpio-mockup-B-4"); } -TEST_DEFINE(chip_find_line_good, - "gpiod_chip_find_line() - good", - TEST_FLAG_NAMED_LINES, { 8, 8, 8 }); -static void chip_find_line_not_found(void) +GPIOD_TEST_CASE(find_line_not_found, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - chip = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_find_line(chip, "nonexistent"); - TEST_ASSERT_NULL(line); - TEST_ASSERT_ERRNO_IS(ENOENT); + g_assert_null(line); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(chip_find_line_not_found, - "gpiod_chip_find_line() - not found", - TEST_FLAG_NAMED_LINES, { 8, 8, 8 }); -static void chip_find_lines_good(void) +GPIOD_TEST_CASE(find_lines_good, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { - static const char *names[] = { "gpio-mockup-B-3", - "gpio-mockup-B-6", - "gpio-mockup-B-7", - NULL }; + static const gchar *names[] = { "gpio-mockup-B-3", + "gpio-mockup-B-6", + "gpio-mockup-B-7", + NULL }; - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; + struct gpiod_line *line0, *line1, *line2; struct gpiod_line_bulk bulk; - struct gpiod_line *line; - int rv; - - chip = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chip); - - rv = gpiod_chip_find_lines(chip, names, &bulk); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT_EQ(gpiod_line_bulk_num_lines(&bulk), 3); - line = gpiod_line_bulk_get_line(&bulk, 0); - TEST_ASSERT_EQ(gpiod_line_offset(line), 3); - line = gpiod_line_bulk_get_line(&bulk, 1); - TEST_ASSERT_EQ(gpiod_line_offset(line), 6); - line = gpiod_line_bulk_get_line(&bulk, 2); - TEST_ASSERT_EQ(gpiod_line_offset(line), 7); + gint ret; + + chip = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); + + ret = gpiod_chip_find_lines(chip, names, &bulk); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpuint(gpiod_line_bulk_num_lines(&bulk), ==, 3); + gpiod_test_return_if_failed(); + + line0 = gpiod_line_bulk_get_line(&bulk, 0); + line1 = gpiod_line_bulk_get_line(&bulk, 1); + line2 = gpiod_line_bulk_get_line(&bulk, 2); + + g_assert_cmpuint(gpiod_line_offset(line0), ==, 3); + g_assert_cmpuint(gpiod_line_offset(line1), ==, 6); + g_assert_cmpuint(gpiod_line_offset(line2), ==, 7); } -TEST_DEFINE(chip_find_lines_good, - "gpiod_chip_find_lines() - good", - TEST_FLAG_NAMED_LINES, { 8, 8, 8 }); -static void chip_find_lines_not_found(void) +GPIOD_TEST_CASE(fine_lines_not_found, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { - static const char *names[] = { "gpio-mockup-B-3", - "nonexistent", - "gpio-mockup-B-7", - NULL }; + static const gchar *names[] = { "gpio-mockup-B-3", + "nonexistent", + "gpio-mockup-B-7", + NULL }; - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); - rv = gpiod_chip_find_lines(chip, names, &bulk); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(ENOENT); + ret = gpiod_chip_find_lines(chip, names, &bulk); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(chip_find_lines_not_found, - "gpiod_chip_find_lines() - not found", - TEST_FLAG_NAMED_LINES, { 8, 8, 8 }); diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c index 4e7cc55..c1e1ca6 100644 --- a/tests/tests-ctxless.c +++ b/tests/tests-ctxless.c @@ -2,167 +2,156 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski * Copyright (C) 2019 Bartosz Golaszewski */ -/* Test cases for the high-level API. */ - #include #include "gpiod-test.h" -static void ctxless_get_value(void) +#define GPIOD_TEST_GROUP "ctxless" + +GPIOD_TEST_CASE(get_value, 0, { 8 }) { - int rv; + gint ret; - rv = gpiod_ctxless_get_value(test_chip_name(0), 3, - false, TEST_CONSUMER); - TEST_ASSERT_EQ(rv, 0); + ret = gpiod_ctxless_get_value(gpiod_test_chip_name(0), 3, + false, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - test_debugfs_set_value(0, 3, 1); + gpiod_test_chip_set_pull(0, 3, 1); + + ret = gpiod_ctxless_get_value(gpiod_test_chip_name(0), 3, + false, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 1); +} - rv = gpiod_ctxless_get_value(test_chip_name(0), 3, - false, TEST_CONSUMER); - TEST_ASSERT_EQ(rv, 1); +static void set_value_check(gpointer data G_GNUC_UNUSED) +{ + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1); } -TEST_DEFINE(ctxless_get_value, - "ctxless get value - single line", - 0, { 8 }); -static void ctxless_set_value_check(void *data) +GPIOD_TEST_CASE(set_value, 0, { 8 }) { - int *val = data; + gint ret; + + gpiod_test_chip_set_pull(0, 3, 0); - *val = test_debugfs_get_value(0, 3); + ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1, + false, GPIOD_TEST_CONSUMER, + set_value_check, NULL); + gpiod_test_return_if_failed(); + g_assert_cmpint(ret, ==, 0); + + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0); } -static void ctxless_set_value(void) +static const guint get_value_multiple_offsets[] = { + 1, 3, 4, 5, 6, 7, 8, 9, 13, 14 +}; + +static const gint get_value_multiple_expected[] = { + 1, 1, 1, 0, 0, 0, 1, 0, 1, 1 +}; + +GPIOD_TEST_CASE(get_value_multiple, 0, { 16 }) { - int rv, val; + gint ret, values[10]; + guint i; - TEST_ASSERT_EQ(test_debugfs_get_value(0, 3), 0); + for (i = 0; i < G_N_ELEMENTS(get_value_multiple_offsets); i++) + gpiod_test_chip_set_pull(0, get_value_multiple_offsets[i], + get_value_multiple_expected[i]); - rv = gpiod_ctxless_set_value(test_chip_name(0), 3, 1, - false, TEST_CONSUMER, - ctxless_set_value_check, &val); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_ctxless_get_value_multiple(gpiod_test_chip_name(0), + get_value_multiple_offsets, + values, 10, false, + GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(val, 1); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 3), 0); + for (i = 0; i < G_N_ELEMENTS(get_value_multiple_offsets); i++) + g_assert_cmpint(values[i], ==, get_value_multiple_expected[i]); } -TEST_DEFINE(ctxless_set_value, - "ctxless set value - single line", - 0, { 8 }); -static const unsigned int ctxless_set_value_multiple_offsets[] = { +static const guint set_value_multiple_offsets[] = { 0, 1, 2, 3, 4, 5, 6, 12, 13, 15 }; -static const int ctxless_set_value_multiple_values[] = { +static const gint set_value_multiple_values[] = { 1, 1, 1, 0, 0, 1, 0, 1, 0, 0 }; -static void ctxless_set_value_multiple_check(void *data) +static void set_value_multiple_check(gpointer data G_GNUC_UNUSED) { - bool *vals_correct = data; - unsigned int offset, i; - int val, exp; - - for (i = 0; - i < TEST_ARRAY_SIZE(ctxless_set_value_multiple_values); - i++) { - offset = ctxless_set_value_multiple_offsets[i]; - exp = ctxless_set_value_multiple_values[i]; - val = test_debugfs_get_value(0, offset); - - if (val != exp) { - *vals_correct = false; - break; - } + guint i, offset; + gint val, exp; + + for (i = 0; i < G_N_ELEMENTS(set_value_multiple_values); i++) { + offset = set_value_multiple_offsets[i]; + exp = set_value_multiple_values[i]; + val = gpiod_test_chip_get_value(0, offset); + + g_assert_cmpint(val, ==, exp); } } -static void ctxless_set_get_value_multiple(void) +GPIOD_TEST_CASE(set_value_multiple, 0, { 16 }) { - bool vals_correct = true; - int values[10], rv; - unsigned int i; - - for (i = 0; - i < TEST_ARRAY_SIZE(ctxless_set_value_multiple_offsets); - i++) { - TEST_ASSERT_EQ(test_debugfs_get_value(0, - ctxless_set_value_multiple_offsets[i]), 0); - } + gint values[10], ret; + guint i; - for (i = 0; - i < TEST_ARRAY_SIZE(ctxless_set_value_multiple_values); - i++) { - values[i] = ctxless_set_value_multiple_values[i]; - } + for (i = 0; i < G_N_ELEMENTS(set_value_multiple_offsets); i++) + values[i] = set_value_multiple_values[i]; - rv = gpiod_ctxless_set_value_multiple(test_chip_name(0), - ctxless_set_value_multiple_offsets, - values, 10, false, TEST_CONSUMER, - ctxless_set_value_multiple_check, - &vals_correct); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT(vals_correct); + ret = gpiod_ctxless_set_value_multiple(gpiod_test_chip_name(0), + set_value_multiple_offsets, values, 10, false, + GPIOD_TEST_CONSUMER, set_value_multiple_check, NULL); + gpiod_test_return_if_failed(); + g_assert_cmpint(ret, ==, 0); } -TEST_DEFINE(ctxless_set_get_value_multiple, - "ctxless set/get value - multiple lines", - 0, { 16 }); -static void ctxless_get_value_multiple_max_lines(void) +GPIOD_TEST_CASE(get_value_multiple_max_lines, 0, { 128 }) { - unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; - int values[GPIOD_LINE_BULK_MAX_LINES + 1], rv; - - rv = gpiod_ctxless_get_value_multiple(test_chip_name(0), offsets, - values, - GPIOD_LINE_BULK_MAX_LINES + 1, - false, TEST_CONSUMER); - TEST_ASSERT_NOTEQ(rv, 0); - TEST_ASSERT_ERRNO_IS(EINVAL); + gint values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; + guint offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; + + ret = gpiod_ctxless_get_value_multiple(gpiod_test_chip_name(0), + offsets, values, + GPIOD_LINE_BULK_MAX_LINES + 1, + false, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(ctxless_get_value_multiple_max_lines, - "gpiod_ctxless_get_value_multiple() exceed max lines", - 0, { 128 }); -static void ctxless_set_value_multiple_max_lines(void) +GPIOD_TEST_CASE(set_value_multiple_max_lines, 0, { 128 }) { - unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; - int values[GPIOD_LINE_BULK_MAX_LINES + 1], rv; - - rv = gpiod_ctxless_set_value_multiple(test_chip_name(0), offsets, - values, - GPIOD_LINE_BULK_MAX_LINES + 1, - false, TEST_CONSUMER, - NULL, NULL); - TEST_ASSERT_NOTEQ(rv, 0); - TEST_ASSERT_ERRNO_IS(EINVAL); + gint values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; + guint offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; + + ret = gpiod_ctxless_set_value_multiple(gpiod_test_chip_name(0), + offsets, values, GPIOD_LINE_BULK_MAX_LINES + 1, + false, GPIOD_TEST_CONSUMER, NULL, NULL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(ctxless_set_value_multiple_max_lines, - "gpiod_ctxless_set_value_multiple() exceed max lines", - 0, { 128 }); struct ctxless_event_data { - bool got_rising_edge; - bool got_falling_edge; - unsigned int offset; - unsigned int count; + gboolean got_rising_edge; + gboolean got_falling_edge; + guint offset; + guint count; }; -static int ctxless_event_cb(int evtype, unsigned int offset, - const struct timespec *ts TEST_UNUSED, void *data) +static int ctxless_event_cb(gint evtype, guint offset, + const struct timespec *ts G_GNUC_UNUSED, + gpointer data) { struct ctxless_event_data *evdata = data; if (evtype == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE) - evdata->got_rising_edge = true; + evdata->got_rising_edge = TRUE; else if (evtype == GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE) - evdata->got_falling_edge = true; + evdata->got_falling_edge = TRUE; evdata->offset = offset; @@ -170,170 +159,157 @@ static int ctxless_event_cb(int evtype, unsigned int offset, : GPIOD_CTXLESS_EVENT_CB_RET_OK; } -static void ctxless_event_monitor(void) +GPIOD_TEST_CASE(event_monitor, 0, { 8 }) { + g_autoptr(GpiodTestEventThread) ev_thread = NULL; struct ctxless_event_data evdata = { false, false, 0, 0 }; struct timespec ts = { 1, 0 }; - int rv; - - test_set_event(0, 3, 100); - - rv = gpiod_ctxless_event_monitor(test_chip_name(0), - GPIOD_CTXLESS_EVENT_BOTH_EDGES, - 3, false, TEST_CONSUMER, &ts, - NULL, ctxless_event_cb, &evdata); - - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT(evdata.got_rising_edge); - TEST_ASSERT(evdata.got_falling_edge); - TEST_ASSERT_EQ(evdata.count, 2); - TEST_ASSERT_EQ(evdata.offset, 3); + gint ret; + + ev_thread = gpiod_test_start_event_thread(0, 3, 100); + + ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0), + GPIOD_CTXLESS_EVENT_BOTH_EDGES, + 3, false, GPIOD_TEST_CONSUMER, &ts, + NULL, ctxless_event_cb, &evdata); + g_assert_cmpint(ret, ==, 0); + g_assert_true(evdata.got_rising_edge); + g_assert_true(evdata.got_falling_edge); + g_assert_cmpuint(evdata.count, ==, 2); + g_assert_cmpuint(evdata.offset, ==, 3); } -TEST_DEFINE(ctxless_event_monitor, - "gpiod_ctxless_event_monitor() - single event", - 0, { 8 }); -static void ctxless_event_monitor_single_event_type(void) +GPIOD_TEST_CASE(event_monitor_single_event_type, 0, { 8 }) { + g_autoptr(GpiodTestEventThread) ev_thread = NULL; struct ctxless_event_data evdata = { false, false, 0, 0 }; struct timespec ts = { 1, 0 }; - int rv; - - test_set_event(0, 3, 100); - - rv = gpiod_ctxless_event_monitor(test_chip_name(0), - GPIOD_CTXLESS_EVENT_FALLING_EDGE, - 3, false, TEST_CONSUMER, &ts, - NULL, ctxless_event_cb, &evdata); - - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT(evdata.got_falling_edge); - TEST_ASSERT_FALSE(evdata.got_rising_edge); - TEST_ASSERT_EQ(evdata.count, 2); - TEST_ASSERT_EQ(evdata.offset, 3); + gint ret; + + ev_thread = gpiod_test_start_event_thread(0, 3, 100); + + ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0), + GPIOD_CTXLESS_EVENT_FALLING_EDGE, + 3, false, GPIOD_TEST_CONSUMER, &ts, + NULL, ctxless_event_cb, &evdata); + g_assert_cmpint(ret, ==, 0); + g_assert_false(evdata.got_rising_edge); + g_assert_true(evdata.got_falling_edge); + g_assert_cmpuint(evdata.count, ==, 2); + g_assert_cmpuint(evdata.offset, ==, 3); } -TEST_DEFINE(ctxless_event_monitor_single_event_type, - "gpiod_ctxless_event_monitor() - specify event type", - 0, { 8 }); -static void ctxless_event_monitor_multiple(void) +GPIOD_TEST_CASE(event_monitor_multiple, 0, { 8 }) { + g_autoptr(GpiodTestEventThread) ev_thread = NULL; struct ctxless_event_data evdata = { false, false, 0, 0 }; struct timespec ts = { 1, 0 }; - unsigned int offsets[4]; - int rv; + guint offsets[4]; + gint ret; offsets[0] = 2; offsets[1] = 3; offsets[2] = 5; offsets[3] = 6; - test_set_event(0, 3, 100); - - rv = gpiod_ctxless_event_monitor_multiple( - test_chip_name(0), - GPIOD_CTXLESS_EVENT_BOTH_EDGES, - offsets, 4, false, TEST_CONSUMER, - &ts, NULL, ctxless_event_cb, &evdata); + ev_thread = gpiod_test_start_event_thread(0, 3, 100); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT(evdata.got_rising_edge); - TEST_ASSERT(evdata.got_falling_edge); - TEST_ASSERT_EQ(evdata.count, 2); - TEST_ASSERT_EQ(evdata.offset, 3); + ret = gpiod_ctxless_event_monitor_multiple(gpiod_test_chip_name(0), + GPIOD_CTXLESS_EVENT_BOTH_EDGES, offsets, 4, false, + GPIOD_TEST_CONSUMER, &ts, NULL, ctxless_event_cb, &evdata); + g_assert_cmpint(ret, ==, 0); + g_assert_true(evdata.got_rising_edge); + g_assert_true(evdata.got_falling_edge); + g_assert_cmpuint(evdata.count, ==, 2); + g_assert_cmpuint(evdata.offset, ==, 3); } -TEST_DEFINE(ctxless_event_monitor_multiple, - "gpiod_ctxless_event_monitor_multiple() - single event", - 0, { 8 }); - -static int error_event_cb(int evtype TEST_UNUSED, - unsigned int offset TEST_UNUSED, - const struct timespec *ts TEST_UNUSED, - void *data TEST_UNUSED) + +static int error_event_cb(gint evtype G_GNUC_UNUSED, + guint offset G_GNUC_UNUSED, + const struct timespec *ts G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED) { errno = ENOTBLK; return GPIOD_CTXLESS_EVENT_CB_RET_ERR; } -static void ctxless_event_monitor_indicate_error(void) +GPIOD_TEST_CASE(event_monitor_indicate_error, 0, { 8 }) { + g_autoptr(GpiodTestEventThread) ev_thread = NULL; struct timespec ts = { 1, 0 }; - int rv; - - test_set_event(0, 3, 100); + gint ret; - rv = gpiod_ctxless_event_monitor(test_chip_name(0), - GPIOD_CTXLESS_EVENT_BOTH_EDGES, - 3, false, TEST_CONSUMER, &ts, - NULL, error_event_cb, NULL); + ev_thread = gpiod_test_start_event_thread(0, 3, 100); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(ENOTBLK); + ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0), + GPIOD_CTXLESS_EVENT_BOTH_EDGES, + 3, false, GPIOD_TEST_CONSUMER, &ts, + NULL, error_event_cb, NULL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, ENOTBLK); } -TEST_DEFINE(ctxless_event_monitor_indicate_error, - "gpiod_ctxless_event_monitor() - error in callback", - 0, { 8 }); -static void ctxless_event_monitor_indicate_error_timeout(void) +static int error_event_cb_timeout(gint evtype, + guint offset G_GNUC_UNUSED, + const struct timespec *ts G_GNUC_UNUSED, + gpointer data G_GNUC_UNUSED) { - struct timespec ts = { 0, 100000 }; - int rv; + errno = ENOTBLK; - rv = gpiod_ctxless_event_monitor(test_chip_name(0), - GPIOD_CTXLESS_EVENT_BOTH_EDGES, - 3, false, TEST_CONSUMER, &ts, - NULL, error_event_cb, NULL); + g_assert_cmpint(evtype, ==, GPIOD_CTXLESS_EVENT_CB_TIMEOUT); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(ENOTBLK); + return GPIOD_CTXLESS_EVENT_CB_RET_ERR; +} + +GPIOD_TEST_CASE(event_monitor_indicate_error_timeout, 0, { 8 }) +{ + struct timespec ts = { 0, 100000 }; + gint ret; + + ret = gpiod_ctxless_event_monitor(gpiod_test_chip_name(0), + GPIOD_CTXLESS_EVENT_BOTH_EDGES, + 3, false, GPIOD_TEST_CONSUMER, &ts, + NULL, error_event_cb_timeout, NULL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, ENOTBLK); } -TEST_DEFINE(ctxless_event_monitor_indicate_error_timeout, - "gpiod_ctxless_event_monitor() - error in callback after timeout", - 0, { 8 }); -static void ctxless_find_line_good(void) +GPIOD_TEST_CASE(find_line, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }) { - unsigned int offset; - char chip[32]; - int rv; - - rv = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 1); - TEST_ASSERT_EQ(offset, 14); - TEST_ASSERT_STR_EQ(chip, test_chip_name(2)); + gchar chip[32]; + guint offset; + gint ret; + + ret = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, + sizeof(chip), &offset); + g_assert_cmpint(ret, ==, 1); + g_assert_cmpuint(offset, ==, 14); + g_assert_cmpstr(chip, ==, gpiod_test_chip_name(2)); } -TEST_DEFINE(ctxless_find_line_good, - "gpiod_ctxless_find_line() - good", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); -static void ctxless_find_line_truncated(void) +GPIOD_TEST_CASE(find_line_truncated, + GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }) { - unsigned int offset; - char chip[6]; - int rv; - - rv = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 1); - TEST_ASSERT_EQ(offset, 14); - TEST_ASSERT_STR_EQ(chip, "gpioc"); + gchar chip[6]; + guint offset; + gint ret; + + ret = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, + sizeof(chip), &offset); + g_assert_cmpint(ret, ==, 1); + g_assert_cmpuint(offset, ==, 14); + g_assert_cmpstr(chip, ==, "gpioc"); } -TEST_DEFINE(ctxless_find_line_truncated, - "gpiod_ctxless_find_line() - chip name truncated", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); -static void ctxless_find_line_not_found(void) +GPIOD_TEST_CASE(find_line_not_found, + GPIOD_TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }) { - unsigned int offset; - char chip[32]; - int rv; + gchar chip[32]; + guint offset; + gint ret; - rv = gpiod_ctxless_find_line("nonexistent", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 0); + ret = gpiod_ctxless_find_line("nonexistent", chip, + sizeof(chip), &offset); + g_assert_cmpint(ret, ==, 0); } -TEST_DEFINE(ctxless_find_line_not_found, - "gpiod_ctxless_find_line() - not found", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); diff --git a/tests/tests-event.c b/tests/tests-event.c index b97b6f8..51b2281 100644 --- a/tests/tests-event.c +++ b/tests/tests-event.c @@ -2,324 +2,346 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski * Copyright (C) 2019 Bartosz Golaszewski */ -/* Test cases for GPIO line events. */ - #include #include #include "gpiod-test.h" -static void event_rising_edge_good(void) +#define GPIOD_TEST_GROUP "event" + +GPIOD_TEST_CASE(rising_edge_good, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct timespec ts = { 1, 0 }; struct gpiod_line_event ev; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_rising_edge_events(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ev_thread = gpiod_test_start_event_thread(0, 7, 100); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); - rv = gpiod_line_event_read(line, &ev); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); } -TEST_DEFINE(event_rising_edge_good, - "events - receive single rising edge event", - 0, { 8 }); -static void event_falling_edge_good(void) +GPIOD_TEST_CASE(falling_edge_good, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct timespec ts = { 1, 0 }; struct gpiod_line_event ev; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_falling_edge_events(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_falling_edge_events(line, + GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ev_thread = gpiod_test_start_event_thread(0, 7, 100); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); - rv = gpiod_line_event_read(line, &ev); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_FALLING_EDGE); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE); } -TEST_DEFINE(event_falling_edge_good, - "events - receive single falling edge event", - 0, { 8 }); -static void event_rising_edge_ignore_falling(void) +GPIOD_TEST_CASE(rising_edge_ignore_falling, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; - struct timespec ts = { 0, 300 }; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; + struct timespec ts = { 1, 0 }; + struct gpiod_line_event ev[3]; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + + ret = gpiod_line_request_rising_edge_events(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); + + ev_thread = gpiod_test_start_event_thread(0, 7, 100); + + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); + ret = gpiod_line_event_read(line, &ev[0]); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); + ret = gpiod_line_event_read(line, &ev[1]); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); + ret = gpiod_line_event_read(line, &ev[2]); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 0); + g_assert_cmpint(ev[0].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); + g_assert_cmpint(ev[1].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); + g_assert_cmpint(ev[2].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); } -TEST_DEFINE(event_rising_edge_ignore_falling, - "events - request rising edge & ignore falling edge events", - 0, { 8 }); -static void event_rising_edge_active_low(void) +GPIOD_TEST_CASE(rising_edge_active_low, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct timespec ts = { 1, 0 }; struct gpiod_line_event ev; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_rising_edge_events_flags(line, TEST_CONSUMER, - GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_rising_edge_events_flags(line, + GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ev_thread = gpiod_test_start_event_thread(0, 7, 100); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); - rv = gpiod_line_event_read(line, &ev); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); } -TEST_DEFINE(event_rising_edge_active_low, - "events - single rising edge event with low active state", - 0, { 8 }); -static void event_get_value(void) +GPIOD_TEST_CASE(get_value, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct timespec ts = { 1, 0 }; struct gpiod_line_event ev; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + gpiod_test_chip_set_pull(0, 7, 1); - rv = gpiod_line_get_value(line); - TEST_ASSERT_EQ(rv, 0); + ret = gpiod_line_request_falling_edge_events(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ret = gpiod_line_get_value(line); + g_assert_cmpint(ret, ==, 1); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 1); + ev_thread = gpiod_test_start_event_thread(0, 7, 100); - rv = gpiod_line_event_read(line, &ev); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); - TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE); + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_get_value(line); - TEST_ASSERT_EQ(rv, 1); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE); } -TEST_DEFINE(event_get_value, - "events - mixing events and gpiod_line_get_value()", - 0, { 8 }); -static void event_get_value_active_low(void) +GPIOD_TEST_CASE(get_value_active_low, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct timespec ts = { 1, 0 }; struct gpiod_line_event ev; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_falling_edge_events_flags(line, TEST_CONSUMER, - GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); - TEST_ASSERT_RET_OK(rv); + gpiod_test_chip_set_pull(0, 7, 1); - rv = gpiod_line_get_value(line); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_request_falling_edge_events_flags(line, + GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 7, 100); + ret = gpiod_line_get_value(line); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, 1); + ev_thread = gpiod_test_start_event_thread(0, 7, 100); - rv = gpiod_line_event_read(line, &ev); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, 1); - TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_FALLING_EDGE); + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_get_value(line); - TEST_ASSERT_EQ(rv, 1); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE); } -TEST_DEFINE(event_get_value_active_low, - "events - mixing events and gpiod_line_get_value() (active-low flag)", - 0, { 8 }); -static void event_wait_multiple(void) +GPIOD_TEST_CASE(wait_multiple, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(GpiodTestEventThread) ev_thread = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk, event_bulk; struct timespec ts = { 1, 0 }; + struct gpiod_line_event ev; struct gpiod_line *line; - int rv, i; + gint ret, i; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulk); - for (i = 0; i < 8; i++) { line = gpiod_chip_get_line(chip, i); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line); } - rv = gpiod_line_request_bulk_both_edges_events(&bulk, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_bulk_rising_edge_events(&bulk, + GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - test_set_event(0, 4, 100); + ev_thread = gpiod_test_start_event_thread(0, 4, 100); - rv = gpiod_line_event_wait_bulk(&bulk, &ts, &event_bulk); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_event_wait_bulk(&bulk, &ts, &event_bulk); + g_assert_cmpint(ret, ==, 1); - TEST_ASSERT_EQ(gpiod_line_bulk_num_lines(&event_bulk), 1); + g_assert_cmpuint(gpiod_line_bulk_num_lines(&event_bulk), ==, 1); line = gpiod_line_bulk_get_line(&event_bulk, 0); - TEST_ASSERT_EQ(gpiod_line_offset(line), 4); + g_assert_cmpuint(gpiod_line_offset(line), ==, 4); + + ret = gpiod_line_event_read(line, &ev); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE); } -TEST_DEFINE(event_wait_multiple, - "events - wait for events on multiple lines", - 0, { 8 }); -static void event_get_fd_when_values_requested(void) +GPIOD_TEST_CASE(get_fd_when_values_requested, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv, fd; + gint ret, fd; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 3); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); fd = gpiod_line_event_get_fd(line); - TEST_ASSERT_EQ(fd, -1); - TEST_ASSERT_ERRNO_IS(EPERM); + g_assert_cmpint(fd, ==, -1); + g_assert_cmpint(errno, ==, EPERM); } -TEST_DEFINE(event_get_fd_when_values_requested, - "events - gpiod_line_event_get_fd(): line requested for values", - 0, { 8 }); -static void event_request_bulk_fail(void) +GPIOD_TEST_CASE(request_bulk_fail, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line; - int rv, i; + gint ret, i; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); - line = gpiod_chip_get_line(chip, 5); - TEST_ASSERT_NOT_NULL(line); + line = gpiod_chip_get_line(chip, 7); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); for (i = 0; i < 8; i++) { line = gpiod_chip_get_line(chip, i); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line); } - rv = gpiod_line_request_bulk_both_edges_events(&bulk, TEST_CONSUMER); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EBUSY); + ret = gpiod_line_request_bulk_both_edges_events(&bulk, + GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EBUSY); } -TEST_DEFINE(event_request_bulk_fail, - "events - failed bulk request (test reversed release)", - 0, { 8 }); -static void event_invalid_fd(void) +GPIOD_TEST_CASE(invalid_fd, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line_bulk ev_bulk; struct timespec ts = { 1, 0 }; struct gpiod_line *line; - int rv, fd; + gint ret, fd; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); - line = gpiod_chip_get_line(chip, 5); - TEST_ASSERT_NOT_NULL(line); + line = gpiod_chip_get_line(chip, 7); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_both_edges_events(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_both_edges_events(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); fd = gpiod_line_event_get_fd(line); close(fd); - rv = gpiod_line_event_wait(line, &ts); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + ret = gpiod_line_event_wait(line, &ts); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); /* * The single line variant calls gpiod_line_event_wait_bulk() with the @@ -327,10 +349,7 @@ static void event_invalid_fd(void) * as well. */ gpiod_line_bulk_add(&bulk, line); - rv = gpiod_line_event_wait_bulk(&bulk, &ts, &ev_bulk); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + ret = gpiod_line_event_wait_bulk(&bulk, &ts, &ev_bulk); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(event_invalid_fd, - "events - gpiod_line_event_wait() error on closed fd", - 0, { 8 }); diff --git a/tests/tests-gpiodetect.c b/tests/tests-gpiodetect.c deleted file mode 100644 index bd5eeb1..0000000 --- a/tests/tests-gpiodetect.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - */ - -/* Test cases for the gpiodetect program. */ - -#include - -#include "gpiod-test.h" - -static void gpiodetect_simple(void) -{ - test_tool_run("gpiodetect", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s [gpio-mockup-A] (4 lines)", - test_chip_name(0))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s [gpio-mockup-B] (8 lines)", - test_chip_name(1))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s [gpio-mockup-C] (16 lines)", - test_chip_name(2))); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpiodetect_simple, - "tools: gpiodetect - simple", - 0, { 4, 8, 16 }); - -static void gpiodetect_invalid_args(void) -{ - test_tool_run("gpiodetect", "unused argument", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), "unrecognized argument"); -} -TEST_DEFINE(gpiodetect_invalid_args, - "tools: gpiodetect - invalid arguments", - 0, { }); diff --git a/tests/tests-gpiofind.c b/tests/tests-gpiofind.c deleted file mode 100644 index 6d8e12a..0000000 --- a/tests/tests-gpiofind.c +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - */ - -/* Test cases for the gpiofind program. */ - -#include - -#include "gpiod-test.h" - -static void gpiofind_found(void) -{ - test_tool_run("gpiofind", "gpio-mockup-B-7", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), - test_build_str("%s 7\n", test_chip_name(1))); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpiofind_found, - "tools: gpiofind - found", - TEST_FLAG_NAMED_LINES, { 4, 8 }); - -static void gpiofind_not_found(void) -{ - test_tool_run("gpiofind", "nonexistent", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpiofind_not_found, - "tools: gpiofind - not found", - TEST_FLAG_NAMED_LINES, { 4, 8 }); - -static void gpiofind_invalid_args(void) -{ - test_tool_run("gpiofind", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "exactly one GPIO line name must be specified"); - - test_tool_run("gpiofind", "first argument", - "second argument", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "exactly one GPIO line name must be specified"); -} -TEST_DEFINE(gpiofind_invalid_args, - "tools: gpiofind - invalid arguments", - 0, { }); diff --git a/tests/tests-gpioget.c b/tests/tests-gpioget.c deleted file mode 100644 index 91796ac..0000000 --- a/tests/tests-gpioget.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - * Copyright (C) 2019 Bartosz Golaszewski - */ - -/* Test cases for the gpioget program. */ - -#include "gpiod-test.h" - -static void gpioget_read_all_lines(void) -{ - test_debugfs_set_value(1, 2, 1); - test_debugfs_set_value(1, 3, 1); - test_debugfs_set_value(1, 5, 1); - test_debugfs_set_value(1, 7, 1); - - test_tool_run("gpioget", test_chip_name(1), - "0", "1", "2", "3", "4", "5", "6", "7", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "0 0 1 1 0 1 0 1\n"); -} -TEST_DEFINE(gpioget_read_all_lines, - "tools: gpioget - read all lines", - 0, { 8, 8, 8 }); - -static void gpioget_read_all_lines_active_low(void) -{ - test_debugfs_set_value(1, 2, 1); - test_debugfs_set_value(1, 3, 1); - test_debugfs_set_value(1, 5, 1); - test_debugfs_set_value(1, 7, 1); - - test_tool_run("gpioget", "--active-low", test_chip_name(1), - "0", "1", "2", "3", "4", "5", "6", "7", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "1 1 0 0 1 0 1 0\n"); -} -TEST_DEFINE(gpioget_read_all_lines_active_low, - "tools: gpioget - read all lines (active-low)", - 0, { 8, 8, 8 }); - -static void gpioget_read_some_lines(void) -{ - test_debugfs_set_value(1, 1, 1); - test_debugfs_set_value(1, 4, 1); - test_debugfs_set_value(1, 6, 1); - - test_tool_run("gpioget", test_chip_name(1), - "0", "1", "4", "6", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "0 1 1 1\n"); -} -TEST_DEFINE(gpioget_read_some_lines, - "tools: gpioget - read some lines", - 0, { 8, 8, 8 }); - -static void gpioget_no_arguments(void) -{ - test_tool_run("gpioget", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "gpiochip must be specified"); -} -TEST_DEFINE(gpioget_no_arguments, - "tools: gpioget - no arguments", - 0, { }); - -static void gpioget_no_lines_specified(void) -{ - test_tool_run("gpioget", test_chip_name(1), (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "at least one GPIO line offset must be specified"); -} -TEST_DEFINE(gpioget_no_lines_specified, - "tools: gpioget - no lines specified", - 0, { 4, 4 }); - -static void gpioget_too_many_lines_specified(void) -{ - test_tool_run("gpioget", test_chip_name(0), - "0", "1", "2", "3", "4", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "error reading GPIO values"); -} -TEST_DEFINE(gpioget_too_many_lines_specified, - "tools: gpioget - too many lines specified", - 0, { 4 }); diff --git a/tests/tests-gpioinfo.c b/tests/tests-gpioinfo.c deleted file mode 100644 index 162896f..0000000 --- a/tests/tests-gpioinfo.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - */ - -/* Test cases for the gpioinfo program. */ - -#include - -#include "gpiod-test.h" - -static void gpioinfo_dump_all_chips(void) -{ - test_tool_run("gpioinfo", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(0))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 8 lines:", - test_chip_name(1))); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high"); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high"); -} -TEST_DEFINE(gpioinfo_dump_all_chips, - "tools: gpioinfo - dump all chips", - 0, { 4, 8 }); - -static void gpioinfo_dump_all_chips_one_exported(void) -{ - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; - struct gpiod_line *line; - int rv; - - chip = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chip); - - line = gpiod_chip_get_line(chip, 7); - TEST_ASSERT_NOT_NULL(line); - - rv = gpiod_line_request_input_flags(line, TEST_CONSUMER, - GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); - TEST_ASSERT_RET_OK(rv); - - test_tool_run("gpioinfo", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(0))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 8 lines:", - test_chip_name(1))); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high"); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+7:\\s+unnamed\\s+\\\"" TEST_CONSUMER "\\\"\\s+input\\s+active-low"); -} -TEST_DEFINE(gpioinfo_dump_all_chips_one_exported, - "tools: gpioinfo - dump all chips (one line exported)", - 0, { 4, 8 }); - -static void gpioinfo_dump_one_chip(void) -{ - test_tool_run("gpioinfo", test_chip_name(1), (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_NOTCONT(test_tool_stdout(), - test_build_str("%s - 8 lines:", - test_chip_name(0))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(1))); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high"); - TEST_ASSERT_REGEX_NOMATCH(test_tool_stdout(), - "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high"); -} -TEST_DEFINE(gpioinfo_dump_one_chip, - "tools: gpioinfo - dump one chip", - 0, { 8, 4 }); - -static void gpioinfo_dump_all_but_one_chip(void) -{ - test_tool_run("gpioinfo", test_chip_name(0), - test_chip_name(1), test_chip_name(3), (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_NOTCONT(test_tool_stdout(), - test_build_str("%s - 8 lines:", - test_chip_name(2))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(0))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(1))); - TEST_ASSERT_STR_CONTAINS(test_tool_stdout(), - test_build_str("%s - 4 lines:", - test_chip_name(3))); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high"); - TEST_ASSERT_REGEX_NOMATCH(test_tool_stdout(), - "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high"); -} -TEST_DEFINE(gpioinfo_dump_all_but_one_chip, - "tools: gpioinfo - dump all but one chip", - 0, { 4, 4, 8, 4 }); - -static void gpioinfo_inexistent_chip(void) -{ - test_tool_run("gpioinfo", "inexistent", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "looking up chip inexistent"); -} -TEST_DEFINE(gpioinfo_inexistent_chip, - "tools: gpioinfo - inexistent chip", - 0, { 8, 4 }); diff --git a/tests/tests-gpiomon.c b/tests/tests-gpiomon.c deleted file mode 100644 index 7440d65..0000000 --- a/tests/tests-gpiomon.c +++ /dev/null @@ -1,378 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - * Copyright (C) 2019 Bartosz Golaszewski - */ - -/* Test cases for the gpiomon program. */ - -#include -#include - -#include "gpiod-test.h" - -static void gpiomon_single_rising_edge_event(void) -{ - test_tool_run("gpiomon", "--rising-edge", "--num-events=1", - test_chip_name(1), "4", (char *)NULL); - test_set_event(1, 4, 200); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); -} -TEST_DEFINE(gpiomon_single_rising_edge_event, - "tools: gpiomon - single rising edge event", - 0, { 8, 8 }); - -static void gpiomon_single_rising_edge_event_active_low(void) -{ - test_tool_run("gpiomon", "--rising-edge", "--num-events=1", - "--active-low", test_chip_name(1), "4", (char *)NULL); - test_set_event(1, 4, 200); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); -} -TEST_DEFINE(gpiomon_single_rising_edge_event_active_low, - "tools: gpiomon - single rising edge event (active-low)", - 0, { 8, 8 }); - -static void gpiomon_single_rising_edge_event_silent(void) -{ - test_tool_run("gpiomon", "--rising-edge", "--num-events=1", - "--silent", test_chip_name(1), "4", (char *)NULL); - test_set_event(1, 4, 200); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpiomon_single_rising_edge_event_silent, - "tools: gpiomon - single rising edge event (silent mode)", - 0, { 8, 8 }); - -static void gpiomon_four_alternating_events(void) -{ - test_tool_run("gpiomon", "--num-events=4", - test_chip_name(1), "4", (char *)NULL); - test_set_event(1, 4, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+FALLING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); -} -TEST_DEFINE(gpiomon_four_alternating_events, - "tools: gpiomon - four alternating events", - 0, { 8, 8 }); - -static void gpiomon_falling_edge_events_sigint(void) -{ - test_tool_run("gpiomon", "--falling-edge", - test_chip_name(0), "4", (char *)NULL); - test_set_event(0, 4, 100); - usleep(400000); - test_tool_signal(SIGINT); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+FALLING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); -} -TEST_DEFINE(gpiomon_falling_edge_events_sigint, - "tools: gpiomon - receive falling edge events and kill with SIGINT", - 0, { 8, 8 }); - -static void gpiomon_both_events_sigterm(void) -{ - test_tool_run("gpiomon", "--falling-edge", "--rising-edge", - test_chip_name(0), "4", (char *)NULL); - test_set_event(0, 4, 100); - usleep(400000); - test_tool_signal(SIGTERM); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+FALLING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), - "event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]"); -} -TEST_DEFINE(gpiomon_both_events_sigterm, - "tools: gpiomon - receive both types of events and kill with SIGTERM", - 0, { 8, 8 }); - -static void gpiomon_watch_multiple_lines(void) -{ - test_tool_run("gpiomon", "--format=%o", test_chip_name(0), - "1", "2", "3", "4", "5", (char *)NULL); - usleep(100000); - test_trigger_event(0, 2); - usleep(100000); - test_trigger_event(0, 3); - usleep(100000); - test_trigger_event(0, 4); - usleep(100000); - test_tool_signal(SIGTERM); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "2\n3\n4\n"); - -} -TEST_DEFINE(gpiomon_watch_multiple_lines, - "tools: gpiomon - watch multiple lines", - 0, { 8, 8 }); - -static void gpiomon_watch_multiple_lines_not_in_order(void) -{ - test_tool_run("gpiomon", "--format=%o", test_chip_name(0), - "5", "2", "7", "1", "6", (char *)NULL); - usleep(100000); - test_trigger_event(0, 2); - usleep(100000); - test_trigger_event(0, 1); - usleep(100000); - test_trigger_event(0, 6); - usleep(100000); - test_tool_signal(SIGTERM); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "2\n1\n6\n"); - -} -TEST_DEFINE(gpiomon_watch_multiple_lines_not_in_order, - "tools: gpiomon - watch multiple lines (offsets not in order)", - 0, { 8, 8 }); - -static void gpiomon_request_the_same_line_twice(void) -{ - test_tool_run("gpiomon", test_chip_name(0), "2", "2", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "error waiting for events"); -} -TEST_DEFINE(gpiomon_request_the_same_line_twice, - "tools: gpiomon - request the same line twice", - 0, { 8, 8 }); - -static void gpiomon_no_arguments(void) -{ - test_tool_run("gpiomon", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "gpiochip must be specified"); -} -TEST_DEFINE(gpiomon_no_arguments, - "tools: gpiomon - no arguments", - 0, { }); - -static void gpiomon_line_not_specified(void) -{ - test_tool_run("gpiomon", test_chip_name(1), (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "GPIO line offset must be specified"); -} -TEST_DEFINE(gpiomon_line_not_specified, - "tools: gpiomon - line not specified", - 0, { 4, 4 }); - -static void gpiomon_line_out_of_range(void) -{ - test_tool_run("gpiomon", test_chip_name(0), "4", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "error waiting for events"); -} -TEST_DEFINE(gpiomon_line_out_of_range, - "tools: gpiomon - line out of range", - 0, { 4 }); - -static void gpiomon_custom_format_event_and_offset(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%e %o", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "1 3\n"); -} -TEST_DEFINE(gpiomon_custom_format_event_and_offset, - "tools: gpiomon - custom output format: event and offset", - 0, { 8, 8 }); - -static void gpiomon_custom_format_event_and_offset_joined(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%e%o", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "13\n"); -} -TEST_DEFINE(gpiomon_custom_format_event_and_offset_joined, - "tools: gpiomon - custom output format: event and offset, joined strings", - 0, { 8, 8 }); - -static void gpiomon_custom_format_timestamp(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%e %o %s.%n", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_REGEX_MATCH(test_tool_stdout(), "1 3 [0-9]+\\.[0-9]+"); -} -TEST_DEFINE(gpiomon_custom_format_timestamp, - "tools: gpiomon - custom output format: timestamp", - 0, { 8, 8 }); - -static void gpiomon_custom_format_double_percent_sign(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%%", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "%\n"); -} -TEST_DEFINE(gpiomon_custom_format_double_percent_sign, - "tools: gpiomon - custom output format: double percent sign", - 0, { 8, 8 }); - -static void gpiomon_custom_format_double_percent_sign_and_spec(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%%e", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "%e\n"); -} -TEST_DEFINE(gpiomon_custom_format_double_percent_sign_and_spec, - "tools: gpiomon - custom output format: double percent sign with specifier", - 0, { 8, 8 }); - -static void gpiomon_custom_format_single_percent_sign(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "%\n"); -} -TEST_DEFINE(gpiomon_custom_format_single_percent_sign, - "tools: gpiomon - custom output format: single percent sign", - 0, { 8, 8 }); - -static void gpiomon_custom_format_single_percent_sign_between_chars(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=foo % bar", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "foo % bar\n"); -} -TEST_DEFINE(gpiomon_custom_format_single_percent_sign_between_chars, - "tools: gpiomon - custom output format: single percent sign between other characters", - 0, { 8, 8 }); - -static void gpiomon_custom_format_unknown_specifier(void) -{ - test_tool_run("gpiomon", "--num-events=1", "--format=%x", - test_chip_name(0), "3", (char *)NULL); - test_set_event(0, 3, 100); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NOT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_EQ(test_tool_stdout(), "%x\n"); -} -TEST_DEFINE(gpiomon_custom_format_unknown_specifier, - "tools: gpiomon - custom output format: unknown specifier", - 0, { 8, 8 }); diff --git a/tests/tests-gpioset.c b/tests/tests-gpioset.c deleted file mode 100644 index c3159a8..0000000 --- a/tests/tests-gpioset.c +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - * Copyright (C) 2019 Bartosz Golaszewski - */ - -/* Test cases for the gpioset program. */ - -#include -#include - -#include "gpiod-test.h" - -static void gpioset_set_lines_and_exit(void) -{ - test_tool_run("gpioset", - "--mode=signal", test_chip_name(2), - "0=0", "1=0", "2=1", "3=1", - "4=1", "5=1", "6=0", "7=1", (char *)NULL); - usleep(200000); - - TEST_ASSERT_EQ(test_debugfs_get_value(2, 0), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 1), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 2), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 3), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 4), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 5), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 6), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 7), 1); - - test_tool_signal(SIGTERM); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpioset_set_lines_and_exit, - "tools: gpioset - set lines and exit", - 0, { 8, 8, 8 }); - -static void gpioset_set_lines_and_exit_active_low(void) -{ - test_tool_run("gpioset", - "--mode=signal", "--active-low", test_chip_name(2), - "0=0", "1=0", "2=1", "3=1", - "4=1", "5=1", "6=0", "7=1", (char *)NULL); - usleep(200000); - - TEST_ASSERT_EQ(test_debugfs_get_value(2, 0), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 1), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 2), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 3), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 4), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 5), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 6), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 7), 0); - - test_tool_signal(SIGTERM); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpioset_set_lines_and_exit_active_low, - "tools: gpioset - set lines and exit (active-low)", - 0, { 8, 8, 8 }); - -static void gpioset_set_some_lines_and_wait_for_enter(void) -{ - test_tool_run("gpioset", "--mode=wait", test_chip_name(2), - "1=0", "2=1", "5=1", "6=0", "7=1", (char *)NULL); - usleep(200000); - - TEST_ASSERT_EQ(test_debugfs_get_value(2, 1), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 2), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 5), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 6), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 7), 1); - - test_tool_stdin_write("\n"); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpioset_set_some_lines_and_wait_for_enter, - "tools: gpioset - set some lines and wait for enter", - 0, { 8, 8, 8 }); - -static void gpioset_set_some_lines_and_wait_for_signal(void) -{ - static const int signals[] = { SIGTERM, SIGINT }; - - unsigned int i; - - for (i = 0; i < TEST_ARRAY_SIZE(signals); i++) { - test_tool_run("gpioset", "--mode=signal", test_chip_name(2), - "1=0", "2=1", "5=0", "6=0", "7=1", (char *)NULL); - usleep(200000); - - TEST_ASSERT_EQ(test_debugfs_get_value(2, 1), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 2), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 5), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 6), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(2, 7), 1); - - test_tool_signal(signals[i]); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); - } -} -TEST_DEFINE(gpioset_set_some_lines_and_wait_for_signal, - "tools: gpioset - set some lines and wait for signal", - 0, { 8, 8, 8 }); - -static void gpioset_set_some_lines_and_wait_time(void) -{ - test_tool_run("gpioset", "--mode=time", - "--usec=600000", "--sec=0", test_chip_name(0), - "1=1", "2=0", "5=1", (char *)NULL); - usleep(200000); - - TEST_ASSERT_EQ(test_debugfs_get_value(0, 1), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 5), 1); - - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_RET_OK(test_tool_exit_status()); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NULL(test_tool_stderr()); -} -TEST_DEFINE(gpioset_set_some_lines_and_wait_time, - "tools: gpioset - set some lines and wait for specified time", - 0, { 8, 8, 8 }); - -static void gpioset_no_arguments(void) -{ - test_tool_run("gpioset", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "gpiochip must be specified"); -} -TEST_DEFINE(gpioset_no_arguments, - "tools: gpioset - no arguments", - 0, { }); - -static void gpioset_no_lines_specified(void) -{ - test_tool_run("gpioset", test_chip_name(1), (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "at least one GPIO line offset to value mapping must be specified"); -} -TEST_DEFINE(gpioset_no_lines_specified, - "tools: gpioset - no lines specified", - 0, { 4, 4 }); - -static void gpioset_too_many_lines_specified(void) -{ - test_tool_run("gpioset", test_chip_name(0), - "0=1", "1=1", "2=1", "3=1", "4=1", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "error setting the GPIO line values"); -} -TEST_DEFINE(gpioset_too_many_lines_specified, - "tools: gpioset - too many lines specified", - 0, { 4 }); - -static void gpioset_sec_usec_without_time(void) -{ - test_tool_run("gpioset", "--mode=exit", "--sec=1", - test_chip_name(0), "0=1", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "can't specify wait time in this mode"); - - test_tool_run("gpioset", "--mode=exit", "--usec=100", - test_chip_name(0), "0=1", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "can't specify wait time in this mode"); -} -TEST_DEFINE(gpioset_sec_usec_without_time, - "tools: gpioset - using --sec/--usec with mode other than 'time'", - 0, { 4 }); - -static void gpioset_invalid_mapping(void) -{ - test_tool_run("gpioset", test_chip_name(0), "0=c", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "invalid offset<->value mapping"); -} -TEST_DEFINE(gpioset_invalid_mapping, - "tools: gpioset - invalid offset<->value mapping", - 0, { 4 }); - -static void gpioset_invalid_value(void) -{ - test_tool_run("gpioset", test_chip_name(0), "0=3", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), "value must be 0 or 1"); -} -TEST_DEFINE(gpioset_invalid_value, - "tools: gpioset - value different than 0 or 1", - 0, { 4 }); - -static void gpioset_invalid_offset(void) -{ - test_tool_run("gpioset", test_chip_name(0), - "4000000000=1", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), "invalid offset"); -} -TEST_DEFINE(gpioset_invalid_offset, - "tools: gpioset - invalid offset", - 0, { 4 }); - -static void gpioset_daemonize_in_wrong_mode(void) -{ - test_tool_run("gpioset", "--background", - test_chip_name(0), "0=1", (char *)NULL); - test_tool_wait(); - - TEST_ASSERT(test_tool_exited()); - TEST_ASSERT_EQ(test_tool_exit_status(), 1); - TEST_ASSERT_NULL(test_tool_stdout()); - TEST_ASSERT_NOT_NULL(test_tool_stderr()); - TEST_ASSERT_STR_CONTAINS(test_tool_stderr(), - "can't daemonize in this mode"); -} -TEST_DEFINE(gpioset_daemonize_in_wrong_mode, - "tools: gpioset - daemonize in wrong mode", - 0, { 4 }); diff --git a/tests/tests-iter.c b/tests/tests-iter.c index de71efd..8deee8e 100644 --- a/tests/tests-iter.c +++ b/tests/tests-iter.c @@ -2,97 +2,86 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski + * Copyright (C) 2019 Bartosz Golaszewski */ -/* Iterator test cases. */ +#include #include "gpiod-test.h" -static void chip_iter(void) +#define GPIOD_TEST_GROUP "iter" + +GPIOD_TEST_CASE(chip_iter, 0, { 8, 8, 8 }) { - TEST_CLEANUP(test_free_chip_iter) struct gpiod_chip_iter *iter = NULL; + g_autoptr(gpiod_chip_iter_struct) iter = NULL; struct gpiod_chip *chip; - bool A, B, C; + gboolean A, B, C; - A = B = C = false; + A = B = C = FALSE; iter = gpiod_chip_iter_new(); - TEST_ASSERT_NOT_NULL(iter); + g_assert_nonnull(iter); + gpiod_test_return_if_failed(); gpiod_foreach_chip(iter, chip) { if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) - A = true; + A = TRUE; else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) - B = true; + B = TRUE; else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0) - C = true; + C = TRUE; } - TEST_ASSERT(A); - TEST_ASSERT(B); - TEST_ASSERT(C); + g_assert_true(A); + g_assert_true(B); + g_assert_true(C); } -TEST_DEFINE(chip_iter, - "gpiod_chip_iter - simple loop", - 0, { 8, 8, 8 }); -static void chip_iter_noclose(void) +GPIOD_TEST_CASE(chip_iter_no_close, 0, { 8, 8, 8 }) { - TEST_CLEANUP(test_free_chip_iter_noclose) - struct gpiod_chip_iter *iter = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipA = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipB = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipC = NULL; + g_autoptr(gpiod_chip_iter_struct) iter = NULL; + g_autoptr(gpiod_chip_struct) chipA = NULL; + g_autoptr(gpiod_chip_struct) chipB = NULL; + g_autoptr(gpiod_chip_struct) chipC = NULL; struct gpiod_chip *chip; - bool A, B, C; - - A = B = C = false; iter = gpiod_chip_iter_new(); - TEST_ASSERT_NOT_NULL(iter); + g_assert_nonnull(iter); + gpiod_test_return_if_failed(); gpiod_foreach_chip_noclose(iter, chip) { - if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) { - A = true; + if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) chipA = chip; - } else if (strcmp(gpiod_chip_label(chip), - "gpio-mockup-B") == 0) { - B = true; + else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) chipB = chip; - } else if (strcmp(gpiod_chip_label(chip), - "gpio-mockup-C") == 0) { - C = true; + else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0) chipC = chip; - } else { + else gpiod_chip_close(chip); - } } - TEST_ASSERT(A); - TEST_ASSERT(B); - TEST_ASSERT(C); + g_assert_nonnull(chipA); + g_assert_nonnull(chipB); + g_assert_nonnull(chipC); gpiod_chip_iter_free_noclose(iter); iter = NULL; /* See if the chips are still open and usable. */ - TEST_ASSERT_STR_EQ(gpiod_chip_label(chipA), "gpio-mockup-A"); - TEST_ASSERT_STR_EQ(gpiod_chip_label(chipB), "gpio-mockup-B"); - TEST_ASSERT_STR_EQ(gpiod_chip_label(chipC), "gpio-mockup-C"); + g_assert_cmpstr(gpiod_chip_label(chipA), ==, "gpio-mockup-A"); + g_assert_cmpstr(gpiod_chip_label(chipB), ==, "gpio-mockup-B"); + g_assert_cmpstr(gpiod_chip_label(chipC), ==, "gpio-mockup-C"); } -TEST_DEFINE(chip_iter_noclose, - "gpiod_chip_iter - simple loop, noclose variant", - 0, { 8, 8, 8 }); -static void chip_iter_break(void) +GPIOD_TEST_CASE(chip_iter_break, 0, { 8, 8, 8, 8, 8 }) { - TEST_CLEANUP(test_free_chip_iter) struct gpiod_chip_iter *iter = NULL; + g_autoptr(gpiod_chip_iter_struct) iter = NULL; struct gpiod_chip *chip; - int i = 0; + guint i = 0; iter = gpiod_chip_iter_new(); - TEST_ASSERT_NOT_NULL(iter); + g_assert_nonnull(iter); + gpiod_test_return_if_failed(); gpiod_foreach_chip(iter, chip) { if ((strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) || @@ -107,32 +96,28 @@ static void chip_iter_break(void) gpiod_chip_iter_free(iter); iter = NULL; - TEST_ASSERT_EQ(i, 3); + g_assert_cmpuint(i, ==, 3); } -TEST_DEFINE(chip_iter_break, - "gpiod_chip_iter - break", - 0, { 8, 8, 8, 8, 8 }); -static void line_iter(void) +GPIOD_TEST_CASE(line_iter, 0, { 8 }) { - TEST_CLEANUP(test_free_line_iter) struct gpiod_line_iter *iter = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_line_iter_struct) iter = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - unsigned int i = 0; + guint i = 0; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); iter = gpiod_line_iter_new(chip); - TEST_ASSERT_NOT_NULL(iter); + g_assert_nonnull(iter); + gpiod_test_return_if_failed(); gpiod_foreach_line(iter, line) { - TEST_ASSERT_EQ(i, gpiod_line_offset(line)); + g_assert_cmpuint(i, ==, gpiod_line_offset(line)); i++; } - TEST_ASSERT_EQ(8, i); + g_assert_cmpuint(i, ==, 8); } -TEST_DEFINE(line_iter, - "gpiod_line_iter - simple loop, check offsets", - 0, { 8 }); diff --git a/tests/tests-line.c b/tests/tests-line.c index a0cb355..db8dc03 100644 --- a/tests/tests-line.c +++ b/tests/tests-line.c @@ -2,140 +2,125 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski * Copyright (C) 2019 Bartosz Golaszewski */ -/* GPIO line test cases. */ - #include +#include #include "gpiod-test.h" -static void line_request_output(void) +#define GPIOD_TEST_GROUP "line" + +GPIOD_TEST_CASE(request_output, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; - struct gpiod_line *line_0; - struct gpiod_line *line_1; - int rv; - - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); - - line_0 = gpiod_chip_get_line(chip, 2); - line_1 = gpiod_chip_get_line(chip, 5); - TEST_ASSERT_NOT_NULL(line_0); - TEST_ASSERT_NOT_NULL(line_1); - - rv = gpiod_line_request_output(line_0, TEST_CONSUMER, 0); - TEST_ASSERT_RET_OK(rv); - rv = gpiod_line_request_output(line_1, TEST_CONSUMER, 1); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 5), 1); + g_autoptr(gpiod_chip_struct) chip = NULL; + struct gpiod_line *line0; + struct gpiod_line *line1; + gint ret; + + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); + + line0 = gpiod_chip_get_line(chip, 2); + line1 = gpiod_chip_get_line(chip, 5); + g_assert_nonnull(line0); + g_assert_nonnull(line1); + gpiod_test_return_if_failed(); + + ret = gpiod_line_request_output(line0, GPIOD_TEST_CONSUMER, 0); + g_assert_cmpint(ret, ==, 0); + ret = gpiod_line_request_output(line1, GPIOD_TEST_CONSUMER, 1); + g_assert_cmpint(ret, ==, 0); + + g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1); } -TEST_DEFINE(line_request_output, - "gpiod_line_request_output() - good", - 0, { 8 }); -static void line_request_already_requested(void) +GPIOD_TEST_CASE(request_already_requested, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_NOTEQ(rv, 0); - TEST_ASSERT_ERRNO_IS(EBUSY); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EBUSY); } -TEST_DEFINE(line_request_already_requested, - "gpiod_line_request() - already requested", - 0, { 8 }); -static void line_consumer(void) +GPIOD_TEST_CASE(consumer, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); - TEST_ASSERT_NOT_NULL(line); - - TEST_ASSERT_NULL(gpiod_line_consumer(line)); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + g_assert_null(gpiod_line_consumer(line)); - TEST_ASSERT(!gpiod_line_needs_update(line)); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), TEST_CONSUMER); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); + g_assert_false(gpiod_line_needs_update(line)); + g_assert_cmpstr(gpiod_line_consumer(line), ==, GPIOD_TEST_CONSUMER); } -TEST_DEFINE(line_consumer, - "gpiod_line_consumer() - good", - 0, { 8 }); -static void line_consumer_long_string(void) +GPIOD_TEST_CASE(consumer_long_string, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 0); - TEST_ASSERT_NOT_NULL(line); - - TEST_ASSERT_NULL(gpiod_line_consumer(line)); - - rv = gpiod_line_request_input(line, - "consumer string over 32 characters long"); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT(!gpiod_line_needs_update(line)); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), - "consumer string over 32 charact"); - TEST_ASSERT_EQ(strlen(gpiod_line_consumer(line)), 31); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + + g_assert_null(gpiod_line_consumer(line)); + + ret = gpiod_line_request_input(line, + "consumer string over 32 characters long"); + g_assert_cmpint(ret, ==, 0); + g_assert_false(gpiod_line_needs_update(line)); + g_assert_cmpstr(gpiod_line_consumer(line), ==, + "consumer string over 32 charact"); + g_assert_cmpuint(strlen(gpiod_line_consumer(line)), ==, 31); } -TEST_DEFINE(line_consumer_long_string, - "gpiod_line_consumer() - long consumer string", - 0, { 8 }); -static void line_request_bulk_output(void) +GPIOD_TEST_CASE(request_bulk_output, 0, { 8, 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chipA = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipB = NULL; - struct gpiod_line_bulk bulkB = GPIOD_LINE_BULK_INITIALIZER; - struct gpiod_line_bulk bulkA; - struct gpiod_line *lineA0; - struct gpiod_line *lineA1; - struct gpiod_line *lineA2; - struct gpiod_line *lineA3; - struct gpiod_line *lineB0; - struct gpiod_line *lineB1; - struct gpiod_line *lineB2; - struct gpiod_line *lineB3; - int valA[4], valB[4]; - int rv; - - chipA = gpiod_chip_open(test_chip_path(0)); - chipB = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chipA); - TEST_ASSERT_NOT_NULL(chipB); - - gpiod_line_bulk_init(&bulkA); + g_autoptr(gpiod_chip_struct) chipA = NULL; + g_autoptr(gpiod_chip_struct) chipB = NULL; + struct gpiod_line_bulk bulkB = GPIOD_LINE_BULK_INITIALIZER, bulkA; + struct gpiod_line *lineA0, *lineA1, *lineA2, *lineA3, + *lineB0, *lineB1, *lineB2, *lineB3; + gint valA[4], valB[4], ret; + + chipA = gpiod_chip_open(gpiod_test_chip_path(0)); + chipB = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chipA); + g_assert_nonnull(chipB); + gpiod_test_return_if_failed(); lineA0 = gpiod_chip_get_line(chipA, 0); lineA1 = gpiod_chip_get_line(chipA, 1); @@ -146,15 +131,17 @@ static void line_request_bulk_output(void) lineB2 = gpiod_chip_get_line(chipB, 2); lineB3 = gpiod_chip_get_line(chipB, 3); - TEST_ASSERT_NOT_NULL(lineA0); - TEST_ASSERT_NOT_NULL(lineA1); - TEST_ASSERT_NOT_NULL(lineA2); - TEST_ASSERT_NOT_NULL(lineA3); - TEST_ASSERT_NOT_NULL(lineB0); - TEST_ASSERT_NOT_NULL(lineB1); - TEST_ASSERT_NOT_NULL(lineB2); - TEST_ASSERT_NOT_NULL(lineB3); + g_assert_nonnull(lineA0); + g_assert_nonnull(lineA1); + g_assert_nonnull(lineA2); + g_assert_nonnull(lineA3); + g_assert_nonnull(lineB0); + g_assert_nonnull(lineB1); + g_assert_nonnull(lineB2); + g_assert_nonnull(lineB3); + gpiod_test_return_if_failed(); + gpiod_line_bulk_init(&bulkA); gpiod_line_bulk_add(&bulkA, lineA0); gpiod_line_bulk_add(&bulkA, lineA1); gpiod_line_bulk_add(&bulkA, lineA2); @@ -168,56 +155,54 @@ static void line_request_bulk_output(void) valA[1] = 0; valA[2] = 0; valA[3] = 1; - rv = gpiod_line_request_bulk_output(&bulkA, TEST_CONSUMER, valA); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_bulk_output(&bulkA, + GPIOD_TEST_CONSUMER, valA); + g_assert_cmpint(ret, ==, 0); valB[0] = 0; valB[1] = 1; valB[2] = 0; valB[3] = 1; - rv = gpiod_line_request_bulk_output(&bulkB, TEST_CONSUMER, valB); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(test_debugfs_get_value(0, 0), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 1), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 3), 1); - - TEST_ASSERT_EQ(test_debugfs_get_value(1, 0), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(1, 1), 1); - TEST_ASSERT_EQ(test_debugfs_get_value(1, 2), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(1, 3), 1); + ret = gpiod_line_request_bulk_output(&bulkB, + GPIOD_TEST_CONSUMER, valB); + g_assert_cmpint(ret, ==, 0); + + g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1); + g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1); + + g_assert_cmpint(gpiod_test_chip_get_value(1, 0), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(1, 1), ==, 1); + g_assert_cmpint(gpiod_test_chip_get_value(1, 2), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(1, 3), ==, 1); } -TEST_DEFINE(line_request_bulk_output, - "gpiod_line_request_bulk_output() - good", - 0, { 8, 8 }); -static void line_request_bulk_different_chips(void) +GPIOD_TEST_CASE(request_bulk_different_chips, 0, { 8, 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chipA = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipB = NULL; + g_autoptr(gpiod_chip_struct) chipA = NULL; + g_autoptr(gpiod_chip_struct) chipB = NULL; + struct gpiod_line *lineA0, *lineA1, *lineB0, *lineB1; struct gpiod_line_request_config req; struct gpiod_line_bulk bulk; - struct gpiod_line *lineA0; - struct gpiod_line *lineA1; - struct gpiod_line *lineB0; - struct gpiod_line *lineB1; - int rv; + gint ret; - chipA = gpiod_chip_open(test_chip_path(0)); - chipB = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chipA); - TEST_ASSERT_NOT_NULL(chipB); + chipA = gpiod_chip_open(gpiod_test_chip_path(0)); + chipB = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chipA); + g_assert_nonnull(chipB); + gpiod_test_return_if_failed(); lineA0 = gpiod_chip_get_line(chipA, 0); lineA1 = gpiod_chip_get_line(chipA, 1); lineB0 = gpiod_chip_get_line(chipB, 0); lineB1 = gpiod_chip_get_line(chipB, 1); - TEST_ASSERT_NOT_NULL(lineA0); - TEST_ASSERT_NOT_NULL(lineA1); - TEST_ASSERT_NOT_NULL(lineB0); - TEST_ASSERT_NOT_NULL(lineB1); + g_assert_nonnull(lineA0); + g_assert_nonnull(lineA1); + g_assert_nonnull(lineB0); + g_assert_nonnull(lineB1); + gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulk); gpiod_line_bulk_add(&bulk, lineA0); @@ -225,401 +210,374 @@ static void line_request_bulk_different_chips(void) gpiod_line_bulk_add(&bulk, lineB0); gpiod_line_bulk_add(&bulk, lineB1); - req.consumer = TEST_CONSUMER; + req.consumer = GPIOD_TEST_CONSUMER; req.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; req.flags = GPIOD_LINE_ACTIVE_STATE_HIGH; - rv = gpiod_line_request_bulk(&bulk, &req, NULL); - TEST_ASSERT_NOTEQ(rv, 0); - TEST_ASSERT_ERRNO_IS(EINVAL); + ret = gpiod_line_request_bulk(&bulk, &req, NULL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(line_request_bulk_different_chips, - "gpiod_line_request_bulk() - different chips", - 0, { 8, 8 }); -static void line_request_null_default_vals_for_output(void) +GPIOD_TEST_CASE(request_null_default_vals_for_output, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; - struct gpiod_line *line; - int rv, vals[3]; + struct gpiod_line *line0, *line1, *line2; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); - line = gpiod_chip_get_line(chip, 0); - gpiod_line_bulk_add(&bulk, line); - line = gpiod_chip_get_line(chip, 1); - gpiod_line_bulk_add(&bulk, line); - line = gpiod_chip_get_line(chip, 2); - gpiod_line_bulk_add(&bulk, line); + line0 = gpiod_chip_get_line(chip, 0); + line1 = gpiod_chip_get_line(chip, 1); + line2 = gpiod_chip_get_line(chip, 2); - rv = gpiod_line_request_bulk_output(&bulk, TEST_CONSUMER, NULL); - TEST_ASSERT_RET_OK(rv); + g_assert_nonnull(line0); + g_assert_nonnull(line1); + g_assert_nonnull(line2); + gpiod_test_return_if_failed(); - gpiod_line_release_bulk(&bulk); - - rv = gpiod_line_request_bulk_input(&bulk, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + gpiod_line_bulk_add(&bulk, line0); + gpiod_line_bulk_add(&bulk, line1); + gpiod_line_bulk_add(&bulk, line2); - memset(vals, 0, sizeof(vals)); + ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, NULL); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 0), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 1), 0); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } -TEST_DEFINE(line_request_null_default_vals_for_output, - "gpiod_line_request_bulk() - null default vals for output", - 0, { 8 }); -static void line_set_value(void) +GPIOD_TEST_CASE(set_value, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); - - rv = gpiod_line_request_output(line, TEST_CONSUMER, 0); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_RET_OK(gpiod_line_set_value(line, 1)); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 1); - TEST_ASSERT_RET_OK(gpiod_line_set_value(line, 0)); - TEST_ASSERT_EQ(test_debugfs_get_value(0, 2), 0); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + + ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0); + g_assert_cmpint(ret, ==, 0); + + ret = gpiod_line_set_value(line, 1); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1); + ret = gpiod_line_set_value(line, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } -TEST_DEFINE(line_set_value, - "gpiod_line_set_value() - good", - 0, { 8 }); -static void line_get_value_different_chips(void) +GPIOD_TEST_CASE(get_value_different_chips, 0, { 8, 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chipA = NULL; - TEST_CLEANUP_CHIP struct gpiod_chip *chipB = NULL; - struct gpiod_line *lineA1, *lineA2, *lineB1, *lineB2; + g_autoptr(gpiod_chip_struct) chipA = NULL; + g_autoptr(gpiod_chip_struct) chipB = NULL; + struct gpiod_line *lineA0, *lineA1, *lineB0, *lineB1; struct gpiod_line_bulk bulkA, bulkB, bulk; - int rv, vals[4]; + gint ret, vals[4]; - chipA = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chipA); + chipA = gpiod_chip_open(gpiod_test_chip_path(0)); + chipB = gpiod_chip_open(gpiod_test_chip_path(1)); + g_assert_nonnull(chipA); + g_assert_nonnull(chipB); + gpiod_test_return_if_failed(); - chipB = gpiod_chip_open(test_chip_path(1)); - TEST_ASSERT_NOT_NULL(chipB); + lineA0 = gpiod_chip_get_line(chipA, 3); + lineA1 = gpiod_chip_get_line(chipA, 4); + lineB0 = gpiod_chip_get_line(chipB, 5); + lineB1 = gpiod_chip_get_line(chipB, 6); - lineA1 = gpiod_chip_get_line(chipA, 3); - lineA2 = gpiod_chip_get_line(chipA, 4); - lineB1 = gpiod_chip_get_line(chipB, 5); - lineB2 = gpiod_chip_get_line(chipB, 6); - TEST_ASSERT_NOT_NULL(lineA1); - TEST_ASSERT_NOT_NULL(lineA2); - TEST_ASSERT_NOT_NULL(lineB1); - TEST_ASSERT_NOT_NULL(lineB2); + g_assert_nonnull(lineA0); + g_assert_nonnull(lineA1); + g_assert_nonnull(lineB0); + g_assert_nonnull(lineB1); + gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulkA); gpiod_line_bulk_init(&bulkB); gpiod_line_bulk_init(&bulk); - gpiod_line_bulk_add(&bulk, lineA1); - gpiod_line_bulk_add(&bulk, lineA2); - gpiod_line_bulk_add(&bulk, lineB1); - gpiod_line_bulk_add(&bulk, lineB2); - + gpiod_line_bulk_add(&bulkA, lineA0); gpiod_line_bulk_add(&bulkA, lineA1); - gpiod_line_bulk_add(&bulkA, lineA2); + gpiod_line_bulk_add(&bulkB, lineB0); gpiod_line_bulk_add(&bulkB, lineB1); - gpiod_line_bulk_add(&bulkB, lineB2); + gpiod_line_bulk_add(&bulk, lineA0); gpiod_line_bulk_add(&bulk, lineA1); - gpiod_line_bulk_add(&bulk, lineA2); + gpiod_line_bulk_add(&bulk, lineB0); gpiod_line_bulk_add(&bulk, lineB1); - gpiod_line_bulk_add(&bulk, lineB2); - rv = gpiod_line_request_bulk_input(&bulkA, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_bulk_input(&bulkA, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); + ret = gpiod_line_request_bulk_input(&bulkB, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_request_bulk_input(&bulkB, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); - - rv = gpiod_line_get_value_bulk(&bulk, vals); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + ret = gpiod_line_get_value_bulk(&bulk, vals); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(line_get_value_different_chips, - "gpiod_line_get_value_bulk() - different chips", - 0, { 8, 8 }); -static void line_get_good(void) +GPIOD_TEST_CASE(get_line_helper, 0, { 16, 16, 32, 16 }) { - TEST_CLEANUP(test_line_close_chip) struct gpiod_line *line = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; + struct gpiod_line *line; - line = gpiod_line_get(test_chip_name(2), 18); - TEST_ASSERT_NOT_NULL(line); - TEST_ASSERT_EQ(gpiod_line_offset(line), 18); + line = gpiod_line_get(gpiod_test_chip_name(2), 18); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + chip = gpiod_line_get_chip(line); + g_assert_cmpint(gpiod_line_offset(line), ==, 18); } -TEST_DEFINE(line_get_good, - "gpiod_line_get() - good", - TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }); -static void line_get_invalid_offset(void) +GPIOD_TEST_CASE(get_line_helper_invalid_offset, 0, { 16, 16, 32, 16 }) { - TEST_CLEANUP(test_line_close_chip) struct gpiod_line *line = NULL; + struct gpiod_line *line; - line = gpiod_line_get(test_chip_name(3), 18); - TEST_ASSERT_NULL(line); - TEST_ASSERT_ERRNO_IS(EINVAL); + line = gpiod_line_get(gpiod_test_chip_name(3), 18); + g_assert_null(line); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(line_get_invalid_offset, - "gpiod_line_get() - invalid offset", - TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }); -static void line_find_good(void) +GPIOD_TEST_CASE(find_good, GPIOD_TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }) { - TEST_CLEANUP(test_line_close_chip) struct gpiod_line *line = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; + struct gpiod_line *line; line = gpiod_line_find("gpio-mockup-C-12"); - TEST_ASSERT_NOT_NULL(line); - - TEST_ASSERT_EQ(gpiod_line_offset(line), 12); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + chip = gpiod_line_get_chip(line); + g_assert_cmpint(gpiod_line_offset(line), ==, 12); } -TEST_DEFINE(line_find_good, - "gpiod_line_find() - good", - TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }); -static void line_find_not_found(void) +GPIOD_TEST_CASE(find_not_found, + GPIOD_TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }) { - TEST_CLEANUP(test_line_close_chip) struct gpiod_line *line = NULL; + struct gpiod_line *line; line = gpiod_line_find("nonexistent"); - TEST_ASSERT_NULL(line); - TEST_ASSERT_ERRNO_IS(ENOENT); + g_assert_null(line); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(line_find_not_found, - "gpiod_line_find() - not found", - TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }); -static void line_find_unnamed_lines(void) +GPIOD_TEST_CASE(find_unnamed_lines, 0, { 16, 16, 32, 16 }) { - TEST_CLEANUP(test_line_close_chip) struct gpiod_line *line = NULL; + struct gpiod_line *line; line = gpiod_line_find("gpio-mockup-C-12"); - TEST_ASSERT_NULL(line); - TEST_ASSERT_ERRNO_IS(ENOENT); + g_assert_null(line); + g_assert_cmpint(errno, ==, ENOENT); } -TEST_DEFINE(line_find_unnamed_lines, - "gpiod_line_find() - unnamed lines", - 0, { 16, 16, 32, 16 }); -static void line_direction(void) +GPIOD_TEST_CASE(direction, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 5); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_output(line, TEST_CONSUMER, 0); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(gpiod_line_direction(line), GPIOD_LINE_DIRECTION_OUTPUT); + ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpint(gpiod_line_direction(line), ==, + GPIOD_LINE_DIRECTION_OUTPUT); gpiod_line_release(line); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(gpiod_line_direction(line), GPIOD_LINE_DIRECTION_INPUT); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpint(gpiod_line_direction(line), ==, + GPIOD_LINE_DIRECTION_INPUT); } -TEST_DEFINE(line_direction, - "gpiod_line_direction() - set & get", - 0, { 8 }); -static void line_active_state(void) +GPIOD_TEST_CASE(active_state, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 5); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input(line, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(gpiod_line_active_state(line), - GPIOD_LINE_ACTIVE_STATE_HIGH); + g_assert_cmpint(gpiod_line_active_state(line), ==, + GPIOD_LINE_ACTIVE_STATE_HIGH); gpiod_line_release(line); - rv = gpiod_line_request_input_flags(line, TEST_CONSUMER, + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW); - TEST_ASSERT_RET_OK(rv); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT_EQ(gpiod_line_direction(line), GPIOD_LINE_DIRECTION_INPUT); + g_assert_cmpint(gpiod_line_direction(line), ==, + GPIOD_LINE_DIRECTION_INPUT); } -TEST_DEFINE(line_active_state, - "gpiod_line_active_state() - set & get", - 0, { 8 }); -static void line_misc_flags(void) +GPIOD_TEST_CASE(misc_flags, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - TEST_ASSERT_FALSE(gpiod_line_is_used(line)); - TEST_ASSERT_FALSE(gpiod_line_is_open_drain(line)); - TEST_ASSERT_FALSE(gpiod_line_is_open_source(line)); + g_assert_false(gpiod_line_is_used(line)); + g_assert_false(gpiod_line_is_open_drain(line)); + g_assert_false(gpiod_line_is_open_source(line)); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; - config.consumer = TEST_CONSUMER; + config.consumer = GPIOD_TEST_CONSUMER; config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT(gpiod_line_is_used(line)); - TEST_ASSERT(gpiod_line_is_open_drain(line)); - TEST_ASSERT_FALSE(gpiod_line_is_open_source(line)); + g_assert_true(gpiod_line_is_used(line)); + g_assert_true(gpiod_line_is_open_drain(line)); + g_assert_false(gpiod_line_is_open_source(line)); gpiod_line_release(line); config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); - TEST_ASSERT(gpiod_line_is_used(line)); - TEST_ASSERT_FALSE(gpiod_line_is_open_drain(line)); - TEST_ASSERT(gpiod_line_is_open_source(line)); + g_assert_true(gpiod_line_is_used(line)); + g_assert_false(gpiod_line_is_open_drain(line)); + g_assert_true(gpiod_line_is_open_source(line)); } -TEST_DEFINE(line_misc_flags, - "gpiod_line - misc flags", - 0, { 8 }); -static void line_open_source_open_drain_input_invalid(void) +GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); - rv = gpiod_line_request_input_flags(line, TEST_CONSUMER, + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); - rv = gpiod_line_request_input_flags(line, TEST_CONSUMER, + ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(line_open_source_open_drain_input_invalid, - "gpiod_line - open-source & open-drain for input mode (invalid)", - 0, { 8 }); -static void line_open_source_open_drain_simultaneously(void) +GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); - - rv = gpiod_line_request_output_flags(line, TEST_CONSUMER, - GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE | - GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, 1); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EINVAL); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); + + ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER, + GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE | + GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, 1); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EINVAL); } -TEST_DEFINE(line_open_source_open_drain_simultaneously, - "gpiod_line - open-source & open-drain flags simultaneously", - 0, { 8 }); /* Verify that the reference counting of the line fd handle works correctly. */ -static void line_release_one_use_another(void) +GPIOD_TEST_CASE(release_one_use_another, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk; + struct gpiod_line *line0; struct gpiod_line *line1; - struct gpiod_line *line2; - int rv, vals[2]; + gint ret, vals[2]; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); - line1 = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line1); - line2 = gpiod_chip_get_line(chip, 3); - TEST_ASSERT_NOT_NULL(line2); + line0 = gpiod_chip_get_line(chip, 2); + line1 = gpiod_chip_get_line(chip, 3); + g_assert_nonnull(line0); + g_assert_nonnull(line1); + gpiod_test_return_if_failed(); gpiod_line_bulk_init(&bulk); + gpiod_line_bulk_add(&bulk, line0); gpiod_line_bulk_add(&bulk, line1); - gpiod_line_bulk_add(&bulk, line2); vals[0] = vals[1] = 1; - rv = gpiod_line_request_bulk_output(&bulk, TEST_CONSUMER, vals); - TEST_ASSERT_RET_OK(rv); - - gpiod_line_release(line1); + ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, vals); + g_assert_cmpint(ret, ==, 0); - rv = gpiod_line_get_value(line1); - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(EPERM); + gpiod_line_release(line0); - rv = gpiod_line_get_value(line2); - TEST_ASSERT_EQ(rv, 1); + ret = gpiod_line_get_value(line0); + g_assert_cmpint(ret, ==, -1); + g_assert_cmpint(errno, ==, EPERM); } -TEST_DEFINE(line_release_one_use_another, - "gpiod_line - request two, release one, use the other one", - 0, { 8 }); -static void line_null_consumer(void) +GPIOD_TEST_CASE(null_consumer, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; config.consumer = NULL; config.flags = 0; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), "?"); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); gpiod_line_release(line); @@ -629,34 +587,33 @@ static void line_null_consumer(void) */ config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), "?"); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); } -TEST_DEFINE(line_null_consumer, - "line request - NULL consumer string", - 0, { 8 }); -static void line_empty_consumer(void) +GPIOD_TEST_CASE(empty_consumer, 0, { 8 }) { - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_request_config config; struct gpiod_line *line; - int rv; + gint ret; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); line = gpiod_chip_get_line(chip, 2); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; config.consumer = ""; config.flags = 0; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), "?"); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); gpiod_line_release(line); @@ -666,47 +623,43 @@ static void line_empty_consumer(void) */ config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; - rv = gpiod_line_request(line, &config, 0); - TEST_ASSERT_RET_OK(rv); - TEST_ASSERT_STR_EQ(gpiod_line_consumer(line), "?"); + ret = gpiod_line_request(line, &config, 0); + g_assert_cmpint(ret, ==, 0); + g_assert_cmpstr(gpiod_line_consumer(line), ==, "?"); } -TEST_DEFINE(line_empty_consumer, - "line request - empty consumer string", - 0, { 8 }); -static void line_bulk_foreach(void) +GPIOD_TEST_CASE(bulk_foreach, GPIOD_TEST_FLAG_NAMED_LINES, { 8 }) { - static const char *const line_names[] = { "gpio-mockup-A-0", - "gpio-mockup-A-1", - "gpio-mockup-A-2", - "gpio-mockup-A-3" }; + static const gchar *const line_names[] = { "gpio-mockup-A-0", + "gpio-mockup-A-1", + "gpio-mockup-A-2", + "gpio-mockup-A-3" }; - TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL; + g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER; struct gpiod_line *line, **lineptr; - int i; + gint i; - chip = gpiod_chip_open(test_chip_path(0)); - TEST_ASSERT_NOT_NULL(chip); + chip = gpiod_chip_open(gpiod_test_chip_path(0)); + g_assert_nonnull(chip); + gpiod_test_return_if_failed(); for (i = 0; i < 4; i++) { line = gpiod_chip_get_line(chip, i); - TEST_ASSERT_NOT_NULL(line); + g_assert_nonnull(line); + gpiod_test_return_if_failed(); gpiod_line_bulk_add(&bulk, line); } i = 0; gpiod_line_bulk_foreach_line(&bulk, line, lineptr) - TEST_ASSERT_STR_EQ(gpiod_line_name(line), line_names[i++]); + g_assert_cmpstr(gpiod_line_name(line), ==, line_names[i++]); i = 0; gpiod_line_bulk_foreach_line(&bulk, line, lineptr) { - TEST_ASSERT_STR_EQ(gpiod_line_name(line), line_names[i++]); + g_assert_cmpstr(gpiod_line_name(line), ==, line_names[i++]); if (i == 2) break; } } -TEST_DEFINE(line_bulk_foreach, - "line bulk - iterate over all lines", - TEST_FLAG_NAMED_LINES, { 8 }); diff --git a/tests/tests-misc.c b/tests/tests-misc.c index 99a80a7..e838b62 100644 --- a/tests/tests-misc.c +++ b/tests/tests-misc.c @@ -2,23 +2,28 @@ /* * This file is part of libgpiod. * - * Copyright (C) 2017-2018 Bartosz Golaszewski + * Copyright (C) 2019 Bartosz Golaszewski */ -/* Misc test cases. */ - -#include +#include #include "gpiod-test.h" -static void version_string(void) +#define GPIOD_TEST_GROUP "misc" + +GPIOD_TEST_CASE(version_string, 0, { 1 }) { - /* Check that gpiod_version_string() returns an actual string. */ - TEST_ASSERT_NOT_NULL(gpiod_version_string()); - TEST_ASSERT(strlen(gpiod_version_string()) > 0); - TEST_ASSERT_REGEX_MATCH(gpiod_version_string(), - "^[0-9]+\\.[0-9]+[0-9a-zA-Z\\.]*$"); + g_autoptr(GRegex) regex = NULL; + GError *err = NULL; + const gchar *ver; + + ver = gpiod_version_string(); + g_assert_nonnull(ver); + gpiod_test_return_if_failed(); + g_assert_cmpuint(strlen(ver), >, 0); + + regex = g_regex_new("^[0-9]+\\.[0-9]+[0-9a-zA-Z\\.]*$", 0, 0, &err); + g_assert_null(err); + gpiod_test_return_if_failed(); + g_assert_true(g_regex_match(regex, ver, 0, NULL)); } -TEST_DEFINE(version_string, - "gpiod_version_string()", - 0, { }); diff --git a/tools/Makefile.am b/tools/Makefile.am index 4198dba..d9615f9 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -27,3 +27,11 @@ gpioset_SOURCES = gpioset.c gpiomon_SOURCES = gpiomon.c gpiofind_SOURCES = gpiofind.c + +EXTRA_DIST = gpio-tools-test.bats + +if WITH_TESTS + +bin_SCRIPTS = gpio-tools-test.bats + +endif diff --git a/tools/gpio-tools-test.bats b/tools/gpio-tools-test.bats new file mode 100755 index 0000000..6a0f076 --- /dev/null +++ b/tools/gpio-tools-test.bats @@ -0,0 +1,869 @@ +#!/usr/bin/env bats +# SPDX-License-Identifier: LGPL-2.1-or-later + +# +# This file is part of libgpiod. +# +# Copyright (C) 2019 Bartosz Golaszewski +# + +# Simple test harness for the gpio-tools. + +# Where output from coprocesses is stored +COPROC_OUTPUT=$BATS_TMPDIR/gpio-tools-test-output +# Save the PID of coprocess - otherwise we won't be able to wait for it +# once it exits as the COPROC_PID will be cleared. +COPROC_SAVED_PID="" + +# Run the command in $* and return 0 if the command failed. The way we do it +# here is a workaround for the way bats handles failing processes. +assert_fail() { + $* || return 0 + return 1 +} + +# Check if the string in $2 matches against the pattern in $1. +regex_matches() { + local PATTERN=$1 + local STRING=$2 + + [[ $STRING =~ $PATTERN ]] +} + +# Iterate over all lines in the output of the last command invoked with bats' +# 'run' or the coproc helper and check if at least one is equal to $1. +output_contains_line() { + local LINE=$1 + + for line in "${lines[@]}" + do + test "$line" = "$LINE" && return 0 + done + + return 1 +} + +# Same as above but match against the regex pattern in $1. +output_regex_match() { + local PATTERN=$1 + + for line in "${lines[@]}" + do + regex_matches "$PATTERN" "$line" && return 0 + done + + return 1 +} + +# Probe the gpio-mockup kernel module. The routine expects a list of chip +# sizes and optionally the 'named-lines' flag. +gpio_mockup_probe() { + local CMDLINE="gpio_mockup_ranges=" + + for ARG in $* + do + if [ $ARG = "named-lines" ] + then + CMDLINE="gpio_mockup_named_lines $CMDLINE" + continue + fi + + regex_matches "[0-9]+" "$ARG" + + CMDLINE="$CMDLINE-1,$ARG," + done + + CMDLINE=${CMDLINE%?} + + modprobe gpio-mockup $CMDLINE + udevadm settle +} + +gpio_mockup_remove() { + if [ -d /sys/module/gpio_mockup ] + then + rmmod gpio-mockup + fi +} + +gpio_mockup_chip_name() { + local CHIPNUM=$1 + + test -d /sys/devices/platform/gpio-mockup.$CHIPNUM/ || return 1 + echo $(ls /sys/devices/platform/gpio-mockup.$CHIPNUM/ | grep gpiochip) +} + +gpio_mockup_set_pull() { + local CHIPNUM=$1 + local LINE=$2 + local PULL=$3 + + FILE="/sys/kernel/debug/gpio-mockup/$(gpio_mockup_chip_name $CHIPNUM)/$LINE" + test -f $FILE || return 1 + echo "$PULL" > $FILE +} + +gpio_mockup_check_value() { + local CHIPNUM=$1 + local LINE=$2 + local EXPECTED=$3 + + FILE="/sys/kernel/debug/gpio-mockup/$(gpio_mockup_chip_name $CHIPNUM)/$LINE" + test -f $FILE || return 1 + + VAL=$(cat $FILE) + test $VAL -eq $EXPECTED || return 1 +} + +run_tool() { + # Executables to test are expected to be in the same directory as the + # testing script. + run timeout 10s $BATS_TEST_DIRNAME/"$@" +} + +coproc_run_tool() { + rm -f $BR_PROC_OUTPUT + coproc timeout 10s $BATS_TEST_DIRNAME/"$@" > $COPROC_OUTPUT 2> $COPROC_OUTPUT + COPROC_SAVED_PID=$COPROC_PID + # FIXME We're giving the background process some time to get up, but really this + # should be more reliable... + sleep 0.2 +} + +coproc_tool_stdin_write() { + echo $* >&${COPROC[1]} +} + +coproc_tool_kill() { + SIGNUM=$1 + + kill $SIGNUM $COPROC_SAVED_PID +} + +coproc_tool_wait() { + status="0" + # A workaround for the way bats handles command failures. + wait $COPROC_SAVED_PID || export status=$? + test "$status" -ne 0 || export status="0" + output=$(cat $COPROC_OUTPUT) + local ORIG_IFS="$IFS" + IFS=$'\n' lines=($output) + IFS="$ORIG_IFS" + rm -f $COPROC_OUTPUT +} + +setup() { + echo $BATS_TMPDIR >> /tmp/dirdir + gpio_mockup_remove +} + +teardown() { + if [ -n "$BG_PROC_PID" ] + then + kill -9 $BG_PROC_PID + run wait $BG_PROC_PID + BG_PROC_PID="" + fi + + gpio_mockup_remove +} + +# +# gpiodetect test cases +# + +@test "gpiodetect: list chips" { + gpio_mockup_probe 4 8 16 + + run_tool gpiodetect + + test "$status" -eq 0 + output_contains_line "$(gpio_mockup_chip_name 0) [gpio-mockup-A] (4 lines)" + output_contains_line "$(gpio_mockup_chip_name 1) [gpio-mockup-B] (8 lines)" + output_contains_line "$(gpio_mockup_chip_name 2) [gpio-mockup-C] (16 lines)" +} + +@test "gpiodetect: invalid args" { + run_tool gpiodetect unimplemented-arg + test "$status" -eq 1 +} + +# +# gpioinfo test cases +# + +@test "gpioinfo: dump all chips" { + gpio_mockup_probe 4 8 + + run_tool gpioinfo + + test "$status" -eq 0 + output_contains_line "$(gpio_mockup_chip_name 0) - 4 lines:" + output_contains_line "$(gpio_mockup_chip_name 1) - 8 lines:" + + output_regex_match "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high" + output_regex_match "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high" +} + +@test "gpioinfo: dump all chips with one line exported" { + gpio_mockup_probe 4 8 + + coproc_run_tool gpioset --mode=signal --active-low "$(gpio_mockup_chip_name 1)" 7=1 + + run_tool gpioinfo + + test "$status" -eq 0 + output_contains_line "$(gpio_mockup_chip_name 0) - 4 lines:" + output_contains_line "$(gpio_mockup_chip_name 1) - 8 lines:" + output_regex_match "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high" + output_regex_match "\\s+line\\s+7:\\s+unnamed\\s+\\\"gpioset\\\"\\s+output\\s+active-low" + + coproc_tool_kill + coproc_tool_wait +} + +@test "gpioinfo: dump one chip" { + gpio_mockup_probe 8 4 + + run_tool gpioinfo "$(gpio_mockup_chip_name 1)" + + test "$status" -eq 0 + assert_fail output_contains_line "$(gpio_mockup_chip_name 0) - 8 lines:" + output_contains_line "$(gpio_mockup_chip_name 1) - 4 lines:" + output_regex_match "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high" + assert_fail output_regex_match "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high" +} + +@test "gpioinfo: dump all but one chip" { + gpio_mockup_probe 4 4 8 4 + + run_tool gpioinfo "$(gpio_mockup_chip_name 0)" \ + "$(gpio_mockup_chip_name 1)" "$(gpio_mockup_chip_name 3)" + + test "$status" -eq 0 + output_contains_line "$(gpio_mockup_chip_name 0) - 4 lines:" + output_contains_line "$(gpio_mockup_chip_name 1) - 4 lines:" + assert_fail output_contains_line "$(gpio_mockup_chip_name 2) - 8 lines:" + output_contains_line "$(gpio_mockup_chip_name 3) - 4 lines:" + output_regex_match "\\s+line\\s+0:\\s+unnamed\\s+unused\\s+input\\s+active-high" + assert_fail output_regex_match "\\s+line\\s+7:\\s+unnamed\\s+unused\\s+input\\s+active-high" +} + +@test "gpioinfo: inexistent chip" { + run_tool gpioinfo "inexistent" + + test "$status" -eq 1 +} + +# +# gpiofind test cases +# + +@test "gpiofind: line found" { + gpio_mockup_probe named-lines 4 8 16 + + run_tool gpiofind gpio-mockup-B-7 + + test "$status" -eq "0" + test "$output" = "$(gpio_mockup_chip_name 1) 7" +} + +@test "gpiofind: line not found" { + gpio_mockup_probe named-lines 4 8 16 + + run_tool gpiofind nonexistent-line + + test "$status" -eq "1" +} + +@test "gpiofind: invalid args" { + run_tool gpiodetect unimplemented-arg + test "$status" -eq 1 +} + +# +# gpioget test cases +# + +@test "gpioget: read all lines" { + gpio_mockup_probe 8 8 8 + + gpio_mockup_set_pull 1 2 1 + gpio_mockup_set_pull 1 3 1 + gpio_mockup_set_pull 1 5 1 + gpio_mockup_set_pull 1 7 1 + + run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 1 2 3 4 5 6 7 + + test "$status" -eq "0" + test "$output" = "0 0 1 1 0 1 0 1" +} + +@test "gpioget: read all lines (active-low)" { + gpio_mockup_probe 8 8 8 + + gpio_mockup_set_pull 1 2 1 + gpio_mockup_set_pull 1 3 1 + gpio_mockup_set_pull 1 5 1 + gpio_mockup_set_pull 1 7 1 + + run_tool gpioget --active-low "$(gpio_mockup_chip_name 1)" 0 1 2 3 4 5 6 7 + + test "$status" -eq "0" + test "$output" = "1 1 0 0 1 0 1 0" +} + +@test "gpioget: read some lines" { + gpio_mockup_probe 8 8 8 + + gpio_mockup_set_pull 1 1 1 + gpio_mockup_set_pull 1 4 1 + gpio_mockup_set_pull 1 6 1 + + run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 1 4 6 + + test "$status" -eq "0" + test "$output" = "0 1 1 1" +} + +@test "gpioget: no arguments" { + run_tool gpioget + + test "$status" -eq "1" + output_regex_match ".*gpiochip must be specified" +} + +@test "gpioget: no lines specified" { + gpio_mockup_probe 8 8 8 + + run_tool gpioget "$(gpio_mockup_chip_name 1)" + + test "$status" -eq "1" + output_regex_match ".*at least one GPIO line offset must be specified" +} + +@test "gpioget: too many lines specified" { + gpio_mockup_probe 4 + + run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 1 2 3 4 + + test "$status" -eq "1" + output_regex_match ".*error reading GPIO values" +} + +@test "gpioget: same line twice" { + gpio_mockup_probe 8 8 8 + + run_tool gpioget "$(gpio_mockup_chip_name 1)" 0 0 + + test "$status" -eq "1" + output_regex_match ".*error reading GPIO values.*" +} + +# +# gpioset test cases +# + +@test "gpioset: set lines and wait for SIGTERM" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpioset --mode=signal "$(gpio_mockup_chip_name 2)" \ + 0=0 1=0 2=1 3=1 4=1 5=1 6=0 7=1 + + gpio_mockup_check_value 2 0 0 + gpio_mockup_check_value 2 1 0 + gpio_mockup_check_value 2 2 1 + gpio_mockup_check_value 2 3 1 + gpio_mockup_check_value 2 4 1 + gpio_mockup_check_value 2 5 1 + gpio_mockup_check_value 2 6 0 + gpio_mockup_check_value 2 7 1 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" +} + +@test "gpioset: set lines and wait for SIGTERM (active-low)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpioset --active-low --mode=signal "$(gpio_mockup_chip_name 2)" \ + 0=0 1=0 2=1 3=1 4=1 5=1 6=0 7=1 + + gpio_mockup_check_value 2 0 1 + gpio_mockup_check_value 2 1 1 + gpio_mockup_check_value 2 2 0 + gpio_mockup_check_value 2 3 0 + gpio_mockup_check_value 2 4 0 + gpio_mockup_check_value 2 5 0 + gpio_mockup_check_value 2 6 1 + gpio_mockup_check_value 2 7 0 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" +} + +@test "gpioset: set some lines and wait for ENTER" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpioset --mode=wait "$(gpio_mockup_chip_name 2)" \ + 1=0 2=1 5=1 6=0 7=1 + + gpio_mockup_check_value 2 1 0 + gpio_mockup_check_value 2 2 1 + gpio_mockup_check_value 2 5 1 + gpio_mockup_check_value 2 6 0 + gpio_mockup_check_value 2 7 1 + + coproc_tool_stdin_write "" + coproc_tool_wait + + test "$status" -eq "0" +} + +@test "gpioset: set some lines and wait for SIGINT" { + gpio_mockup_probe 8 + + coproc_run_tool gpioset --mode=signal "$(gpio_mockup_chip_name 0)" 0=1 + + gpio_mockup_check_value 0 0 1 + + coproc_tool_kill -SIGINT + coproc_tool_wait + + test "$status" -eq "0" +} + +@test "gpioset: set some lines and wait with --mode=time" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpioset --mode=time --sec=1 --usec=200000 \ + "$(gpio_mockup_chip_name 1)" 0=1 5=0 7=1 + + gpio_mockup_check_value 1 0 1 + gpio_mockup_check_value 1 5 0 + gpio_mockup_check_value 1 7 1 + + coproc_tool_wait + + test "$status" -eq "0" +} + +@test "gpioset: no arguments" { + run_tool gpioset + + test "$status" -eq "1" + output_regex_match ".*gpiochip must be specified" +} + +@test "gpioset: no lines specified" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" + + test "$status" -eq "1" + output_regex_match ".*at least one GPIO line offset to value mapping must be specified" +} + +@test "gpioset: too many lines specified" { + gpio_mockup_probe 4 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=1 1=1 2=1 3=1 4=1 5=1 + + test "$status" -eq "1" + output_regex_match ".*error setting the GPIO line values" +} + +@test "gpioset: use --sec without --mode=time" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset --mode=exit --sec=1 "$(gpio_mockup_chip_name 1)" 0=1 + + test "$status" -eq "1" + output_regex_match ".*can't specify wait time in this mode" +} + +@test "gpioset: use --usec without --mode=time" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset --mode=exit --usec=1 "$(gpio_mockup_chip_name 1)" 0=1 + + test "$status" -eq "1" + output_regex_match ".*can't specify wait time in this mode" +} + +@test "gpioset: invalid mapping" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=c + + test "$status" -eq "1" + output_regex_match ".*invalid offset<->value mapping" +} + +@test "gpioset: invalid value" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=3 + + test "$status" -eq "1" + output_regex_match ".*value must be 0 or 1" +} + +@test "gpioset: invalid offset" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" 4000000000=0 + + test "$status" -eq "1" + output_regex_match ".*invalid offset" +} + +@test "gpioset: daemonize in invalid mode" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset --background "$(gpio_mockup_chip_name 1)" 0=1 + + test "$status" -eq "1" + output_regex_match ".*can't daemonize in this mode" +} + +@test "gpioset: same line twice" { + gpio_mockup_probe 8 8 8 + + run_tool gpioset "$(gpio_mockup_chip_name 1)" 0=1 0=1 + + test "$status" -eq "1" + output_regex_match ".*error setting the GPIO line values.*" +} + +# +# gpiomon test cases +# + +@test "gpiomon: single rising edge event" { + gpio_mockup_probe 8 8 + + coproc_run_tool gpiomon --rising-edge "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match \ +"event:\\s+RISING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]" +} + +@test "gpiomon: single falling edge event" { + gpio_mockup_probe 8 8 + + coproc_run_tool gpiomon --falling-edge "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + gpio_mockup_set_pull 1 4 0 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match \ +"event:\\s+FALLING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]" +} + +@test "gpiomon: single rising edge event (active-low)" { + gpio_mockup_probe 8 8 + + coproc_run_tool gpiomon --rising-edge --active-low "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match \ +"event:\\s+RISING\\s+EDGE\\s+offset:\\s+4\\s+timestamp:\\s+\[[0-9]+\.[0-9]+\]" + +} + +@test "gpiomon: single rising edge event (silent mode)" { + gpio_mockup_probe 8 8 + + coproc_run_tool gpiomon --rising-edge --silent "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test -z "$output" +} + +@test "gpiomon: four alternating events" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon --num-events=4 "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + gpio_mockup_set_pull 1 4 0 + sleep 0.2 + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + gpio_mockup_set_pull 1 4 0 + sleep 0.2 + + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match \ +"event\\:\\s+FALLING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]" + output_regex_match \ +"event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]" +} + +@test "gpiomon: exit after SIGINT" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "$(gpio_mockup_chip_name 1)" 4 + + coproc_tool_kill -SIGINT + coproc_tool_wait + + test "$status" -eq "0" + test -z "$output" +} + +@test "gpiomon: exit after SIGTERM" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "$(gpio_mockup_chip_name 1)" 4 + + coproc_tool_kill -SIGTERM + coproc_tool_wait + + test "$status" -eq "0" + test -z "$output" +} + +@test "gpiomon: both event flags" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon --falling-edge --rising-edge "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + gpio_mockup_set_pull 1 4 0 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match \ +"event\\:\\s+FALLING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]" + output_regex_match \ +"event\\:\\s+RISING\\s+EDGE\\s+offset\\:\\s+4\\s+timestamp:\\s+\\[[0-9]+\\.[0-9]+\\]" +} + +@test "gpiomon: watch multiple lines" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon --format=%o "$(gpio_mockup_chip_name 1)" 1 2 3 4 5 + + gpio_mockup_set_pull 1 2 1 + gpio_mockup_set_pull 1 3 1 + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "${lines[0]}" = "2" + test "${lines[1]}" = "3" + test "${lines[2]}" = "4" +} + +@test "gpiomon: watch multiple lines (lines in mixed-up order)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon --format=%o "$(gpio_mockup_chip_name 1)" 5 2 7 1 6 + + gpio_mockup_set_pull 1 2 1 + gpio_mockup_set_pull 1 1 1 + gpio_mockup_set_pull 1 6 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "${lines[0]}" = "2" + test "${lines[1]}" = "1" + test "${lines[2]}" = "6" +} + +@test "gpiomon: same line twice" { + gpio_mockup_probe 8 8 8 + + run_tool gpiomon "$(gpio_mockup_chip_name 1)" 0 0 + + test "$status" -eq "1" + output_regex_match ".*error waiting for events.*" +} + +@test "gpiomon: no arguments" { + run_tool gpiomon + + test "$status" -eq "1" + output_regex_match ".*gpiochip must be specified" +} + +@test "gpiomon: line not specified" { + gpio_mockup_probe 8 8 8 + + run_tool gpiomon "$(gpio_mockup_chip_name 1)" + + test "$status" -eq "1" + output_regex_match ".*GPIO line offset must be specified" +} + +@test "gpiomon: line out of range" { + gpio_mockup_probe 4 + + run_tool gpiomon "$(gpio_mockup_chip_name 0)" 5 + + test "$status" -eq "1" + output_regex_match ".*error waiting for events" +} + +@test "gpiomon: custom format (event type + offset)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%e %o" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "1 4" +} + +@test "gpiomon: custom format (event type + offset joined)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%e%o" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "14" +} + +@test "gpiomon: custom format (timestamp)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%e %o %s.%n" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + output_regex_match "1 4 [0-9]+\\.[0-9]+" +} + +@test "gpiomon: custom format (double percent sign)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%%" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "%" +} + +@test "gpiomon: custom format (double percent sign + event type specifier)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%%e" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "%e" +} + +@test "gpiomon: custom format (single percent sign)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "%" +} + +@test "gpiomon: custom format (single percent sign between other characters)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=foo % bar" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "foo % bar" +} + +@test "gpiomon: custom format (unknown specifier)" { + gpio_mockup_probe 8 8 8 + + coproc_run_tool gpiomon "--format=%x" "$(gpio_mockup_chip_name 1)" 4 + + gpio_mockup_set_pull 1 4 1 + sleep 0.2 + + coproc_tool_kill + coproc_tool_wait + + test "$status" -eq "0" + test "$output" = "%x" +} -- 2.30.2