tools/Makefile
tests/Makefile
tests/gpiosim/Makefile
+ tests/gpiosim-glib/Makefile
+ tests/harness/Makefile
bindings/cxx/libgpiodcxx.pc
bindings/Makefile
bindings/cxx/Makefile
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl>
-SUBDIRS = gpiosim
+SUBDIRS = gpiosim gpiosim-glib harness
-AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/gpiosim/
+AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/gpiosim-glib/
+AM_CFLAGS += -I$(top_srcdir)/tests/harness/
AM_CFLAGS += -include $(top_builddir)/config.h
AM_CFLAGS += -Wall -Wextra -g -std=gnu89 $(GLIB_CFLAGS) $(GIO_CFLAGS)
AM_CFLAGS += -DG_LOG_DOMAIN=\"gpiod-test\"
LDADD = $(top_builddir)/lib/libgpiod.la
LDADD += $(top_builddir)/tests/gpiosim/libgpiosim.la
+LDADD += $(top_builddir)/tests/gpiosim-glib/libgpiosim-glib.la
+LDADD += $(top_builddir)/tests/harness/libgpiod-test-harness.la
LDADD += $(GLIB_LIBS) $(GIO_LIBS)
noinst_PROGRAMS = gpiod-test
gpiod_test_SOURCES = \
- gpiod-test.c \
- gpiod-test.h \
- gpiod-test-helpers.c \
- gpiod-test-helpers.h \
- gpiod-test-sim.c \
- gpiod-test-sim.h \
+ helpers.h \
tests-chip.c \
tests-chip-info.c \
tests-edge-event.c \
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
-
-/*
- * 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.
- */
-
-#include "gpiod-test-helpers.h"
-
-GVariant *
-gpiod_test_package_line_names(const GPIOSimLineName *names)
-{
- g_autoptr(GVariantBuilder) builder = NULL;
- const GPIOSimLineName *name;
-
- builder = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
-
- for (name = &names[0]; name->name; name++)
- g_variant_builder_add(builder, "(us)",
- name->offset, name->name);
-
- return g_variant_ref_sink(g_variant_new("a(us)", builder));
-}
-
-GVariant *gpiod_test_package_hogs(const GPIOSimHog *hogs)
-{
- g_autoptr(GVariantBuilder) builder = NULL;
- const GPIOSimHog *hog;
-
- builder = g_variant_builder_new(G_VARIANT_TYPE("a(usi)"));
-
- for (hog = &hogs[0]; hog->name; hog++)
- g_variant_builder_add(builder, "(usi)",
- hog->offset, hog->name, hog->direction);
-
- return g_variant_ref_sink(g_variant_new("a(usi)", builder));
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
-
-#ifndef __GPIOD_TEST_HELPERS_H__
-#define __GPIOD_TEST_HELPERS_H__
-
-#include <errno.h>
-#include <glib.h>
-#include <gpiod.h>
-
-#include "gpiod-test-sim.h"
-
-/*
- * These typedefs are needed to make g_autoptr work - it doesn't accept
- * regular 'struct typename' syntax.
- */
-
-typedef struct gpiod_chip struct_gpiod_chip;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_chip, gpiod_chip_close);
-
-typedef struct gpiod_chip_info struct_gpiod_chip_info;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_chip_info, gpiod_chip_info_free);
-
-typedef struct gpiod_line_info struct_gpiod_line_info;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_info, gpiod_line_info_free);
-
-typedef struct gpiod_info_event struct_gpiod_info_event;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_info_event, gpiod_info_event_free);
-
-typedef struct gpiod_line_config struct_gpiod_line_config;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_config, gpiod_line_config_free);
-
-typedef struct gpiod_line_settings struct_gpiod_line_settings;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_settings,
- gpiod_line_settings_free);
-
-typedef struct gpiod_request_config struct_gpiod_request_config;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_request_config,
- gpiod_request_config_free);
-
-typedef struct gpiod_line_request struct_gpiod_line_request;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_request,
- gpiod_line_request_release);
-
-typedef struct gpiod_edge_event struct_gpiod_edge_event;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event, gpiod_edge_event_free);
-
-typedef struct gpiod_edge_event_buffer struct_gpiod_edge_event_buffer;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event_buffer,
- gpiod_edge_event_buffer_free);
-
-#define gpiod_test_return_if_failed() \
- do { \
- if (g_test_failed()) \
- return; \
- } while (0)
-
-#define gpiod_test_join_thread_and_return_if_failed(_thread) \
- do { \
- if (g_test_failed()) { \
- g_thread_join(_thread); \
- return; \
- } \
- } while (0)
-
-#define gpiod_test_open_chip_or_fail(_path) \
- ({ \
- struct gpiod_chip *_chip = gpiod_chip_open(_path); \
- g_assert_nonnull(_chip); \
- gpiod_test_return_if_failed(); \
- _chip; \
- })
-
-#define gpiod_test_chip_get_info_or_fail(_chip) \
- ({ \
- struct gpiod_chip_info *_info = gpiod_chip_get_info(_chip); \
- g_assert_nonnull(_info); \
- gpiod_test_return_if_failed(); \
- _info; \
- })
-
-#define gpiod_test_chip_get_line_info_or_fail(_chip, _offset) \
- ({ \
- struct gpiod_line_info *_info = \
- gpiod_chip_get_line_info(_chip, _offset); \
- g_assert_nonnull(_info); \
- gpiod_test_return_if_failed(); \
- _info; \
- })
-
-#define gpiod_test_chip_watch_line_info_or_fail(_chip, _offset) \
- ({ \
- struct gpiod_line_info *_info = \
- gpiod_chip_watch_line_info(_chip, _offset); \
- g_assert_nonnull(_info); \
- gpiod_test_return_if_failed(); \
- _info; \
- })
-
-#define gpiod_test_create_line_settings_or_fail() \
- ({ \
- struct gpiod_line_settings *_settings = \
- gpiod_line_settings_new(); \
- g_assert_nonnull(_settings); \
- gpiod_test_return_if_failed(); \
- _settings; \
- })
-
-#define gpiod_test_create_line_config_or_fail() \
- ({ \
- struct gpiod_line_config *_config = \
- gpiod_line_config_new(); \
- g_assert_nonnull(_config); \
- gpiod_test_return_if_failed(); \
- _config; \
- })
-
-#define gpiod_test_create_edge_event_buffer_or_fail(_capacity) \
- ({ \
- struct gpiod_edge_event_buffer *_buffer = \
- gpiod_edge_event_buffer_new(_capacity); \
- g_assert_nonnull(_buffer); \
- gpiod_test_return_if_failed(); \
- _buffer; \
- })
-
-#define gpiod_test_line_config_add_line_settings_or_fail(_line_cfg, _offsets, \
- _num_offsets, \
- _settings) \
- do { \
- gint _ret = gpiod_line_config_add_line_settings(_line_cfg, \
- _offsets, \
- _num_offsets, \
- _settings); \
- g_assert_cmpint(_ret, ==, 0); \
- gpiod_test_return_if_failed(); \
- } while (0)
-
-#define gpiod_test_line_config_get_line_settings_or_fail(_line_cfg, _offset) \
- ({ \
- struct gpiod_line_settings *_settings = \
- gpiod_line_config_get_line_settings(_line_cfg, \
- _offset); \
- g_assert_nonnull(_settings); \
- gpiod_test_return_if_failed(); \
- _settings; \
- })
-
-#define gpiod_test_line_config_set_output_values_or_fail(_line_cfg, _values, \
- _num_values) \
- do { \
- gint _ret = gpiod_line_config_set_output_values(_line_cfg, \
- _values, \
- _num_values); \
- g_assert_cmpint(_ret, ==, 0); \
- gpiod_test_return_if_failed(); \
- } while (0)
-
-#define gpiod_test_create_request_config_or_fail() \
- ({ \
- struct gpiod_request_config *_config = \
- gpiod_request_config_new(); \
- g_assert_nonnull(_config); \
- gpiod_test_return_if_failed(); \
- _config; \
- })
-
-#define gpiod_test_chip_request_lines_or_fail(_chip, _req_cfg, _line_cfg) \
- ({ \
- struct gpiod_line_request *_request = \
- gpiod_chip_request_lines(_chip, \
- _req_cfg, _line_cfg); \
- g_assert_nonnull(_request); \
- gpiod_test_return_if_failed(); \
- _request; \
- })
-
-#define gpiod_test_line_request_reconfigure_lines_or_fail(_request, _line_cfg) \
- do { \
- gint _ret = gpiod_line_request_reconfigure_lines(_request, \
- _line_cfg); \
- g_assert_cmpint(_ret, ==, 0); \
- gpiod_test_return_if_failed(); \
- } while (0)
-
-#define gpiod_test_expect_errno(_expected) \
- g_assert_cmpint(_expected, ==, errno)
-
-typedef struct {
- guint offset;
- const gchar *name;
-} GPIOSimLineName;
-
-typedef struct {
- guint offset;
- const gchar *name;
- GPIOSimDirection direction;
-} GPIOSimHog;
-
-GVariant *gpiod_test_package_line_names(const GPIOSimLineName *names);
-GVariant *gpiod_test_package_hogs(const GPIOSimHog *hogs);
-
-#endif /* __GPIOD_TEST_HELPERS_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
-
-#include <errno.h>
-#include <gpiosim.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "gpiod-test-sim.h"
-
-G_DEFINE_QUARK(g-gpiosim-error, g_gpiosim_error);
-
-struct _GPIOSimChip {
- GObject parent_instance;
- struct gpiosim_bank *bank;
- GError *construct_err;
- guint num_lines;
- gchar *label;
- GVariant *line_names;
- GVariant *hogs;
-};
-
-enum {
- G_GPIOSIM_CHIP_PROP_DEV_PATH = 1,
- G_GPIOSIM_CHIP_PROP_NAME,
- G_GPIOSIM_CHIP_PROP_NUM_LINES,
- G_GPIOSIM_CHIP_PROP_LABEL,
- G_GPIOSIM_CHIP_PROP_LINE_NAMES,
- G_GPIOSIM_CHIP_PROP_HOGS,
-};
-
-static struct gpiosim_ctx *sim_ctx;
-
-static gboolean
-g_gpiosim_chip_initable_init(GInitable *initable,
- GCancellable *cancellable G_GNUC_UNUSED,
- GError **err)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP_OBJ(initable);
-
- if (self->construct_err) {
- g_propagate_error(err, self->construct_err);
- self->construct_err = NULL;
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void g_gpiosim_chip_initable_iface_init(GInitableIface *iface)
-{
- iface->init = g_gpiosim_chip_initable_init;
-}
-
-G_DEFINE_TYPE_WITH_CODE(GPIOSimChip, g_gpiosim_chip, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE(
- G_TYPE_INITABLE,
- g_gpiosim_chip_initable_iface_init));
-
-static void g_gpiosim_ctx_unref(void)
-{
- gpiosim_ctx_unref(sim_ctx);
-}
-
-static gboolean g_gpiosim_chip_apply_line_names(GPIOSimChip *self)
-{
- g_autoptr(GVariantIter) iter = NULL;
- guint offset;
- gchar *name;
- int ret;
-
- if (!self->line_names)
- return TRUE;
-
- iter = g_variant_iter_new(self->line_names);
-
- while (g_variant_iter_loop(iter, "(us)", &offset, &name)) {
- ret = gpiosim_bank_set_line_name(self->bank, offset, name);
- if (ret) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to set the name of the simulated GPIO line: %s",
- g_strerror(errno));
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static gboolean g_gpiosim_chip_apply_hogs(GPIOSimChip *self)
-{
- g_autoptr(GVariantIter) iter = NULL;
- enum gpiosim_direction dir;
- guint offset;
- gchar *name;
- gint vdir;
- int ret;
-
- if (!self->hogs)
- return TRUE;
-
- iter = g_variant_iter_new(self->hogs);
-
- while (g_variant_iter_loop(iter, "(usi)", &offset, &name, &vdir)) {
- switch (vdir) {
- case G_GPIOSIM_DIRECTION_INPUT:
- dir = GPIOSIM_DIRECTION_INPUT;
- break;
- case G_GPIOSIM_DIRECTION_OUTPUT_HIGH:
- dir = GPIOSIM_DIRECTION_OUTPUT_HIGH;
- break;
- case G_GPIOSIM_DIRECTION_OUTPUT_LOW:
- dir = GPIOSIM_DIRECTION_OUTPUT_LOW;
- break;
- default:
- g_error("Invalid hog direction value: %d", vdir);
- }
-
- ret = gpiosim_bank_hog_line(self->bank, offset, name, dir);
- if (ret) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to hog the simulated GPIO line: %s",
- g_strerror(errno));
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static gboolean g_gpiosim_chip_apply_properties(GPIOSimChip *self)
-{
- int ret;
-
- ret = gpiosim_bank_set_num_lines(self->bank, self->num_lines);
- if (ret) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to set the number of lines exposed by the simulated chip: %s",
- g_strerror(errno));
- return FALSE;
- }
-
- if (self->label) {
- ret = gpiosim_bank_set_label(self->bank, self->label);
- if (ret) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to set the label of the simulated chip: %s",
- g_strerror(errno));
- return FALSE;
- }
- }
-
- ret = g_gpiosim_chip_apply_line_names(self);
- if (!ret)
- return FALSE;
-
- return g_gpiosim_chip_apply_hogs(self);
-}
-
-static gboolean g_gpiosim_chip_enable(GPIOSimChip *self)
-{
- struct gpiosim_dev *dev;
- int ret;
-
- dev = gpiosim_bank_get_dev(self->bank);
- ret = gpiosim_dev_enable(dev);
- gpiosim_dev_unref(dev);
- if (ret) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_ENABLE_FAILED,
- "Error while trying to enable the simulated GPIO device: %s",
- g_strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean g_gpiosim_ctx_init(GError **err)
-{
- sim_ctx = gpiosim_ctx_new();
- if (!sim_ctx) {
- g_set_error(err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CTX_INIT_FAILED,
- "Unable to initialize libgpiosim: %s",
- g_strerror(errno));
- return FALSE;
- }
-
- atexit(g_gpiosim_ctx_unref);
-
- return TRUE;
-}
-
-static void g_gpiosim_chip_constructed(GObject *obj)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
- struct gpiosim_dev *dev;
- gboolean ret;
-
- if (!sim_ctx) {
- ret = g_gpiosim_ctx_init(&self->construct_err);
- if (!ret)
- return;
- }
-
- dev = gpiosim_dev_new(sim_ctx);
- if (!dev) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to instantiate new GPIO device: %s",
- g_strerror(errno));
- return;
- }
-
- self->bank = gpiosim_bank_new(dev);
- gpiosim_dev_unref(dev);
- if (!self->bank) {
- g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- "Unable to instantiate new GPIO bank: %s",
- g_strerror(errno));
- return;
- }
-
- ret = g_gpiosim_chip_apply_properties(self);
- if (!ret)
- return;
-
- ret = g_gpiosim_chip_enable(self);
- if (!ret)
- return;
-
- G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->constructed(obj);
-}
-
-static void g_gpiosim_chip_get_property(GObject *obj, guint prop_id,
- GValue *val, GParamSpec *pspec)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
-
- switch (prop_id) {
- case G_GPIOSIM_CHIP_PROP_DEV_PATH:
- g_value_set_static_string(val,
- gpiosim_bank_get_dev_path(self->bank));
- break;
- case G_GPIOSIM_CHIP_PROP_NAME:
- g_value_set_static_string(val,
- gpiosim_bank_get_chip_name(self->bank));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
- break;
- }
-}
-
-static void set_variant_prop(GVariant **prop, const GValue *val)
-{
- GVariant *variant = g_value_get_variant(val);
-
- g_clear_pointer(prop, g_variant_unref);
- if (variant)
- *prop = g_variant_ref(variant);
-}
-
-static void g_gpiosim_chip_set_property(GObject *obj, guint prop_id,
- const GValue *val, GParamSpec *pspec)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
- const gchar *label;
-
- switch (prop_id) {
- case G_GPIOSIM_CHIP_PROP_NUM_LINES:
- self->num_lines = g_value_get_uint(val);
- break;
- case G_GPIOSIM_CHIP_PROP_LABEL:
- g_clear_pointer(&self->label, g_free);
- label = g_value_get_string(val);
- if (label)
- self->label = g_strdup(label);
- break;
- case G_GPIOSIM_CHIP_PROP_LINE_NAMES:
- set_variant_prop(&self->line_names, val);
- break;
- case G_GPIOSIM_CHIP_PROP_HOGS:
- set_variant_prop(&self->hogs, val);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
- break;
- }
-}
-
-static void g_gpiosim_chip_dispose(GObject *obj)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
-
- g_clear_pointer(&self->line_names, g_variant_unref);
- g_clear_pointer(&self->hogs, g_variant_unref);
-
- G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->dispose(obj);
-}
-
-static void g_gpiosim_disable_and_cleanup(struct gpiosim_bank *bank)
-{
- struct gpiosim_dev *dev;
- gint ret;
-
- dev = gpiosim_bank_get_dev(bank);
-
- if (gpiosim_dev_is_live(dev)) {
- ret = gpiosim_dev_disable(dev);
- if (ret)
- g_warning("Error while trying to disable the simulated GPIO device: %s",
- g_strerror(errno));
- }
-
- gpiosim_dev_unref(dev);
- gpiosim_bank_unref(bank);
-}
-
-static void g_gpiosim_chip_finalize(GObject *obj)
-{
- GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
-
- g_clear_error(&self->construct_err);
- g_clear_pointer(&self->label, g_free);
- g_clear_pointer(&self->bank, g_gpiosim_disable_and_cleanup);
-
- G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->finalize(obj);
-}
-
-static void g_gpiosim_chip_class_init(GPIOSimChipClass *chip_class)
-{
- GObjectClass *class = G_OBJECT_CLASS(chip_class);
-
- class->constructed = g_gpiosim_chip_constructed;
- class->get_property = g_gpiosim_chip_get_property;
- class->set_property = g_gpiosim_chip_set_property;
- class->dispose = g_gpiosim_chip_dispose;
- class->finalize = g_gpiosim_chip_finalize;
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_DEV_PATH,
- g_param_spec_string("dev-path", "Device path",
- "Character device filesystem path.", NULL,
- G_PARAM_READABLE));
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_NAME,
- g_param_spec_string(
- "name", "Chip name",
- "Name of this chip device as set by the kernel.", NULL,
- G_PARAM_READABLE));
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_NUM_LINES,
- g_param_spec_uint("num-lines", "Number of lines",
- "Number of lines this simulated chip exposes.",
- 1, G_MAXUINT, 1,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_LABEL,
- g_param_spec_string("label", "Chip label",
- "Label of this simulated chip.", NULL,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_LINE_NAMES,
- g_param_spec_variant(
- "line-names", "Line names",
- "List of names of the lines exposed by this chip",
- (GVariantType *)"a(us)", NULL,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property(
- class, G_GPIOSIM_CHIP_PROP_HOGS,
- g_param_spec_variant(
- "hogs", "Line hogs",
- "List of hogged lines and their directions.",
- (GVariantType *)"a(usi)", NULL,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void g_gpiosim_chip_init(GPIOSimChip *self)
-{
- self->construct_err = NULL;
- self->num_lines = 1;
- self->label = NULL;
- self->line_names = NULL;
- self->hogs = NULL;
-}
-
-static const gchar *
-g_gpiosim_chip_get_string_prop(GPIOSimChip *self, const gchar *prop)
-{
- GValue val = G_VALUE_INIT;
- const gchar *str;
-
- g_object_get_property(G_OBJECT(self), prop, &val);
- str = g_value_get_string(&val);
- g_value_unset(&val);
-
- return str;
-}
-
-const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self)
-{
- return g_gpiosim_chip_get_string_prop(self, "dev-path");
-}
-
-const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self)
-{
- return g_gpiosim_chip_get_string_prop(self, "name");
-}
-
-GPIOSimValue
-_g_gpiosim_chip_get_value(GPIOSimChip *chip, guint offset, GError **err)
-{
- enum gpiosim_value val;
-
- val = gpiosim_bank_get_value(chip->bank, offset);
- switch (val) {
- case GPIOSIM_VALUE_ERROR:
- g_set_error(err, G_GPIOSIM_ERROR,
- G_GPIOSIM_ERR_GET_VALUE_FAILED,
- "Unable to read the line value: %s",
- g_strerror(errno));
- return G_GPIOSIM_VALUE_ERROR;
- case GPIOSIM_VALUE_INACTIVE:
- return G_GPIOSIM_VALUE_INACTIVE;
- case GPIOSIM_VALUE_ACTIVE:
- return G_GPIOSIM_VALUE_ACTIVE;
- }
-
- g_error("Invalid line value returned by gpiosim");
-}
-
-void g_gpiosim_chip_set_pull(GPIOSimChip *chip, guint offset, GPIOSimPull pull)
-{
- enum gpiosim_pull sim_pull;
- gint ret;
-
- switch (pull) {
- case G_GPIOSIM_PULL_DOWN:
- sim_pull = GPIOSIM_PULL_DOWN;
- break;
- case G_GPIOSIM_PULL_UP:
- sim_pull = GPIOSIM_PULL_UP;
- break;
- default:
- g_error("invalid pull value");
- }
-
- ret = gpiosim_bank_set_pull(chip->bank, offset, sim_pull);
- if (ret)
- g_critical("Unable to set the pull setting for simulated line: %s",
- g_strerror(errno));
-}
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
-
-#ifndef __GPIOD_TEST_SIM_H__
-#define __GPIOD_TEST_SIM_H__
-
-#include <gio/gio.h>
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
- G_GPIOSIM_VALUE_ERROR = -1,
- G_GPIOSIM_VALUE_INACTIVE = 0,
- G_GPIOSIM_VALUE_ACTIVE = 1,
-} GPIOSimValue;
-
-typedef enum {
- G_GPIOSIM_PULL_UP = 1,
- G_GPIOSIM_PULL_DOWN,
-} GPIOSimPull;
-
-typedef enum {
- G_GPIOSIM_DIRECTION_INPUT = 1,
- G_GPIOSIM_DIRECTION_OUTPUT_HIGH,
- G_GPIOSIM_DIRECTION_OUTPUT_LOW,
-} GPIOSimDirection;
-
-#define G_GPIOSIM_ERROR g_gpiosim_error_quark()
-
-typedef enum {
- G_GPIOSIM_ERR_CTX_INIT_FAILED = 1,
- G_GPIOSIM_ERR_CHIP_INIT_FAILED,
- G_GPIOSIM_ERR_CHIP_ENABLE_FAILED,
- G_GPIOSIM_ERR_GET_VALUE_FAILED,
-} GPIOSimError;
-
-GQuark g_gpiosim_error_quark(void);
-
-G_DECLARE_FINAL_TYPE(GPIOSimChip, g_gpiosim_chip, G_GPIOSIM, CHIP, GObject);
-
-#define G_GPIOSIM_CHIP_TYPE (g_gpiosim_chip_get_type())
-#define G_GPIOSIM_CHIP_OBJ(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), G_GPIOSIM_CHIP_TYPE, GPIOSimChip))
-
-#define g_gpiosim_chip_new(...) \
- ({ \
- g_autoptr(GError) _err = NULL; \
- GPIOSimChip *_chip = G_GPIOSIM_CHIP_OBJ( \
- g_initable_new(G_GPIOSIM_CHIP_TYPE, \
- NULL, &_err, \
- __VA_ARGS__)); \
- g_assert_no_error(_err); \
- if (g_test_failed()) \
- return; \
- _chip; \
- })
-
-const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self);
-const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self);
-
-GPIOSimValue
-_g_gpiosim_chip_get_value(GPIOSimChip *self, guint offset, GError **err);
-void g_gpiosim_chip_set_pull(GPIOSimChip *self, guint offset, GPIOSimPull pull);
-
-#define g_gpiosim_chip_get_value(self, offset) \
- ({ \
- g_autoptr(GError) _err = NULL; \
- gint _val = _g_gpiosim_chip_get_value(self, offset, &_err); \
- g_assert_no_error(_err); \
- if (g_test_failed()) \
- return; \
- _val; \
- })
-
-G_END_DECLS
-
-#endif /* __GPIOD_TEST_SIM_H__ */
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-// SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl>
-
-#include <errno.h>
-#include <linux/version.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-
-#include "gpiod-test.h"
-
-#define MIN_KERNEL_MAJOR 5
-#define MIN_KERNEL_MINOR 19
-#define MIN_KERNEL_RELEASE 0
-#define MIN_KERNEL_VERSION KERNEL_VERSION(MIN_KERNEL_MAJOR, \
- MIN_KERNEL_MINOR, \
- MIN_KERNEL_RELEASE)
-
-static GList *tests;
-
-static gboolean check_kernel(void)
-{
- guint major, minor, release;
- struct utsname un;
- gint ret;
-
- g_debug("checking linux kernel version");
-
- ret = uname(&un);
- if (ret) {
- g_critical("unable to read the kernel release version: %s",
- g_strerror(errno));
- return FALSE;
- }
-
- ret = sscanf(un.release, "%u.%u.%u", &major, &minor, &release);
- if (ret != 3) {
- g_critical("error reading kernel release version");
- return FALSE;
- }
-
- if (KERNEL_VERSION(major, minor, release) < MIN_KERNEL_VERSION) {
- g_critical("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);
- return FALSE;
- }
-
- g_debug("kernel release is v%u.%u.%u - ok to run tests",
- major, minor, release);
-
- return TRUE;
-}
-
-static void test_func_wrapper(gconstpointer data)
-{
- const struct _gpiod_test_case *test = data;
-
- test->func();
-}
-
-static void add_test_from_list(gpointer element, gpointer data G_GNUC_UNUSED)
-{
- struct _gpiod_test_case *test = element;
-
- g_test_add_data_func(test->path, test, test_func_wrapper);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
- g_test_set_nonfatal_assertions();
-
- g_debug("running libgpiod test suite");
- g_debug("%u tests registered", g_list_length(tests));
-
- if (!check_kernel())
- return EXIT_FAILURE;
-
- g_list_foreach(tests, add_test_from_list, NULL);
- g_list_free(tests);
-
- return g_test_run();
-}
-
-void _gpiod_test_register(struct _gpiod_test_case *test)
-{
- tests = g_list_append(tests, test);
-}
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
-
-/*
- * 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>
-
-/* These are private definitions and should not be used directly. */
-
-struct _gpiod_test_case {
- const gchar *path;
- void (*func)(void);
-};
-
-void _gpiod_test_register(struct _gpiod_test_case *test);
-
-#define _GPIOD_TEST_PATH(_name) \
- "/gpiod/" GPIOD_TEST_GROUP "/" G_STRINGIFY(_name)
-
-/*
- * Register a test case function.
- */
-#define GPIOD_TEST_CASE(_name) \
- static void _gpiod_test_func_##_name(void); \
- static struct _gpiod_test_case _##_name##_test_case = { \
- .path = _GPIOD_TEST_PATH(_name), \
- .func = _gpiod_test_func_##_name, \
- }; \
- static __attribute__((constructor)) void \
- _##_name##_test_register(void) \
- { \
- _gpiod_test_register(&_##_name##_test_case); \
- } \
- static void _gpiod_test_func_##_name(void)
-
-#endif /* __GPIOD_TEST_H__ */
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+noinst_LTLIBRARIES = libgpiosim-glib.la
+libgpiosim_glib_la_SOURCES = \
+ gpiosim-glib.c \
+ gpiosim-glib.h
+
+AM_CFLAGS = -I$(top_srcdir)/tests/gpiosim/
+AM_CFLAGS += -include $(top_builddir)/config.h
+AM_CFLAGS += -Wall -Wextra -g -std=gnu89 $(GLIB_CFLAGS) $(GIO_CFLAGS)
+AM_CFLAGS += -DG_LOG_DOMAIN=\"gpiosim-glib\"
+libgpiosim_glib_la_LDFLAGS = -lgpiosim
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#include <errno.h>
+#include <gpiosim.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "gpiosim-glib.h"
+
+G_DEFINE_QUARK(g-gpiosim-error, g_gpiosim_error);
+
+struct _GPIOSimChip {
+ GObject parent_instance;
+ struct gpiosim_bank *bank;
+ GError *construct_err;
+ guint num_lines;
+ gchar *label;
+ GVariant *line_names;
+ GVariant *hogs;
+};
+
+enum {
+ G_GPIOSIM_CHIP_PROP_DEV_PATH = 1,
+ G_GPIOSIM_CHIP_PROP_NAME,
+ G_GPIOSIM_CHIP_PROP_NUM_LINES,
+ G_GPIOSIM_CHIP_PROP_LABEL,
+ G_GPIOSIM_CHIP_PROP_LINE_NAMES,
+ G_GPIOSIM_CHIP_PROP_HOGS,
+};
+
+static struct gpiosim_ctx *sim_ctx;
+
+static gboolean
+g_gpiosim_chip_initable_init(GInitable *initable,
+ GCancellable *cancellable G_GNUC_UNUSED,
+ GError **err)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP_OBJ(initable);
+
+ if (self->construct_err) {
+ g_propagate_error(err, self->construct_err);
+ self->construct_err = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void g_gpiosim_chip_initable_iface_init(GInitableIface *iface)
+{
+ iface->init = g_gpiosim_chip_initable_init;
+}
+
+G_DEFINE_TYPE_WITH_CODE(GPIOSimChip, g_gpiosim_chip, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(
+ G_TYPE_INITABLE,
+ g_gpiosim_chip_initable_iface_init));
+
+static void g_gpiosim_ctx_unref(void)
+{
+ gpiosim_ctx_unref(sim_ctx);
+}
+
+static gboolean g_gpiosim_chip_apply_line_names(GPIOSimChip *self)
+{
+ g_autoptr(GVariantIter) iter = NULL;
+ guint offset;
+ gchar *name;
+ int ret;
+
+ if (!self->line_names)
+ return TRUE;
+
+ iter = g_variant_iter_new(self->line_names);
+
+ while (g_variant_iter_loop(iter, "(us)", &offset, &name)) {
+ ret = gpiosim_bank_set_line_name(self->bank, offset, name);
+ if (ret) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to set the name of the simulated GPIO line: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean g_gpiosim_chip_apply_hogs(GPIOSimChip *self)
+{
+ g_autoptr(GVariantIter) iter = NULL;
+ enum gpiosim_direction dir;
+ guint offset;
+ gchar *name;
+ gint vdir;
+ int ret;
+
+ if (!self->hogs)
+ return TRUE;
+
+ iter = g_variant_iter_new(self->hogs);
+
+ while (g_variant_iter_loop(iter, "(usi)", &offset, &name, &vdir)) {
+ switch (vdir) {
+ case G_GPIOSIM_DIRECTION_INPUT:
+ dir = GPIOSIM_DIRECTION_INPUT;
+ break;
+ case G_GPIOSIM_DIRECTION_OUTPUT_HIGH:
+ dir = GPIOSIM_DIRECTION_OUTPUT_HIGH;
+ break;
+ case G_GPIOSIM_DIRECTION_OUTPUT_LOW:
+ dir = GPIOSIM_DIRECTION_OUTPUT_LOW;
+ break;
+ default:
+ g_error("Invalid hog direction value: %d", vdir);
+ }
+
+ ret = gpiosim_bank_hog_line(self->bank, offset, name, dir);
+ if (ret) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to hog the simulated GPIO line: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean g_gpiosim_chip_apply_properties(GPIOSimChip *self)
+{
+ int ret;
+
+ ret = gpiosim_bank_set_num_lines(self->bank, self->num_lines);
+ if (ret) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to set the number of lines exposed by the simulated chip: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+
+ if (self->label) {
+ ret = gpiosim_bank_set_label(self->bank, self->label);
+ if (ret) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to set the label of the simulated chip: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+ }
+
+ ret = g_gpiosim_chip_apply_line_names(self);
+ if (!ret)
+ return FALSE;
+
+ return g_gpiosim_chip_apply_hogs(self);
+}
+
+static gboolean g_gpiosim_chip_enable(GPIOSimChip *self)
+{
+ struct gpiosim_dev *dev;
+ int ret;
+
+ dev = gpiosim_bank_get_dev(self->bank);
+ ret = gpiosim_dev_enable(dev);
+ gpiosim_dev_unref(dev);
+ if (ret) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_ENABLE_FAILED,
+ "Error while trying to enable the simulated GPIO device: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean g_gpiosim_ctx_init(GError **err)
+{
+ sim_ctx = gpiosim_ctx_new();
+ if (!sim_ctx) {
+ g_set_error(err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CTX_INIT_FAILED,
+ "Unable to initialize libgpiosim: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+
+ atexit(g_gpiosim_ctx_unref);
+
+ return TRUE;
+}
+
+static void g_gpiosim_chip_constructed(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+ struct gpiosim_dev *dev;
+ gboolean ret;
+
+ if (!sim_ctx) {
+ ret = g_gpiosim_ctx_init(&self->construct_err);
+ if (!ret)
+ return;
+ }
+
+ dev = gpiosim_dev_new(sim_ctx);
+ if (!dev) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to instantiate new GPIO device: %s",
+ g_strerror(errno));
+ return;
+ }
+
+ self->bank = gpiosim_bank_new(dev);
+ gpiosim_dev_unref(dev);
+ if (!self->bank) {
+ g_set_error(&self->construct_err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ "Unable to instantiate new GPIO bank: %s",
+ g_strerror(errno));
+ return;
+ }
+
+ ret = g_gpiosim_chip_apply_properties(self);
+ if (!ret)
+ return;
+
+ ret = g_gpiosim_chip_enable(self);
+ if (!ret)
+ return;
+
+ G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->constructed(obj);
+}
+
+static void g_gpiosim_chip_get_property(GObject *obj, guint prop_id,
+ GValue *val, GParamSpec *pspec)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+
+ switch (prop_id) {
+ case G_GPIOSIM_CHIP_PROP_DEV_PATH:
+ g_value_set_static_string(val,
+ gpiosim_bank_get_dev_path(self->bank));
+ break;
+ case G_GPIOSIM_CHIP_PROP_NAME:
+ g_value_set_static_string(val,
+ gpiosim_bank_get_chip_name(self->bank));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void set_variant_prop(GVariant **prop, const GValue *val)
+{
+ GVariant *variant = g_value_get_variant(val);
+
+ g_clear_pointer(prop, g_variant_unref);
+ if (variant)
+ *prop = g_variant_ref(variant);
+}
+
+static void g_gpiosim_chip_set_property(GObject *obj, guint prop_id,
+ const GValue *val, GParamSpec *pspec)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+ const gchar *label;
+
+ switch (prop_id) {
+ case G_GPIOSIM_CHIP_PROP_NUM_LINES:
+ self->num_lines = g_value_get_uint(val);
+ break;
+ case G_GPIOSIM_CHIP_PROP_LABEL:
+ g_clear_pointer(&self->label, g_free);
+ label = g_value_get_string(val);
+ if (label)
+ self->label = g_strdup(label);
+ break;
+ case G_GPIOSIM_CHIP_PROP_LINE_NAMES:
+ set_variant_prop(&self->line_names, val);
+ break;
+ case G_GPIOSIM_CHIP_PROP_HOGS:
+ set_variant_prop(&self->hogs, val);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void g_gpiosim_chip_dispose(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+
+ g_clear_pointer(&self->line_names, g_variant_unref);
+ g_clear_pointer(&self->hogs, g_variant_unref);
+
+ G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->dispose(obj);
+}
+
+static void g_gpiosim_disable_and_cleanup(struct gpiosim_bank *bank)
+{
+ struct gpiosim_dev *dev;
+ gint ret;
+
+ dev = gpiosim_bank_get_dev(bank);
+
+ if (gpiosim_dev_is_live(dev)) {
+ ret = gpiosim_dev_disable(dev);
+ if (ret)
+ g_warning("Error while trying to disable the simulated GPIO device: %s",
+ g_strerror(errno));
+ }
+
+ gpiosim_dev_unref(dev);
+ gpiosim_bank_unref(bank);
+}
+
+static void g_gpiosim_chip_finalize(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+
+ g_clear_error(&self->construct_err);
+ g_clear_pointer(&self->label, g_free);
+ g_clear_pointer(&self->bank, g_gpiosim_disable_and_cleanup);
+
+ G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->finalize(obj);
+}
+
+static void g_gpiosim_chip_class_init(GPIOSimChipClass *chip_class)
+{
+ GObjectClass *class = G_OBJECT_CLASS(chip_class);
+
+ class->constructed = g_gpiosim_chip_constructed;
+ class->get_property = g_gpiosim_chip_get_property;
+ class->set_property = g_gpiosim_chip_set_property;
+ class->dispose = g_gpiosim_chip_dispose;
+ class->finalize = g_gpiosim_chip_finalize;
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_DEV_PATH,
+ g_param_spec_string("dev-path", "Device path",
+ "Character device filesystem path.", NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_NAME,
+ g_param_spec_string(
+ "name", "Chip name",
+ "Name of this chip device as set by the kernel.", NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_NUM_LINES,
+ g_param_spec_uint("num-lines", "Number of lines",
+ "Number of lines this simulated chip exposes.",
+ 1, G_MAXUINT, 1,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_LABEL,
+ g_param_spec_string("label", "Chip label",
+ "Label of this simulated chip.", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_LINE_NAMES,
+ g_param_spec_variant(
+ "line-names", "Line names",
+ "List of names of the lines exposed by this chip",
+ (GVariantType *)"a(us)", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(
+ class, G_GPIOSIM_CHIP_PROP_HOGS,
+ g_param_spec_variant(
+ "hogs", "Line hogs",
+ "List of hogged lines and their directions.",
+ (GVariantType *)"a(usi)", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void g_gpiosim_chip_init(GPIOSimChip *self)
+{
+ self->construct_err = NULL;
+ self->num_lines = 1;
+ self->label = NULL;
+ self->line_names = NULL;
+ self->hogs = NULL;
+}
+
+static const gchar *
+g_gpiosim_chip_get_string_prop(GPIOSimChip *self, const gchar *prop)
+{
+ GValue val = G_VALUE_INIT;
+ const gchar *str;
+
+ g_object_get_property(G_OBJECT(self), prop, &val);
+ str = g_value_get_string(&val);
+ g_value_unset(&val);
+
+ return str;
+}
+
+const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self)
+{
+ return g_gpiosim_chip_get_string_prop(self, "dev-path");
+}
+
+const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self)
+{
+ return g_gpiosim_chip_get_string_prop(self, "name");
+}
+
+GPIOSimValue
+_g_gpiosim_chip_get_value(GPIOSimChip *chip, guint offset, GError **err)
+{
+ enum gpiosim_value val;
+
+ val = gpiosim_bank_get_value(chip->bank, offset);
+ switch (val) {
+ case GPIOSIM_VALUE_ERROR:
+ g_set_error(err, G_GPIOSIM_ERROR,
+ G_GPIOSIM_ERR_GET_VALUE_FAILED,
+ "Unable to read the line value: %s",
+ g_strerror(errno));
+ return G_GPIOSIM_VALUE_ERROR;
+ case GPIOSIM_VALUE_INACTIVE:
+ return G_GPIOSIM_VALUE_INACTIVE;
+ case GPIOSIM_VALUE_ACTIVE:
+ return G_GPIOSIM_VALUE_ACTIVE;
+ }
+
+ g_error("Invalid line value returned by gpiosim");
+}
+
+void g_gpiosim_chip_set_pull(GPIOSimChip *chip, guint offset, GPIOSimPull pull)
+{
+ enum gpiosim_pull sim_pull;
+ gint ret;
+
+ switch (pull) {
+ case G_GPIOSIM_PULL_DOWN:
+ sim_pull = GPIOSIM_PULL_DOWN;
+ break;
+ case G_GPIOSIM_PULL_UP:
+ sim_pull = GPIOSIM_PULL_UP;
+ break;
+ default:
+ g_error("invalid pull value");
+ }
+
+ ret = gpiosim_bank_set_pull(chip->bank, offset, sim_pull);
+ if (ret)
+ g_critical("Unable to set the pull setting for simulated line: %s",
+ g_strerror(errno));
+}
+
+GVariant *g_gpiosim_package_line_names(const GPIOSimLineName *names)
+{
+ g_autoptr(GVariantBuilder) builder = NULL;
+ const GPIOSimLineName *name;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
+
+ for (name = &names[0]; name->name; name++)
+ g_variant_builder_add(builder, "(us)",
+ name->offset, name->name);
+
+ return g_variant_ref_sink(g_variant_new("a(us)", builder));
+}
+
+GVariant *g_gpiosim_package_hogs(const GPIOSimHog *hogs)
+{
+ g_autoptr(GVariantBuilder) builder = NULL;
+ const GPIOSimHog *hog;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a(usi)"));
+
+ for (hog = &hogs[0]; hog->name; hog++)
+ g_variant_builder_add(builder, "(usi)",
+ hog->offset, hog->name, hog->direction);
+
+ return g_variant_ref_sink(g_variant_new("a(usi)", builder));
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#ifndef __GPIOD_TEST_SIM_H__
+#define __GPIOD_TEST_SIM_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ G_GPIOSIM_VALUE_ERROR = -1,
+ G_GPIOSIM_VALUE_INACTIVE = 0,
+ G_GPIOSIM_VALUE_ACTIVE = 1,
+} GPIOSimValue;
+
+typedef enum {
+ G_GPIOSIM_PULL_UP = 1,
+ G_GPIOSIM_PULL_DOWN,
+} GPIOSimPull;
+
+typedef enum {
+ G_GPIOSIM_DIRECTION_INPUT = 1,
+ G_GPIOSIM_DIRECTION_OUTPUT_HIGH,
+ G_GPIOSIM_DIRECTION_OUTPUT_LOW,
+} GPIOSimDirection;
+
+#define G_GPIOSIM_ERROR g_gpiosim_error_quark()
+
+typedef enum {
+ G_GPIOSIM_ERR_CTX_INIT_FAILED = 1,
+ G_GPIOSIM_ERR_CHIP_INIT_FAILED,
+ G_GPIOSIM_ERR_CHIP_ENABLE_FAILED,
+ G_GPIOSIM_ERR_GET_VALUE_FAILED,
+} GPIOSimError;
+
+GQuark g_gpiosim_error_quark(void);
+
+G_DECLARE_FINAL_TYPE(GPIOSimChip, g_gpiosim_chip, G_GPIOSIM, CHIP, GObject);
+
+#define G_GPIOSIM_CHIP_TYPE (g_gpiosim_chip_get_type())
+#define G_GPIOSIM_CHIP_OBJ(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), G_GPIOSIM_CHIP_TYPE, GPIOSimChip))
+
+#define g_gpiosim_chip_new(...) \
+ ({ \
+ g_autoptr(GError) _err = NULL; \
+ GPIOSimChip *_chip = G_GPIOSIM_CHIP_OBJ( \
+ g_initable_new(G_GPIOSIM_CHIP_TYPE, \
+ NULL, &_err, \
+ __VA_ARGS__)); \
+ g_assert_no_error(_err); \
+ if (g_test_failed()) \
+ return; \
+ _chip; \
+ })
+
+const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self);
+const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self);
+
+GPIOSimValue
+_g_gpiosim_chip_get_value(GPIOSimChip *self, guint offset, GError **err);
+void g_gpiosim_chip_set_pull(GPIOSimChip *self, guint offset, GPIOSimPull pull);
+
+#define g_gpiosim_chip_get_value(self, offset) \
+ ({ \
+ g_autoptr(GError) _err = NULL; \
+ gint _val = _g_gpiosim_chip_get_value(self, offset, &_err); \
+ g_assert_no_error(_err); \
+ if (g_test_failed()) \
+ return; \
+ _val; \
+ })
+
+typedef struct {
+ guint offset;
+ const gchar *name;
+} GPIOSimLineName;
+
+typedef struct {
+ guint offset;
+ const gchar *name;
+ GPIOSimDirection direction;
+} GPIOSimHog;
+
+GVariant *g_gpiosim_package_line_names(const GPIOSimLineName *names);
+GVariant *g_gpiosim_package_hogs(const GPIOSimHog *hogs);
+
+G_END_DECLS
+
+#endif /* __GPIOD_TEST_SIM_H__ */
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+noinst_LTLIBRARIES = libgpiod-test-harness.la
+libgpiod_test_harness_la_SOURCES = \
+ gpiod-test.c \
+ gpiod-test.h \
+ gpiod-test-common.h
+
+AM_CFLAGS = -include $(top_builddir)/config.h
+AM_CFLAGS += -Wall -Wextra -g -std=gnu89 $(GLIB_CFLAGS)
+AM_CFLAGS += -DG_LOG_DOMAIN=\"gpiod-test\"
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#ifndef __GPIOD_TEST_COMMON_H__
+#define __GPIOD_TEST_COMMON_H__
+
+#include <glib.h>
+
+#define gpiod_test_return_if_failed() \
+ do { \
+ if (g_test_failed()) \
+ return; \
+ } while (0)
+
+#define gpiod_test_join_thread_and_return_if_failed(_thread) \
+ do { \
+ if (g_test_failed()) { \
+ g_thread_join(_thread); \
+ return; \
+ } \
+ } while (0)
+
+#endif /* __GPIOD_TEST_COMMON_H__ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+#include <errno.h>
+#include <linux/version.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "gpiod-test.h"
+
+#define MIN_KERNEL_MAJOR 5
+#define MIN_KERNEL_MINOR 19
+#define MIN_KERNEL_RELEASE 0
+#define MIN_KERNEL_VERSION KERNEL_VERSION(MIN_KERNEL_MAJOR, \
+ MIN_KERNEL_MINOR, \
+ MIN_KERNEL_RELEASE)
+
+static GList *tests;
+
+static gboolean check_kernel(void)
+{
+ guint major, minor, release;
+ struct utsname un;
+ gint ret;
+
+ g_debug("checking linux kernel version");
+
+ ret = uname(&un);
+ if (ret) {
+ g_critical("unable to read the kernel release version: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+
+ ret = sscanf(un.release, "%u.%u.%u", &major, &minor, &release);
+ if (ret != 3) {
+ g_critical("error reading kernel release version");
+ return FALSE;
+ }
+
+ if (KERNEL_VERSION(major, minor, release) < MIN_KERNEL_VERSION) {
+ g_critical("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);
+ return FALSE;
+ }
+
+ g_debug("kernel release is v%u.%u.%u - ok to run tests",
+ major, minor, release);
+
+ return TRUE;
+}
+
+static void test_func_wrapper(gconstpointer data)
+{
+ const struct _gpiod_test_case *test = data;
+
+ test->func();
+}
+
+static void add_test_from_list(gpointer element, gpointer data G_GNUC_UNUSED)
+{
+ struct _gpiod_test_case *test = element;
+
+ g_test_add_data_func(test->path, test, test_func_wrapper);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_set_nonfatal_assertions();
+
+ g_debug("running libgpiod test suite");
+ g_debug("%u tests registered", g_list_length(tests));
+
+ if (!check_kernel())
+ return EXIT_FAILURE;
+
+ g_list_foreach(tests, add_test_from_list, NULL);
+ g_list_free(tests);
+
+ return g_test_run();
+}
+
+void _gpiod_test_register(struct _gpiod_test_case *test)
+{
+ tests = g_list_append(tests, test);
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/*
+ * 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>
+
+/* These are private definitions and should not be used directly. */
+
+struct _gpiod_test_case {
+ const gchar *path;
+ void (*func)(void);
+};
+
+void _gpiod_test_register(struct _gpiod_test_case *test);
+
+#define _GPIOD_TEST_PATH(_name) \
+ "/gpiod/" GPIOD_TEST_GROUP "/" G_STRINGIFY(_name)
+
+/*
+ * Register a test case function.
+ */
+#define GPIOD_TEST_CASE(_name) \
+ static void _gpiod_test_func_##_name(void); \
+ static struct _gpiod_test_case _##_name##_test_case = { \
+ .path = _GPIOD_TEST_PATH(_name), \
+ .func = _gpiod_test_func_##_name, \
+ }; \
+ static __attribute__((constructor)) void \
+ _##_name##_test_register(void) \
+ { \
+ _gpiod_test_register(&_##_name##_test_case); \
+ } \
+ static void _gpiod_test_func_##_name(void)
+
+#endif /* __GPIOD_TEST_H__ */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> */
+
+#ifndef __GPIOD_TEST_HELPERS_H__
+#define __GPIOD_TEST_HELPERS_H__
+
+#include <glib.h>
+#include <gpiod.h>
+#include <gpiod-test-common.h>
+
+/*
+ * These typedefs are needed to make g_autoptr work - it doesn't accept
+ * regular 'struct typename' syntax.
+ */
+
+typedef struct gpiod_chip struct_gpiod_chip;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_chip, gpiod_chip_close);
+
+typedef struct gpiod_chip_info struct_gpiod_chip_info;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_chip_info, gpiod_chip_info_free);
+
+typedef struct gpiod_line_info struct_gpiod_line_info;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_info, gpiod_line_info_free);
+
+typedef struct gpiod_info_event struct_gpiod_info_event;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_info_event, gpiod_info_event_free);
+
+typedef struct gpiod_line_config struct_gpiod_line_config;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_config, gpiod_line_config_free);
+
+typedef struct gpiod_line_settings struct_gpiod_line_settings;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_settings,
+ gpiod_line_settings_free);
+
+typedef struct gpiod_request_config struct_gpiod_request_config;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_request_config,
+ gpiod_request_config_free);
+
+typedef struct gpiod_line_request struct_gpiod_line_request;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_request,
+ gpiod_line_request_release);
+
+typedef struct gpiod_edge_event struct_gpiod_edge_event;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event, gpiod_edge_event_free);
+
+typedef struct gpiod_edge_event_buffer struct_gpiod_edge_event_buffer;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event_buffer,
+ gpiod_edge_event_buffer_free);
+
+#define gpiod_test_open_chip_or_fail(_path) \
+ ({ \
+ struct gpiod_chip *_chip = gpiod_chip_open(_path); \
+ g_assert_nonnull(_chip); \
+ gpiod_test_return_if_failed(); \
+ _chip; \
+ })
+
+#define gpiod_test_chip_get_info_or_fail(_chip) \
+ ({ \
+ struct gpiod_chip_info *_info = gpiod_chip_get_info(_chip); \
+ g_assert_nonnull(_info); \
+ gpiod_test_return_if_failed(); \
+ _info; \
+ })
+
+#define gpiod_test_chip_get_line_info_or_fail(_chip, _offset) \
+ ({ \
+ struct gpiod_line_info *_info = \
+ gpiod_chip_get_line_info(_chip, _offset); \
+ g_assert_nonnull(_info); \
+ gpiod_test_return_if_failed(); \
+ _info; \
+ })
+
+#define gpiod_test_chip_watch_line_info_or_fail(_chip, _offset) \
+ ({ \
+ struct gpiod_line_info *_info = \
+ gpiod_chip_watch_line_info(_chip, _offset); \
+ g_assert_nonnull(_info); \
+ gpiod_test_return_if_failed(); \
+ _info; \
+ })
+
+#define gpiod_test_create_line_settings_or_fail() \
+ ({ \
+ struct gpiod_line_settings *_settings = \
+ gpiod_line_settings_new(); \
+ g_assert_nonnull(_settings); \
+ gpiod_test_return_if_failed(); \
+ _settings; \
+ })
+
+#define gpiod_test_create_line_config_or_fail() \
+ ({ \
+ struct gpiod_line_config *_config = \
+ gpiod_line_config_new(); \
+ g_assert_nonnull(_config); \
+ gpiod_test_return_if_failed(); \
+ _config; \
+ })
+
+#define gpiod_test_create_edge_event_buffer_or_fail(_capacity) \
+ ({ \
+ struct gpiod_edge_event_buffer *_buffer = \
+ gpiod_edge_event_buffer_new(_capacity); \
+ g_assert_nonnull(_buffer); \
+ gpiod_test_return_if_failed(); \
+ _buffer; \
+ })
+
+#define gpiod_test_line_config_add_line_settings_or_fail(_line_cfg, _offsets, \
+ _num_offsets, \
+ _settings) \
+ do { \
+ gint _ret = gpiod_line_config_add_line_settings(_line_cfg, \
+ _offsets, \
+ _num_offsets, \
+ _settings); \
+ g_assert_cmpint(_ret, ==, 0); \
+ gpiod_test_return_if_failed(); \
+ } while (0)
+
+#define gpiod_test_line_config_get_line_settings_or_fail(_line_cfg, _offset) \
+ ({ \
+ struct gpiod_line_settings *_settings = \
+ gpiod_line_config_get_line_settings(_line_cfg, \
+ _offset); \
+ g_assert_nonnull(_settings); \
+ gpiod_test_return_if_failed(); \
+ _settings; \
+ })
+
+#define gpiod_test_line_config_set_output_values_or_fail(_line_cfg, _values, \
+ _num_values) \
+ do { \
+ gint _ret = gpiod_line_config_set_output_values(_line_cfg, \
+ _values, \
+ _num_values); \
+ g_assert_cmpint(_ret, ==, 0); \
+ gpiod_test_return_if_failed(); \
+ } while (0)
+
+#define gpiod_test_create_request_config_or_fail() \
+ ({ \
+ struct gpiod_request_config *_config = \
+ gpiod_request_config_new(); \
+ g_assert_nonnull(_config); \
+ gpiod_test_return_if_failed(); \
+ _config; \
+ })
+
+#define gpiod_test_chip_request_lines_or_fail(_chip, _req_cfg, _line_cfg) \
+ ({ \
+ struct gpiod_line_request *_request = \
+ gpiod_chip_request_lines(_chip, \
+ _req_cfg, _line_cfg); \
+ g_assert_nonnull(_request); \
+ gpiod_test_return_if_failed(); \
+ _request; \
+ })
+
+#define gpiod_test_line_request_reconfigure_lines_or_fail(_request, _line_cfg) \
+ do { \
+ gint _ret = gpiod_line_request_reconfigure_lines(_request, \
+ _line_cfg); \
+ g_assert_cmpint(_ret, ==, 0); \
+ gpiod_test_return_if_failed(); \
+ } while (0)
+
+#define gpiod_test_expect_errno(_expected) \
+ g_assert_cmpint((_expected), ==, errno)
+
+#endif /* __GPIOD_TEST_HELPERS_H__ */
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "chip-info"
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "chip"
g_autoptr(GPIOSimChip) sim = NULL;
g_autoptr(struct_gpiod_chip) chip = NULL;
- g_autoptr(GVariant) vnames = gpiod_test_package_line_names(names);
+ g_autoptr(GVariant) vnames = g_gpiosim_package_line_names(names);
sim = g_gpiosim_chip_new(
"num-lines", 8,
g_autoptr(GPIOSimChip) sim = NULL;
g_autoptr(struct_gpiod_chip) chip = NULL;
- g_autoptr(GVariant) vnames = gpiod_test_package_line_names(names);
+ g_autoptr(GVariant) vnames = g_gpiosim_package_line_names(names);
sim = g_gpiosim_chip_new(
"num-lines", 8,
g_autoptr(GPIOSimChip) sim = NULL;
g_autoptr(struct_gpiod_chip) chip = NULL;
- g_autoptr(GVariant) vnames = gpiod_test_package_line_names(names);
+ g_autoptr(GVariant) vnames = g_gpiosim_package_line_names(names);
sim = g_gpiosim_chip_new(
"num-lines", 8,
{ }
};
- g_autoptr(GVariant) vnames = gpiod_test_package_line_names(names);
+ g_autoptr(GVariant) vnames = g_gpiosim_package_line_names(names);
g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8,
"line-names", vnames,
NULL);
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
#include <poll.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "edge-event"
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
#include <poll.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "info-event"
#include <glib.h>
#include <gpiod.h>
#include <poll.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "kernel-uapi"
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "line-config"
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "line-info"
g_autoptr(struct_gpiod_chip) chip = NULL;
g_autoptr(struct_gpiod_line_info) info4 = NULL;
g_autoptr(struct_gpiod_line_info) info6 = NULL;
- g_autoptr(GVariant) vnames = gpiod_test_package_line_names(names);
- g_autoptr(GVariant) vhogs = gpiod_test_package_hogs(hogs);
+ g_autoptr(GVariant) vnames = g_gpiosim_package_line_names(names);
+ g_autoptr(GVariant) vhogs = g_gpiosim_package_hogs(hogs);
sim = g_gpiosim_chip_new(
"num-lines", 8,
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "line-request"
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "line-settings"
#include <errno.h>
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
+#include <gpiosim-glib.h>
#include <unistd.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
-#include "gpiod-test-sim.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "misc"
#include <glib.h>
#include <gpiod.h>
+#include <gpiod-test.h>
+#include <gpiod-test-common.h>
-#include "gpiod-test.h"
-#include "gpiod-test-helpers.h"
+#include "helpers.h"
#define GPIOD_TEST_GROUP "request-config"