From b79fcf9418299811d6a93b91f6498c47cbdae827 Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Thu, 2 Apr 2020 14:19:32 -0400 Subject: [PATCH] lib: add spa type API --- lib/wp/meson.build | 2 + lib/wp/private.h | 7 +- lib/wp/spa-type.c | 335 +++++++++++++++++++++++++++++++++++++++++++ lib/wp/spa-type.h | 64 +++++++++ lib/wp/wp.h | 1 + tests/wp/meson.build | 6 + tests/wp/spa-type.c | 163 +++++++++++++++++++++ 7 files changed, 572 insertions(+), 6 deletions(-) create mode 100644 lib/wp/spa-type.c create mode 100644 lib/wp/spa-type.h create mode 100644 tests/wp/spa-type.c diff --git a/lib/wp/meson.build b/lib/wp/meson.build index e0eafb6a..1cc8685c 100644 --- a/lib/wp/meson.build +++ b/lib/wp/meson.build @@ -17,6 +17,7 @@ wp_lib_sources = files( 'properties.c', 'proxy.c', 'session.c', + 'spa-type.c', 'spa-props.c', ) @@ -40,6 +41,7 @@ wp_lib_headers = files( 'properties.h', 'proxy.h', 'session.h', + 'spa-type.h', 'wp.h', ) diff --git a/lib/wp/private.h b/lib/wp/private.h index 15684835..14a9bde4 100644 --- a/lib/wp/private.h +++ b/lib/wp/private.h @@ -12,6 +12,7 @@ #include "core.h" #include "object-manager.h" #include "proxy.h" +#include "iterator.h" #include #include @@ -116,12 +117,6 @@ void wp_proxy_handle_event_param (void * proxy, int seq, uint32_t id, /* iterator */ -typedef struct _WpIterator WpIterator; - -typedef gboolean (*WpIteratorFoldFunc) (const GValue *item, GValue *ret, - gpointer data); -typedef void (*WpIteratorForeachFunc) (const GValue *item, gpointer data); - struct _WpIteratorMethods { void (*reset) (WpIterator *self); gboolean (*next) (WpIterator *self, GValue *item); diff --git a/lib/wp/spa-type.c b/lib/wp/spa-type.c new file mode 100644 index 00000000..cb1e98c0 --- /dev/null +++ b/lib/wp/spa-type.c @@ -0,0 +1,335 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include "spa-type.h" + +static gboolean +name_equal_func (gconstpointer a, gconstpointer b) { + const struct spa_type_info *ti = a; + const char *name = b; + return g_strcmp0 (ti->name, name) == 0; +} + +static const struct spa_type_info * +spa_type_find (const struct spa_type_info *table, GEqualFunc func, + gconstpointer data) +{ + for (guint32 i = 0; table[i].name; i++) + if (func (table + i, data)) + return table + i; + return NULL; +} + +static const struct spa_type_info * +spa_type_find_by_name (const struct spa_type_info *table, const char *name) +{ + return spa_type_find (table, name_equal_func, name); +} + +struct type_info { + gboolean is_spa_type; + union { + const struct spa_type_info *spa; + struct { + guint32 type; + char *name; + } custom; + } info; + char *nick; +}; + +static struct type_info * +type_info_new_spa (const struct spa_type_info *info, const char* nick) { + struct type_info *ti = g_slice_new0 (struct type_info); + ti->is_spa_type = TRUE; + ti->info.spa = info; + ti->nick = g_strdup (nick); + return ti; +} + +static struct type_info * +type_info_new_custom (uint32_t type, const char *name, const char* nick) { + struct type_info *ti = g_slice_new0 (struct type_info); + ti->is_spa_type = FALSE; + ti->info.custom.type = type; + ti->info.custom.name = g_strdup (name); + ti->nick = g_strdup (nick); + return ti; +} + +static void +type_info_free (struct type_info *ti) { + g_return_if_fail (ti); + if (!ti->is_spa_type) + g_clear_pointer (&ti->info.custom.name, g_free); + g_clear_pointer (&ti->nick, g_free); + g_slice_free (struct type_info, ti); +} + +struct spa_type_table_data { + const struct spa_type_info *spa_table; + guint32 last_id; + GPtrArray *info_array; + GHashTable *id_table; + GHashTable *nick_table; +}; + +static struct spa_type_table_data s_tables [WP_SPA_TYPE_TABLE_LAST] = { + [WP_SPA_TYPE_TABLE_BASIC] = {spa_types, SPA_TYPE_VENDOR_Other, NULL, NULL, NULL }, + [WP_SPA_TYPE_TABLE_PARAM] = {spa_type_param, SPA_N_ELEMENTS (spa_type_param), NULL, NULL, NULL, }, + [WP_SPA_TYPE_TABLE_PROPS] = {spa_type_props, SPA_PROP_START_CUSTOM, NULL, NULL, NULL, }, + [WP_SPA_TYPE_TABLE_PROP_INFO] = {spa_type_prop_info, SPA_N_ELEMENTS (spa_type_prop_info), NULL, NULL, NULL, }, + [WP_SPA_TYPE_TABLE_CONTROL] = {spa_type_control, SPA_CONTROL_LAST, NULL, NULL, NULL, }, + [WP_SPA_TYPE_TABLE_CHOICE] = {spa_type_choice, SPA_N_ELEMENTS (spa_type_choice), NULL, NULL, NULL, }, +}; + +static WpSpaTypeTable +wp_spa_type_table_find_by_spa_table (const struct spa_type_info *spa_table) +{ + for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) + if (s_tables[i].spa_table == spa_table) + return i; + return 0; +} + +/** + * wp_spa_type_init: + * @register_spa: whether spa types will be registered or not + * + * Initializes the spa type registry + */ +void +wp_spa_type_init (gboolean register_spa) +{ + /* Init the array and hash tables */ + for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { + struct spa_type_table_data *td = s_tables + i; + if (!td->info_array) + td->info_array = g_ptr_array_new_with_free_func ((GDestroyNotify) + type_info_free); + if (!td->id_table) + td->id_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, NULL); + if (!td->nick_table) + td->nick_table = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + } + + /* Register the spa types if requested */ + if (register_spa) { + for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { + struct spa_type_table_data *td = s_tables + i; + for (guint32 j = 0; td->spa_table && td->spa_table[j].name; j++) { + const struct spa_type_info *t = td->spa_table + j; + const char *nick = strrchr (t->name, ':'); + if (nick && strlen (nick) > 1) + wp_spa_type_register (i, t->name, nick + 1); + } + } + } +} + +/** + * wp_spa_type_deinit: + * + * Deinitializes the spa type registry + */ +void +wp_spa_type_deinit (void) +{ + for (guint32 i = 0; i < WP_SPA_TYPE_TABLE_LAST; i++) { + struct spa_type_table_data *td = s_tables + i; + g_clear_pointer (&td->info_array, g_ptr_array_unref); + g_clear_pointer (&td->id_table, g_hash_table_unref); + g_clear_pointer (&td->nick_table, g_hash_table_unref); + } +} + +/** + * wp_spa_type_get_table_size: + * @table: the table + * + * Gets the number of registered types in a given table + * + * Returns: The number of registered types + */ +size_t +wp_spa_type_get_table_size (WpSpaTypeTable table) +{ + struct spa_type_table_data *td = NULL; + + g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, 0); + + /* Get the table data */ + td = s_tables + table; + + return td->info_array->len; +} + +/** + * wp_spa_type_register: + * @table: the table + * @name: the name of the type + * @nick: the nick name of the type + * + * Registers a type name with a nickname in the registry + * + * Returns: TRUE if the type could be registered, FALSE otherwise + */ +gboolean +wp_spa_type_register (WpSpaTypeTable table, const char *name, const char *nick) +{ + struct spa_type_table_data *td = NULL; + const struct spa_type_info *spa_info = NULL; + struct type_info *info = NULL; + guint32 id; + + g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (nick, FALSE); + + /* Get the table data */ + td = s_tables + table; + + /* Return false if the nick already exists in the nick table */ + if (g_hash_table_contains (td->nick_table, nick)) + return FALSE; + + /* Add the type in the custom table */ + spa_info = spa_type_find_by_name (td->spa_table, name); + if (spa_info) { + id = spa_info->type; + info = type_info_new_spa (spa_info, nick); + } else { + id = ++td->last_id; + info = type_info_new_custom (id, name, nick); + } + g_ptr_array_add (td->info_array, info); + + /* Insert the id and nick in the hash tables */ + return g_hash_table_insert (td->id_table, GUINT_TO_POINTER (id), info) && + g_hash_table_insert (td->nick_table, g_strdup (nick), info); +} + +/** + * wp_spa_type_unregister: + * @table: the table + * @nick: the nick name of the type + * + * Unregisters a type given its nick name + */ +void +wp_spa_type_unregister (WpSpaTypeTable table, const char *nick) +{ + struct spa_type_table_data *td = NULL; + struct type_info *info = NULL; + guint32 id; + + g_return_if_fail (table < WP_SPA_TYPE_TABLE_LAST); + g_return_if_fail (nick); + + /* Get the table data */ + td = s_tables + table; + + /* Lookup the info by nick */ + info = g_hash_table_lookup (td->nick_table, nick); + if (!info) + return; + + /* Get id */ + id = info->is_spa_type ? info->info.spa->type : info->info.custom.type; + + /* Remove info from hash tables */ + g_hash_table_remove (td->nick_table, nick); + g_hash_table_remove (td->id_table, GUINT_TO_POINTER (id)); + + /* Remove info from array */ + g_ptr_array_remove_fast (td->info_array, info); +} + +/** + * wp_spa_type_get_by_nick: + * @table: the table + * @nick: the nick name of the type + * @id: (out) (optional): the id of the type + * @name: (out) (optional): the name of the type + * @values_table: (out) (optional): the values table of the type + * + * Gets the id and name of the registered type given its nick name + * + * Returns: TRUE if the type was found, FALSE otherwise + */ +gboolean +wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick, + guint32 *id, const char **name, WpSpaTypeTable *values_table) +{ + struct spa_type_table_data *td = NULL; + const struct type_info *info = NULL; + + g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); + + /* Make sure nick is valid */ + if (!nick) + return FALSE; + + /* Get the table data */ + td = s_tables + table; + + /* Lookup the info by nick */ + info = g_hash_table_lookup (td->nick_table, nick); + if (!info) + return FALSE; + + if (id) + *id = info->is_spa_type ? info->info.spa->type : info->info.custom.type; + if (name) + *name = info->is_spa_type ? info->info.spa->name : info->info.custom.name; + if (values_table && info->is_spa_type) + *values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values); + return TRUE; +} + +/** + * wp_spa_type_get_by_id: + * @table: the table + * @id: the id of the type + * @name: (out) (optional): the name of the type + * @nick: (out) (optional): the nick name of the type + * @values_table: (out) (optional): the values table of the type + * + * Gets the name and nick name of the registered type given its id + * + * Returns: TRUE if the type was found, FALSE otherwise + */ +gboolean +wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id, + const char **name, const char **nick, WpSpaTypeTable *values_table) +{ + struct spa_type_table_data *td = NULL; + const struct type_info *info = NULL; + + g_return_val_if_fail (table < WP_SPA_TYPE_TABLE_LAST, FALSE); + + /* Get the table data */ + td = s_tables + table; + + /* Lookup the info by id */ + info = g_hash_table_lookup (td->id_table, GUINT_TO_POINTER (id)); + if (!info) + return FALSE; + + if (name) + *name = info->is_spa_type ? info->info.spa->name : info->info.custom.name; + if (nick) + *nick = info->nick; + if (values_table && info->is_spa_type) + *values_table = wp_spa_type_table_find_by_spa_table (info->info.spa->values); + return TRUE; +} diff --git a/lib/wp/spa-type.h b/lib/wp/spa-type.h new file mode 100644 index 00000000..eee08007 --- /dev/null +++ b/lib/wp/spa-type.h @@ -0,0 +1,64 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WIREPLUMBER_SPA_TYPE_H__ +#define __WIREPLUMBER_SPA_TYPE_H__ + +#include +#include "defs.h" + +G_BEGIN_DECLS + +/** + * WpSpaTypeTable: + * + * The diferent tables (namespaces) the registry has. + * WP_SPA_TYPE_TABLE_BASIC (0) - The basic type table + * WP_SPA_TYPE_TABLE_PARAM (1) – The param type table (used as object id) + * WP_SPA_TYPE_TABLE_PROPS (2) – The object properties type table + * WP_SPA_TYPE_TABLE_PROP_INFO (3) – The object property info type table + * WP_SPA_TYPE_TABLE_CONTROL (4) - The sequence control type table + * WP_SPA_TYPE_TABLE_CHOICE (5) - The choice type table + */ +typedef enum { + WP_SPA_TYPE_TABLE_BASIC = 0, + WP_SPA_TYPE_TABLE_PARAM, + WP_SPA_TYPE_TABLE_PROPS, + WP_SPA_TYPE_TABLE_PROP_INFO, + WP_SPA_TYPE_TABLE_CONTROL, + WP_SPA_TYPE_TABLE_CHOICE, + WP_SPA_TYPE_TABLE_LAST, +} WpSpaTypeTable; + +WP_API +void wp_spa_type_init (gboolean register_spa); + +WP_API +void wp_spa_type_deinit (void); + +WP_API +size_t wp_spa_type_get_table_size (WpSpaTypeTable table); + +WP_API +gboolean wp_spa_type_register (WpSpaTypeTable table, const char *name, + const char *nick); + +WP_API +void wp_spa_type_unregister (WpSpaTypeTable table, const char *nick); + +WP_API +gboolean wp_spa_type_get_by_nick (WpSpaTypeTable table, const char *nick, + guint32 *id, const char **name, WpSpaTypeTable *values_table); + +WP_API +gboolean wp_spa_type_get_by_id (WpSpaTypeTable table, guint32 id, + const char **name, const char **nick, WpSpaTypeTable *values_table); + +G_END_DECLS + +#endif diff --git a/lib/wp/wp.h b/lib/wp/wp.h index 3c3b200e..3d2f345a 100644 --- a/lib/wp/wp.h +++ b/lib/wp/wp.h @@ -24,4 +24,5 @@ #include "properties.h" #include "proxy.h" #include "session.h" +#include "spa-type.h" #include "wpenums.h" diff --git a/tests/wp/meson.build b/tests/wp/meson.build index 8fdb52b0..917a35e7 100644 --- a/tests/wp/meson.build +++ b/tests/wp/meson.build @@ -33,3 +33,9 @@ test( executable('test-spa-props', 'spa-props.c', dependencies: common_deps), env: common_env, ) + +test( + 'test-spa-type', + executable('test-spa-type', 'spa-type.c', dependencies: common_deps), + env: common_env, +) diff --git a/tests/wp/spa-type.c b/tests/wp/spa-type.c new file mode 100644 index 00000000..e709c1e6 --- /dev/null +++ b/tests/wp/spa-type.c @@ -0,0 +1,163 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author Julian Bouzas + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +static void +test_spa_type_basic (void) +{ + wp_spa_type_init (TRUE); + + /* Make sure table sizes are not 0 */ + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), >, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), >, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), >, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROP_INFO), >, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), >, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), >, 0); + + /* Make sure SPA_TYPE_OBJECT_Props type from WP_SPA_TYPE_TABLE_BASIC is registered */ + { + const char *name = NULL; + const char *nick = NULL; + WpSpaTypeTable table = WP_SPA_TYPE_TABLE_BASIC; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, SPA_TYPE_OBJECT_Props, + &name, &nick, &table)); + g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props"); + g_assert_cmpstr (nick, ==, "Props"); + g_assert_cmpuint (table, ==, WP_SPA_TYPE_TABLE_PROPS); + } + + /* Make sure SPA_PARAM_Props type from WP_SPA_TYPE_TABLE_PARAM is registered */ + { + const char *name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PARAM, SPA_PARAM_Props, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Enum:ParamId:Props"); + g_assert_cmpstr (nick, ==, "Props"); + } + + /* Make sure SPA_PROP_mute type from WP_SPA_TYPE_TABLE_PROPS is registered */ + { + const char *name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROPS, SPA_PROP_mute, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:Props:mute"); + g_assert_cmpstr (nick, ==, "mute"); + } + + /* Make sure SPA_PROP_INFO_id type from WP_SPA_TYPE_TABLE_PROP_INFO is registered */ + { + const char *name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_PROP_INFO, SPA_PROP_INFO_id, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Pod:Object:Param:PropInfo:id"); + g_assert_cmpstr (nick, ==, "id"); + } + + /* Make sure SPA_CONTROL_Properties type from WP_SPA_TYPE_TABLE_CONTROL is registered */ + { + const char *name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CONTROL, SPA_CONTROL_Properties, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Enum:Control:Properties"); + g_assert_cmpstr (nick, ==, "Properties"); + } + + /* Make sure SPA_CHOICE_Enum type from WP_SPA_TYPE_TABLE_CHOICE is registered */ + { + const char *name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_CHOICE, SPA_CHOICE_Enum, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Enum:Choice:Enum"); + g_assert_cmpstr (nick, ==, "Enum"); + } + + wp_spa_type_deinit (); +} + +static void +test_spa_type_register (void) +{ + wp_spa_type_init (FALSE); + + /* Make sure no types are registered */ + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PARAM), ==, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_PROPS), ==, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CONTROL), ==, 0); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_CHOICE), ==, 0); + + /* Register SPA_TYPE_Bool */ + { + g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool")); + + guint32 id = 0; + const char *name = NULL; + g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", &id, &name, NULL)); + g_assert_cmpuint (id, ==, SPA_TYPE_Bool); + g_assert_cmpstr (name, ==, "Spa:Bool"); + + name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Spa:Bool"); + g_assert_cmpstr (nick, ==, "spa-bool"); + + g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Spa:Bool", "spa-bool")); + + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1); + } + + /* Register Custom */ + { + g_assert_true (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool")); + + guint32 id = 0; + const char *name = NULL; + g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", &id, &name, NULL)); + g_assert_cmpuint (id, ==, SPA_TYPE_VENDOR_Other + 1); + g_assert_cmpstr (name, ==, "Wp:Bool"); + + name = NULL; + const char *nick = NULL; + g_assert_true (wp_spa_type_get_by_id (WP_SPA_TYPE_TABLE_BASIC, id, &name, &nick, NULL)); + g_assert_cmpstr (name, ==, "Wp:Bool"); + g_assert_cmpstr (nick, ==, "wp-bool"); + + g_assert_false (wp_spa_type_register (WP_SPA_TYPE_TABLE_BASIC, "Wp:Bool", "wp-bool")); + + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 2); + } + + /* Unregister SPA_TYPE_Bool */ + g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL)); + wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "spa-bool"); + g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "spa-bool", NULL, NULL, NULL)); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 1); + + /* Unregister Custom */ + g_assert_true (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL)); + wp_spa_type_unregister (WP_SPA_TYPE_TABLE_BASIC, "wp-bool"); + g_assert_false (wp_spa_type_get_by_nick (WP_SPA_TYPE_TABLE_BASIC, "wp-bool", NULL, NULL, NULL)); + g_assert_cmpuint (wp_spa_type_get_table_size (WP_SPA_TYPE_TABLE_BASIC), ==, 0); + + wp_spa_type_deinit (); +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/wp/spa-type/basic", test_spa_type_basic); + g_test_add_func ("/wp/spa-type/register", test_spa_type_register); + + return g_test_run (); +}