summaryrefslogtreecommitdiff
path: root/gusb/gusb-umockdev-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'gusb/gusb-umockdev-test.c')
-rw-r--r--gusb/gusb-umockdev-test.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/gusb/gusb-umockdev-test.c b/gusb/gusb-umockdev-test.c
new file mode 100644
index 0000000..23ee491
--- /dev/null
+++ b/gusb/gusb-umockdev-test.c
@@ -0,0 +1,211 @@
+/*
+ * libusb umockdev based tests
+ *
+ * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gusb.h"
+
+#include "umockdev.h"
+
+#define UNUSED_DATA __attribute__ ((unused)) gconstpointer unused_data
+
+/* avoid leak reports inside assertions; leaking stuff on assertion failures does not matter in tests */
+#if !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
+#pragma GCC diagnostic ignored "-Wanalyzer-file-leak"
+#endif
+
+typedef struct {
+ UMockdevTestbed *testbed;
+ GUsbContext *ctx;
+} UMockdevTestbedFixture;
+
+static void
+test_fixture_setup (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ fixture->testbed = umockdev_testbed_new ();
+ g_assert (fixture->testbed != NULL);
+}
+
+static void
+test_fixture_setup_empty (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ test_fixture_setup (fixture, NULL);
+ fixture->ctx = g_usb_context_new (NULL);
+}
+
+static void
+test_fixture_teardown (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ /* Break context -> device -> context cycle */
+ if (fixture->ctx)
+ g_object_run_dispose (G_OBJECT (fixture->ctx));
+ g_clear_object (&fixture->ctx);
+ g_clear_object (&fixture->testbed);
+
+ /* Running the mainloop is needed to ensure everything is cleaned up. */
+ while (g_main_context_iteration (NULL, FALSE)) { }
+}
+
+static void
+test_fixture_add_canon (UMockdevTestbedFixture *fixture)
+{
+ /* NOTE: There is no device file, so cannot be opened */
+
+ /* NOTE: add_device would not create a file, needed for device emulation */
+ /* XXX: Racy, see https://github.com/martinpitt/umockdev/issues/173 */
+ umockdev_testbed_add_from_string (fixture->testbed,
+ "P: /devices/usb1\n"
+ "N: bus/usb/001/001\n"
+ "E: SUBSYSTEM=usb\n"
+ "E: DRIVER=usb\n"
+ "E: BUSNUM=001\n"
+ "E: DEVNUM=001\n"
+ "E: DEVNAME=/dev/bus/usb/001/001\n"
+ "E: DEVTYPE=usb_device\n"
+ "A: bConfigurationValue=1\\n\n"
+ "A: busnum=1\\n\n"
+ "A: devnum=1\\n\n"
+ "A: bConfigurationValue=1\\n\n"
+ "A: speed=480\\n\n"
+ /* descriptor from a Canon PowerShot SX200; VID 04a9 PID 31c0 */
+ "H: descriptors="
+ "1201000200000040a904c03102000102"
+ "030109022700010100c0010904000003"
+ "06010100070581020002000705020200"
+ "020007058303080009\n",
+ NULL);
+}
+
+static void
+test_ctx_enumerate (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ g_autoptr(GPtrArray) devices = NULL;
+
+ test_fixture_add_canon (fixture);
+
+ g_usb_context_enumerate (fixture->ctx);
+
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (devices->len, ==, 1);
+}
+
+static void
+count_hotplug_event_cb (GUsbContext *context, GUsbDevice *device, gpointer user_data)
+{
+ int *counter = user_data;
+
+ *counter += 1;
+}
+
+static void
+test_ctx_hotplug (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ g_autoptr(GPtrArray) devices = NULL;
+ gint events = 0;
+
+ g_signal_connect (fixture->ctx, "device-added", G_CALLBACK (count_hotplug_event_cb), &events);
+
+ g_usb_context_enumerate (fixture->ctx);
+
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (devices->len, ==, 0);
+ g_assert_cmpint (events, ==, 0);
+ g_clear_pointer (&devices, g_ptr_array_unref);
+
+ test_fixture_add_canon (fixture);
+ /* Ensure the event was processed by helper thread. */
+ g_usleep (G_USEC_PER_SEC / 2);
+
+ /* Still not returned (and no event fired). */
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (devices->len, ==, 0);
+ g_assert_cmpint (events, ==, 0);
+ g_clear_pointer (&devices, g_ptr_array_unref);
+
+ /* Run mainloop, which causes the event to be processed. */
+ while (g_main_context_iteration (NULL, FALSE)) { }
+
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (events, ==, 1);
+ g_assert_cmpint (devices->len, ==, 1);
+ g_clear_pointer (&devices, g_ptr_array_unref);
+}
+
+static void
+test_ctx_hotplug_dispose (UMockdevTestbedFixture *fixture, UNUSED_DATA)
+{
+ g_autoptr(GPtrArray) devices = NULL;
+ gint events = 0;
+
+ g_signal_connect (fixture->ctx, "device-added", G_CALLBACK (count_hotplug_event_cb), &events);
+
+ g_usb_context_enumerate (fixture->ctx);
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (devices->len, ==, 0);
+ g_assert_cmpint (events, ==, 0);
+ g_clear_pointer (&devices, g_ptr_array_unref);
+
+ test_fixture_add_canon (fixture);
+ /* Ensure the event was processed by helper thread. */
+ g_usleep (G_USEC_PER_SEC / 2);
+
+ /* Still not returned (and no event fired). */
+ g_usb_context_enumerate (fixture->ctx);
+ devices = g_usb_context_get_devices (fixture->ctx);
+ g_assert_cmpint (devices->len, ==, 0);
+ g_assert_cmpint (events, ==, 0);
+ g_clear_pointer (&devices, g_ptr_array_unref);
+
+ /* The idle handler is pending, we dispose our context reference */
+ g_object_run_dispose (G_OBJECT (fixture->ctx));
+
+ /* Run mainloop, which causes the event to be processed. */
+ while (g_main_context_iteration (NULL, FALSE)) { }
+
+ /* But no signal is fired. */
+ g_assert_cmpint (events, ==, 0);
+
+ g_clear_object (&fixture->ctx);
+}
+
+int
+main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add("/gusb/ctx/enumerate", UMockdevTestbedFixture, NULL,
+ test_fixture_setup_empty,
+ test_ctx_enumerate,
+ test_fixture_teardown);
+
+ g_test_add("/gusb/ctx/hotplug", UMockdevTestbedFixture, NULL,
+ test_fixture_setup_empty,
+ test_ctx_hotplug,
+ test_fixture_teardown);
+
+ g_test_add("/gusb/ctx/hotplug-dispose", UMockdevTestbedFixture, NULL,
+ test_fixture_setup_empty,
+ test_ctx_hotplug_dispose,
+ test_fixture_teardown);
+
+ return g_test_run();
+}