tests: use GLib for library test cases and bats for gpio-tools
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Fri, 7 Jun 2019 12:30:57 +0000 (14:30 +0200)
committerBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 1 Aug 2019 15:31:31 +0000 (17:31 +0200)
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 <bgolaszewski@baylibre.com>
19 files changed:
TODO
configure.ac
tests/Makefile.am
tests/gpiod-test.c
tests/gpiod-test.h
tests/tests-chip.c
tests/tests-ctxless.c
tests/tests-event.c
tests/tests-gpiodetect.c [deleted file]
tests/tests-gpiofind.c [deleted file]
tests/tests-gpioget.c [deleted file]
tests/tests-gpioinfo.c [deleted file]
tests/tests-gpiomon.c [deleted file]
tests/tests-gpioset.c [deleted file]
tests/tests-iter.c
tests/tests-line.c
tests/tests-misc.c
tools/Makefile.am
tools/gpio-tools-test.bats [new file with mode: 0755]

diff --git a/TODO b/TODO
index 6f1cd650d51b2390256118c1b4645705d286d6f7..f857fea6b61993e341d3bd734d62cc9d73929871 100644 (file)
--- 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
index e24b96d8a8491e2346877adde55eb736a0da1dbc..8f0eb3885eacb0f2871c559092c0c5dadcad3326 100644 (file)
@@ -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
index f24b966c59554f7ab66d53b4174f37f8c06d770b..6e6d823e54386a6f6bac7783a91e9541f3ddd9aa 100644 (file)
@@ -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).           *"
index d003c1ced587c4c08f2f3a1c21aa634c5db3b9a5..9eb5d6186c4a5a6e2abd437fa040d52cb18c132f 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-#include <ctype.h>
 #include <errno.h>
-#include <fcntl.h>
+#include <glib/gstdio.h>
 #include <gpio-mockup.h>
-#include <libgen.h>
-#include <poll.h>
-#include <pthread.h>
-#include <regex.h>
-#include <signal.h>
-#include <stdarg.h>
+#include <linux/version.h>
 #include <stdio.h>
-#include <string.h>
-#include <sys/signalfd.h>
-#include <sys/time.h>
-#include <sys/types.h>
 #include <sys/utsname.h>
-#include <sys/wait.h>
 #include <unistd.h>
 
 #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(&regex, pattern, REG_EXTENDED | REG_NEWLINE);
-       if (rv) {
-               regerror(rv, &regex, errbuf, sizeof(errbuf));
-               die("unable to compile regex '%s': %s", pattern, errbuf);
-       }
+       g_mutex_init(&thread->lock);
+       g_cond_init(&thread->cond);
 
-       rv = regexec(&regex, str, 0, 0, 0);
-       if (rv == REG_NOERROR) {
-               ret = true;
-       } else if (rv == REG_NOMATCH) {
-               ret = false;
-       } else {
-               regerror(rv, &regex, 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(&regex);
+       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);
 }
index 1815c6513cce72f45014401ec8735a7eea9320e4..bb0f8beb772b6f2cbab3d64f182668a45511d4a8 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* 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 <glib.h>
 #include <gpiod.h>
-#include <string.h>
-
-#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__ */
index 0acb5c7b25ccf123465512a76b29b4959ba469a0..6edb61c73b43fe4e3678deb7599ff524238507f6 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
+ * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* Test cases for GPIO chip handling. */
-
 #include <errno.h>
-#include <stdio.h>
 
 #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 });
index 4e7cc552ac8528d51c401a32f144b70720365089..c1e1ca624b3f4a98703d579c465dd5957824eac8 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* Test cases for the high-level API. */
-
 #include <errno.h>
 
 #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 });
index b97b6f8cf26d5fb98af62a0a49f54f701240e002..51b22818d14a8e53eb6d2a3826f8a1962e7ecdbb 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* Test cases for GPIO line events. */
-
 #include <errno.h>
 #include <unistd.h>
 
 #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 (file)
index bd5eeb1..0000000
+++ /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 <bartekgola@gmail.com>
- */
-
-/* Test cases for the gpiodetect program. */
-
-#include <stdio.h>
-
-#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 (file)
index 6d8e12a..0000000
+++ /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 <bartekgola@gmail.com>
- */
-
-/* Test cases for the gpiofind program. */
-
-#include <stdio.h>
-
-#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 (file)
index 91796ac..0000000
+++ /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 <bartekgola@gmail.com>
- * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
- */
-
-/* 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 (file)
index 162896f..0000000
+++ /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 <bartekgola@gmail.com>
- */
-
-/* Test cases for the gpioinfo program. */
-
-#include <stdio.h>
-
-#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 (file)
index 7440d65..0000000
+++ /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 <bartekgola@gmail.com>
- * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
- */
-
-/* Test cases for the gpiomon program. */
-
-#include <signal.h>
-#include <unistd.h>
-
-#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 (file)
index c3159a8..0000000
+++ /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 <bartekgola@gmail.com>
- * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
- */
-
-/* Test cases for the gpioset program. */
-
-#include <signal.h>
-#include <unistd.h>
-
-#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 });
index de71efdb874b2540873df741ef4188228eaedcc2..8deee8ef6172182a826589dd682244849c8af7ab 100644 (file)
@@ -2,97 +2,86 @@
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
+ * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* Iterator test cases. */
+#include <string.h>
 
 #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 });
index a0cb3555626c8cc471e8ab7d3776e93c9d80c75f..db8dc03379cd9d94e898f8df8ae189ba0bb20b44 100644 (file)
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* GPIO line test cases. */
-
 #include <errno.h>
+#include <string.h>
 
 #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 });
index 99a80a793dd4e9a3277dbccc1648e8555435c6b4..e838b6283a789a12e23f78de25488727c0f48d0e 100644 (file)
@@ -2,23 +2,28 @@
 /*
  * This file is part of libgpiod.
  *
- * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
+ * Copyright (C) 2019 Bartosz Golaszewski <bgolaszewski@baylibre.com>
  */
 
-/* Misc test cases. */
-
-#include <errno.h>
+#include <string.h>
 
 #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, { });
index 4198dba74968cd3ce3a41517d3061e7a0a59e433..d9615f98dfafcd4f89651d41d122df5e2b638d8c 100644 (file)
@@ -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 (executable)
index 0000000..6a0f076
--- /dev/null
@@ -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 <bgolaszewski@baylibre.com>
+#
+
+# 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"
+}