wireplumber/tests/wp/spa-pod.c
George Kiagiadakis 4736d56557 log: implement a log topics system, like pipewire
The intention is to make checks for enabled log topics faster.

Every topic has its own structure that is statically defined in the file
where the logs are printed from. The structure is initialized transparently
when it is first used and it contains all the log level flags for the levels
that this topic should print messages. It is then checked on the wp_log()
macro before printing the message.

Topics from SPA/PipeWire are also handled natively, so messages are printed
directly without checking if the topic is enabled, since the PipeWire and SPA
macros do the checking themselves.

Messages coming from GLib are checked inside the handler.

An internal WpLogFields object is used to manage the state of each log
message, populating all the fields appropriately from the place they
are coming from (wp_log, spa_log, glib log), formatting the message and
then printing it. For printing to the journald, we still use the glib
message handler, converting all the needed fields to GLogField on demand.
That message handler does not do any checks for the topic or the level, so
we can just call it to send the message.
2023-05-16 20:42:28 +03:00

1093 lines
36 KiB
C

/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "../common/test-log.h"
static void
test_spa_pod_basic (void)
{
/* None */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_none ();
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_none (pod));
g_assert_false (wp_spa_pod_is_id (pod));
g_assert_cmpstr ("Spa:None", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_autoptr (WpSpaPod) other = wp_spa_pod_new_none ();
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Boolean */
{
g_autoptr (WpSpaPod) copy = NULL;
g_assert_null (copy);
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_boolean (TRUE);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_boolean (pod));
gboolean value = FALSE;
g_assert_true (wp_spa_pod_get_boolean (pod, &value));
g_assert_true (value);
g_assert_cmpstr ("Spa:Bool", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_boolean (pod, FALSE));
g_assert_true (wp_spa_pod_get_boolean (pod, &value));
g_assert_false (value);
copy = wp_spa_pod_copy (pod);
}
g_assert_nonnull (copy);
g_assert_true (wp_spa_pod_is_boolean (copy));
gboolean value = FALSE;
g_assert_true (wp_spa_pod_get_boolean (copy, &value));
g_assert_false (value);
g_assert_cmpstr ("Spa:Bool", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (copy)));
g_autoptr (WpSpaPod) other = wp_spa_pod_new_boolean (TRUE);
g_assert_true (wp_spa_pod_set_pod (copy, other));
g_assert_true (wp_spa_pod_get_boolean (copy, &value));
g_assert_true (value);
g_assert_true (wp_spa_pod_equal (copy, other));
}
/* Id */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_id (5);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_id (pod));
guint32 value = 0;
g_assert_true (wp_spa_pod_get_id (pod, &value));
g_assert_cmpuint (value, ==, 5);
g_assert_cmpstr ("Spa:Id", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_id (pod, 10));
g_assert_true (wp_spa_pod_get_id (pod, &value));
g_assert_cmpuint (value, ==, 10);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_id (20);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_id (pod, &value));
g_assert_cmpuint (value, ==, 20);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Int */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_int (-12);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_int (pod));
gint32 value = 0;
g_assert_true (wp_spa_pod_get_int (pod, &value));
g_assert_cmpint (value, ==, -12);
g_assert_cmpstr ("Spa:Int", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_int (pod, 9999));
g_assert_true (wp_spa_pod_get_int (pod, &value));
g_assert_cmpint (value, ==, 9999);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_int (1000);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_int (pod, &value));
g_assert_cmpuint (value, ==, 1000);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Long */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_long (LONG_MAX);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_long (pod));
gint64 value = 0;
g_assert_true (wp_spa_pod_get_long (pod, &value));
g_assert_cmpint (value, ==, LONG_MAX);
g_assert_cmpstr ("Spa:Long", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_long (pod, LONG_MIN));
g_assert_true (wp_spa_pod_get_long (pod, &value));
g_assert_cmpuint (value, ==, LONG_MIN);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_long (0);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_long (pod, &value));
g_assert_cmpuint (value, ==, 0);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Float */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_float (3.14);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_float (pod));
float value = 0;
g_assert_true (wp_spa_pod_get_float (pod, &value));
g_assert_cmpfloat_with_epsilon (value, 3.14, 0.001);
g_assert_cmpstr ("Spa:Float", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_float (pod, 1.0));
g_assert_true (wp_spa_pod_get_float (pod, &value));
g_assert_cmpfloat_with_epsilon (value, 1.0, 0.001);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_float (-3.14);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_float (pod, &value));
g_assert_cmpfloat_with_epsilon (value, -3.14, 0.001);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Double */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_double (2.718281828);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_double (pod));
double value = 0;
g_assert_true (wp_spa_pod_get_double (pod, &value));
g_assert_cmpfloat_with_epsilon (value, 2.718281828, 0.0000000001);
g_assert_cmpstr ("Spa:Double", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_double (pod, 2.0));
g_assert_true (wp_spa_pod_get_double (pod, &value));
g_assert_cmpfloat_with_epsilon (value, 2.0, 0.0000000001);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_double (3.0);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_double (pod, &value));
g_assert_cmpfloat_with_epsilon (value, 3.0, 0.0000000001);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* String */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_string ("WirePlumber");
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_string (pod));
const char *value = NULL;
g_assert_true (wp_spa_pod_get_string (pod, &value));
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "WirePlumber");
g_assert_cmpstr ("Spa:String", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_autoptr (WpSpaPod) other = wp_spa_pod_new_string ("Other");
g_assert_nonnull (other);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_string (pod, &value));
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "Other");
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Bytes */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_bytes ("bytes", 5);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_bytes (pod));
gconstpointer value = NULL;
guint32 len = 0;
g_assert_true (wp_spa_pod_get_bytes (pod, &value, &len));
g_assert_nonnull (value);
g_assert_cmpmem (value, len, "bytes", 5);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpstr ("Spa:Bytes", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_autoptr (WpSpaPod) other = wp_spa_pod_new_bytes ("pod", 3);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_bytes (pod, &value, &len));
g_assert_nonnull (value);
g_assert_cmpmem (value, len, "pod", 3);
g_assert_cmpuint (len, ==, 3);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Pointer */
{
gint i = 3;
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_pointer ("Spa:Pointer:Buffer", &i);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_pointer (pod));
gconstpointer p = NULL;
g_assert_true (wp_spa_pod_get_pointer (pod, &p));
g_assert_nonnull (p);
g_assert_true (p == &i);
g_assert_cmpint (*(gint *)p, ==, 3);
g_assert_cmpstr ("Spa:Pointer:Buffer", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
float f = 1.1;
g_autoptr (WpSpaPod) other = wp_spa_pod_new_pointer ("Spa:Pointer:Meta", &f);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_pointer (pod, &p));
g_assert_nonnull (p);
g_assert_true (p == &f);
g_assert_cmpfloat_with_epsilon (*(float *)p, 1.1, 0.01);
g_assert_cmpstr ("Spa:Pointer:Meta", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Fd */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_fd (4);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_fd (pod));
gint64 value = 0;
g_assert_true (wp_spa_pod_get_fd (pod, &value));
g_assert_cmpint (value, ==, 4);
g_assert_cmpstr ("Spa:Fd", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_fd (pod, 1));
g_assert_true (wp_spa_pod_get_fd (pod, &value));
g_assert_cmpuint (value, ==, 1);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_fd (10);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_fd (pod, &value));
g_assert_cmpuint (value, ==, 10);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Rectangle */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_rectangle (1920, 1080);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_rectangle (pod));
guint32 width = 0;
guint32 height = 0;
g_assert_true (wp_spa_pod_get_rectangle (pod, &width, &height));
g_assert_cmpint (width, ==, 1920);
g_assert_cmpint (height, ==, 1080);
g_assert_cmpstr ("Spa:Rectangle", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_rectangle (pod, 640, 480));
g_assert_true (wp_spa_pod_get_rectangle (pod, &width, &height));
g_assert_cmpint (width, ==, 640);
g_assert_cmpint (height, ==, 480);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_rectangle (200, 100);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_rectangle (pod, &width, &height));
g_assert_cmpint (width, ==, 200);
g_assert_cmpint (height, ==, 100);
g_assert_true (wp_spa_pod_equal (pod, other));
}
/* Fraction */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_fraction (16, 9);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_fraction (pod));
guint32 num = 0;
guint32 denom = 0;
g_assert_true (wp_spa_pod_get_fraction (pod, &num, &denom));
g_assert_cmpint (num, ==, 16);
g_assert_cmpint (denom, ==, 9);
g_assert_cmpstr ("Spa:Fraction", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_true (wp_spa_pod_set_fraction (pod, 4, 3));
g_assert_true (wp_spa_pod_get_fraction (pod, &num, &denom));
g_assert_cmpint (num, ==, 4);
g_assert_cmpint (denom, ==, 3);
g_autoptr (WpSpaPod) other = wp_spa_pod_new_fraction (2, 1);
g_assert_true (wp_spa_pod_set_pod (pod, other));
g_assert_true (wp_spa_pod_get_fraction (pod, &num, &denom));
g_assert_cmpint (num, ==, 2);
g_assert_cmpint (denom, ==, 1);
g_assert_true (wp_spa_pod_equal (pod, other));
}
}
static void
test_spa_pod_choice (void)
{
/* Static Enum */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_choice (
"Enum", "i", 0, "i", 1, "i", 2, NULL);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_choice (pod));
g_assert_cmpstr ("Spa:Pod:Choice", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_assert_cmpstr ("Enum", ==,
wp_spa_id_value_short_name (wp_spa_pod_get_choice_type (pod)));
g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod);
g_assert_nonnull (child);
g_assert_cmpstr ("Spa:Int", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (child)));
gint32 value = 1;
g_assert_true (wp_spa_pod_get_int (child, &value));
g_assert_cmpint (value, ==, 0);
g_assert_true (wp_spa_pod_set_int (child, 3));
g_assert_true (wp_spa_pod_get_int (child, &value));
g_assert_cmpint (value, ==, 3);
}
/* Static None */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_choice ("None", "s",
"default value", NULL);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_choice (pod));
g_assert_cmpstr ("Spa:Pod:Choice", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
{
g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod);
g_assert_nonnull (child);
g_assert_cmpstr ("Spa:String", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (child)));
const char *value = NULL;
g_assert_true (wp_spa_pod_get_string (child, &value));
g_assert_nonnull (value);
g_assert_cmpstr ("default value", ==, value);
g_autoptr (WpSpaPod) str_pod = wp_spa_pod_new_string ("new value");
g_assert_true (wp_spa_pod_set_pod (child, str_pod));
g_assert_true (wp_spa_pod_get_string (child, &value));
g_assert_cmpstr ("new value", ==, value);
}
{
g_autoptr (WpSpaPod) child = wp_spa_pod_get_choice_child (pod);
g_assert_nonnull (child);
g_assert_cmpstr ("Spa:String", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (child)));
const char *value = NULL;
g_assert_true (wp_spa_pod_get_string (child, &value));
g_assert_nonnull (value);
g_assert_cmpstr ("new value", ==, value);
}
}
/* Dynamic */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice ("Enum");
wp_spa_pod_builder_add (b, "i", 0, NULL);
wp_spa_pod_builder_add (b, "i", 1, NULL);
wp_spa_pod_builder_add (b, "i", 2, NULL);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_choice (pod));
g_assert_cmpstr ("Spa:Pod:Choice", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
}
/* It is not possible to use the parser to get the contents of a choice, you
* need to use the iterator API to achieve that. This is because there is no
* `spa_pod_parser_get_choice` API in the SPA library */
}
static void
test_spa_pod_array (void)
{
/* Dynamic */
{
WpSpaPodBuilder *b = wp_spa_pod_builder_new_array ();
wp_spa_pod_builder_add (b, "b", FALSE, NULL);
wp_spa_pod_builder_add (b, "b", TRUE, NULL);
wp_spa_pod_builder_add (b, "b", TRUE, NULL);
wp_spa_pod_builder_add (b, "b", FALSE, NULL);
wp_spa_pod_builder_add (b, "b", TRUE, NULL);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_array (pod));
g_assert_cmpstr ("Spa:Array", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
wp_spa_pod_builder_unref (b);
g_assert_true (wp_spa_pod_is_array (pod));
g_autoptr (WpSpaPod) child = wp_spa_pod_get_array_child (pod);
g_assert_nonnull (child);
g_assert_cmpstr ("Spa:Bool", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (child)));
gboolean value = TRUE;
g_assert_true (wp_spa_pod_get_boolean (child, &value));
g_assert_false (value);
}
/* It is not possible to use the parser to get the contents of an array, you
* need to use the iterator API to achieve that. This is because there is no
* `spa_pod_parser_get_array` API in the SPA library. */
}
static void
test_spa_pod_object (void)
{
/* Static */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:Props", "Props",
"mute", "b", FALSE,
"volume", "f", 0.5,
"frequency", "i", 440,
"device", "s", "device-name",
"deviceFd", "h", 5,
"id-01000000", "b", TRUE,
NULL);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_object (pod));
g_assert_cmpstr ("Spa:Pod:Object:Param:Props", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
const char *id_name;
gboolean mute = TRUE;
float vol = 0.0;
gint32 frequency;
const char *device;
gint64 device_fd;
gboolean custom = FALSE;
g_assert_true (wp_spa_pod_get_object (pod,
&id_name,
"mute", "b", &mute,
"volume", "f", &vol,
"frequency", "i", &frequency,
"device", "s", &device,
"deviceFd", "h", &device_fd,
"id-01000000", "b", &custom,
NULL));
g_assert_cmpstr (id_name, ==, "Props");
g_assert_false (mute);
g_assert_cmpfloat_with_epsilon (vol, 0.5, 0.01);
g_assert_cmpint (frequency, ==, 440);
g_assert_cmpstr (device, ==, "device-name");
g_assert_cmpint (device_fd, ==, 5);
g_assert_true (custom);
}
/* Dynamic */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_object (
"Spa:Pod:Object:Param:Props", "Props");
wp_spa_pod_builder_add_property (b, "mute");
wp_spa_pod_builder_add_boolean (b, FALSE);
wp_spa_pod_builder_add_property (b, "volume");
wp_spa_pod_builder_add_float (b, 0.5);
wp_spa_pod_builder_add_property (b, "frequency");
wp_spa_pod_builder_add_int (b, 440);
wp_spa_pod_builder_add_property (b, "device");
wp_spa_pod_builder_add_string (b, "device-name");
wp_spa_pod_builder_add_property (b, "deviceFd");
wp_spa_pod_builder_add_fd (b, 5);
wp_spa_pod_builder_add_property (b, "id-01000000");
wp_spa_pod_builder_add_boolean (b, TRUE);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_object (pod));
g_assert_cmpstr ("Spa:Pod:Object:Param:Props", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
const char *id_name;
gboolean mute = TRUE;
float vol = 0.0;
gint32 frequency;
const char *device;
gint64 device_fd;
gboolean custom = FALSE;
g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_object (pod, &id_name);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_parser_get (p, "mute", "b", &mute, NULL));
g_assert_true (wp_spa_pod_parser_get (p, "volume", "f", &vol, NULL));
g_assert_true (wp_spa_pod_parser_get (p, "frequency", "i", &frequency, NULL));
g_assert_true (wp_spa_pod_parser_get (p, "device", "s", &device, NULL));
g_assert_true (wp_spa_pod_parser_get (p, "deviceFd", "h", &device_fd, NULL));
g_assert_true (wp_spa_pod_parser_get (p, "id-01000000", "b", &custom, NULL));
wp_spa_pod_parser_end (p);
g_assert_cmpstr (id_name, ==, "Props");
g_assert_false (mute);
g_assert_cmpfloat_with_epsilon (vol, 0.5, 0.01);
g_assert_cmpint (frequency, ==, 440);
g_assert_cmpstr (device, ==, "device-name");
g_assert_cmpint (device_fd, ==, 5);
g_assert_true (custom);
}
}
static void
test_spa_pod_struct (void)
{
/* Dynamic */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_struct ();
wp_spa_pod_builder_add_boolean (b, TRUE);
wp_spa_pod_builder_add_id (b, 2);
wp_spa_pod_builder_add_int (b, 8);
wp_spa_pod_builder_add_long (b, 64);
wp_spa_pod_builder_add_float (b, 3.14);
wp_spa_pod_builder_add_double (b, 2.718281828);
wp_spa_pod_builder_add_string (b, "WirePlumber");
wp_spa_pod_builder_add_bytes (b, "bytes", 5);
wp_spa_pod_builder_add_pointer (b, "Spa:Pointer:Buffer", b);
wp_spa_pod_builder_add_fd (b, 4);
wp_spa_pod_builder_add_rectangle (b, 1920, 1080);
wp_spa_pod_builder_add_fraction (b, 16, 9);
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_int (35254);
wp_spa_pod_builder_add_pod (b, pod);
}
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:Props", "Props",
"mute", "b", FALSE,
NULL);
wp_spa_pod_builder_add (b, "P", pod, NULL);
}
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_struct (pod));
g_assert_cmpstr ("Spa:Pod:Struct", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
g_autoptr (WpSpaPodParser) p = wp_spa_pod_parser_new_struct (pod);
g_assert_nonnull (pod);
gboolean value_boolean;
g_assert_true (wp_spa_pod_parser_get_boolean (p, &value_boolean));
g_assert_true (value_boolean);
guint32 value_id;
g_assert_true (wp_spa_pod_parser_get_id (p, &value_id));
g_assert_cmpuint (value_id, ==, 2);
gint32 value_int;
g_assert_true (wp_spa_pod_parser_get_int (p, &value_int));
g_assert_cmpint (value_int, ==, 8);
gint64 value_long;
g_assert_true (wp_spa_pod_parser_get_long (p, &value_long));
g_assert_cmpint (value_long, ==, 64);
float value_float;
g_assert_true (wp_spa_pod_parser_get_float (p, &value_float));
g_assert_cmpfloat_with_epsilon (value_float, 3.14, 0.001);
double value_double;
g_assert_true (wp_spa_pod_parser_get_double (p, &value_double));
g_assert_cmpfloat_with_epsilon (value_double, 2.718281828, 0.0000000001);
const char *value_string;
g_assert_true (wp_spa_pod_parser_get_string (p, &value_string));
g_assert_cmpstr (value_string, ==, "WirePlumber");
gconstpointer value_bytes;
guint32 len_bytes;
g_assert_true (wp_spa_pod_parser_get_bytes (p, &value_bytes, &len_bytes));
g_assert_cmpmem (value_bytes, len_bytes, "bytes", 5);
g_assert_cmpuint (len_bytes, ==, 5);
gconstpointer value_pointer;
g_assert_true (wp_spa_pod_parser_get_pointer (p, &value_pointer));
g_assert_nonnull (value_pointer);
g_assert_true (value_pointer == b);
gint64 value_fd;
g_assert_true (wp_spa_pod_parser_get_fd (p, &value_fd));
g_assert_cmpint (value_fd, ==, 4);
guint32 value_width;
guint32 value_height;
g_assert_true (wp_spa_pod_parser_get_rectangle (p, &value_width, &value_height));
g_assert_cmpuint (value_width, ==, 1920);
g_assert_cmpuint (value_height, ==, 1080);
guint32 value_num;
guint32 value_denom;
g_assert_true (wp_spa_pod_parser_get_fraction (p, &value_num, &value_denom));
g_assert_cmpuint (value_num, ==, 16);
g_assert_cmpuint (value_denom, ==, 9);
g_autoptr (WpSpaPod) value_pod = wp_spa_pod_parser_get_pod (p);
g_assert_nonnull (value_pod);
gint value_pod_int;
g_assert_true (wp_spa_pod_get_int (value_pod, &value_pod_int));
g_assert_cmpint (value_pod_int, ==, 35254);
g_autoptr (WpSpaPod) value_object = NULL;
g_assert_true (wp_spa_pod_parser_get (p, "P", &value_object, NULL));
g_assert_nonnull (value_object);
const char *id_name;
gboolean mute = TRUE;
g_assert_true (wp_spa_pod_get_object (value_object,
&id_name,
"mute", "b", &mute,
NULL));
g_assert_cmpstr (id_name, ==, "Props");
g_assert_false (mute);
}
}
static void
test_spa_pod_sequence (void)
{
/* Static */
{
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_sequence (0,
10, "Properties", "l", G_GINT64_CONSTANT (9999), NULL);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_sequence (pod));
g_assert_cmpstr ("Spa:Pod:Sequence", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
}
/* Dynamic */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_sequence (0);
wp_spa_pod_builder_add_control (b, 10, "Properties");
wp_spa_pod_builder_add_long (b, G_GINT64_CONSTANT (9999));
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_sequence (pod));
g_assert_cmpstr ("Spa:Pod:Sequence", ==,
wp_spa_type_name (wp_spa_pod_get_spa_type (pod)));
}
/* It is not possible to use the parser to get the contents of a sequence, you
* need to use the iterator API to achieve that. This is because there is no
* `spa_pod_parser_get_sequence` API in the SPA library. */
}
static void
choice_foreach (const GValue *item, gpointer data)
{
gint32 *total = data;
const gint32 *value = g_value_get_pointer (item);
*total += *value;
}
static void
array_foreach (const GValue *item, gpointer data)
{
gint32 *total = data;
const gint32 *value = g_value_get_pointer (item);
*total += *value;
}
static void
object_foreach (const GValue *item, gpointer data)
{
guint32 *total_props = data;
WpSpaPod *prop = g_value_get_boxed (item);
g_assert_true (wp_spa_pod_is_property (prop));
*total_props += 1;
}
static void
struct_foreach (const GValue *item, gpointer data)
{
guint32 *total_fields = data;
*total_fields += 1;
}
static void
sequence_foreach (const GValue *item, gpointer data)
{
guint32 *offset_total = data;
WpSpaPod *control = g_value_get_boxed (item);
g_assert_true (wp_spa_pod_is_control (control));
guint32 offset = 0;
g_assert_true (wp_spa_pod_get_control (control, &offset, NULL, NULL));
*offset_total += offset;
}
static void
test_spa_pod_iterator (void)
{
/* Choice */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_choice ("Enum");
wp_spa_pod_builder_add (b, "i", 0, NULL);
wp_spa_pod_builder_add (b, "i", 1, NULL);
wp_spa_pod_builder_add (b, "i", 2, NULL);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 0);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 1);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 2);
g_value_unset (&next);
}
{
g_assert_false (wp_iterator_next (it, NULL));
}
gint32 total = 0;
g_assert_true (wp_iterator_foreach (it, choice_foreach, &total));
g_assert_cmpint (total, ==, 3);
}
/* Array */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_array ();
wp_spa_pod_builder_add_int (b, 1);
wp_spa_pod_builder_add_int (b, 2);
wp_spa_pod_builder_add_int (b, 3);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 1);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 2);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
gpointer p = g_value_get_pointer (&next);
g_assert_nonnull (p);
g_assert_cmpint (*(gint *)p, ==, 3);
g_value_unset (&next);
}
{
g_assert_false (wp_iterator_next (it, NULL));
}
gint total = 0;
g_assert_true (wp_iterator_foreach (it, array_foreach, &total));
g_assert_cmpint (total, ==, 6);
}
/* Object */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_object (
"Spa:Pod:Object:Param:Props", "Props");
wp_spa_pod_builder_add_property (b, "mute");
wp_spa_pod_builder_add_boolean (b, FALSE);
wp_spa_pod_builder_add_property (b, "device");
wp_spa_pod_builder_add_string (b, "device-name");
wp_spa_pod_builder_add_property (b, "id-01000000");
wp_spa_pod_builder_add_boolean (b, TRUE);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
g_assert_true (wp_spa_pod_is_property (p));
const char *key = NULL;
g_autoptr (WpSpaPod) value = NULL;
g_assert_true (wp_spa_pod_get_property (p, &key, &value));
g_assert_cmpstr (key, ==, "mute");
gboolean b = TRUE;
g_assert_true (wp_spa_pod_get_boolean (value, &b));
g_assert_false (b);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
g_assert_true (wp_spa_pod_is_property (p));
const char *key = NULL;
g_autoptr (WpSpaPod) value = NULL;
g_assert_true (wp_spa_pod_get_property (p, &key, &value));
g_assert_cmpstr (key, ==, "device");
const char *s = NULL;
g_assert_true (wp_spa_pod_get_string (value, &s));
g_assert_cmpstr (s, ==, "device-name");
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
g_assert_true (wp_spa_pod_is_property (p));
const char *key = NULL;
g_autoptr (WpSpaPod) value = NULL;
g_assert_true (wp_spa_pod_get_property (p, &key, &value));
g_assert_cmpstr (key, ==, "id-01000000");
gboolean b = FALSE;
g_assert_true (wp_spa_pod_get_boolean (value, &b));
g_assert_true (b);
g_value_unset (&next);
}
{
g_assert_false (wp_iterator_next (it, NULL));
}
guint32 total_props = 0;
g_assert_true (wp_iterator_foreach (it, object_foreach, &total_props));
g_assert_cmpuint (total_props, ==, 3);
}
/* Struct */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_struct ();
wp_spa_pod_builder_add_boolean (b, TRUE);
wp_spa_pod_builder_add_id (b, 2);
wp_spa_pod_builder_add_int (b, 8);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
gboolean v = FALSE;
g_assert_true (wp_spa_pod_get_boolean (p, &v));
g_assert_true (v);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
guint32 v = 0;
g_assert_true (wp_spa_pod_get_id (p, &v));
g_assert_cmpuint (v, ==, 2);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
gint v = 0;
g_assert_true (wp_spa_pod_get_int (p, &v));
g_assert_cmpint (v, ==, 8);
g_value_unset (&next);
}
{
g_assert_false (wp_iterator_next (it, NULL));
}
guint32 total_fields = 0;
g_assert_true (wp_iterator_foreach (it, struct_foreach, &total_fields));
g_assert_cmpuint (total_fields, ==, 3);
}
/* Sequence */
{
g_autoptr (WpSpaPodBuilder) b = wp_spa_pod_builder_new_sequence (0);
wp_spa_pod_builder_add_control (b, 10, "Properties");
wp_spa_pod_builder_add_float (b, 0.33);
wp_spa_pod_builder_add_control (b, 40, "Properties");
wp_spa_pod_builder_add_float (b, 0.66);
g_autoptr (WpSpaPod) pod = wp_spa_pod_builder_end (b);
g_assert_nonnull (pod);
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
g_assert_true (wp_spa_pod_is_control (p));
guint32 offset = 0;
const char *type_name = NULL;
g_autoptr (WpSpaPod) value = NULL;
g_assert_true (wp_spa_pod_get_control (p, &offset, &type_name, &value));
g_assert_cmpuint (offset, ==, 10);
g_assert_cmpstr (type_name, ==, "Properties");
float f = 0;
g_assert_true (wp_spa_pod_get_float (value, &f));
g_assert_cmpfloat_with_epsilon (f, 0.33, 0.001);
g_value_unset (&next);
}
{
GValue next = G_VALUE_INIT;
g_assert_true (wp_iterator_next (it, &next));
WpSpaPod *p = g_value_get_boxed (&next);
g_assert_nonnull (p);
g_assert_true (wp_spa_pod_is_control (p));
guint32 offset = 0;
const char *type_name = NULL;
g_autoptr (WpSpaPod) value = NULL;
g_assert_true (wp_spa_pod_get_control (p, &offset, &type_name, &value));
g_assert_cmpuint (offset, ==, 40);
g_assert_cmpstr (type_name, ==, "Properties");
float f = 0;
g_assert_true (wp_spa_pod_get_float (value, &f));
g_assert_cmpfloat_with_epsilon (f, 0.66, 0.001);
g_value_unset (&next);
}
{
g_assert_false (wp_iterator_next (it, NULL));
}
guint32 offset_total = 0;
g_assert_true (wp_iterator_foreach (it, sequence_foreach, &offset_total));
g_assert_cmpuint (offset_total, ==, 50);
}
}
static void
test_spa_pod_unique_owner (void)
{
/* Create an object */
WpSpaPod *pod = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:PropInfo", "PropInfo",
"id", "K", "unknown",
"name", "s", "prop-info-name",
NULL);
g_assert_nonnull (pod);
g_assert_true (wp_spa_pod_is_unique_owner (pod));
/* Get the first property using an iterator */
GValue next = G_VALUE_INIT;
g_autoptr (WpSpaPod) property = NULL;
{
g_autoptr (WpIterator) it = wp_spa_pod_new_iterator (pod);
g_assert_nonnull (it);
g_assert_true (wp_iterator_next (it, &next));
property = g_value_dup_boxed (&next);
}
g_assert_nonnull (property);
g_assert_true (wp_spa_pod_is_property (property));
{
g_autoptr (WpSpaPod) value = NULL;
const char *key = NULL;
g_assert_true (wp_spa_pod_get_property (property, &key, &value));
g_assert_nonnull (key);
g_assert_cmpstr (key, ==, "id");
g_assert_nonnull (value);
guint32 id = 0;
g_assert_true (wp_spa_pod_get_id (value, &id));
g_assert_cmpuint (id, ==, 1);
}
/* Own the data */
g_assert_true (wp_spa_pod_is_unique_owner (pod));
g_assert_false (wp_spa_pod_is_unique_owner (property));
property = wp_spa_pod_ensure_unique_owner (property);
g_assert_true (wp_spa_pod_is_unique_owner (pod));
g_assert_true (wp_spa_pod_is_unique_owner (property));
/* Destroy the object */
wp_spa_pod_unref (pod);
g_assert_true (wp_spa_pod_is_unique_owner (property));
/* Make sure the property data is still valid */
{
g_autoptr (WpSpaPod) value = NULL;
const char *key = NULL;
g_assert_true (wp_spa_pod_get_property (property, &key, &value));
g_assert_nonnull (key);
g_assert_cmpstr (key, ==, "id");
g_assert_nonnull (value);
guint32 id = 0;
g_assert_true (wp_spa_pod_get_id (value, &id));
g_assert_cmpuint (id, ==, 1);
}
/* Destroy the property */
g_value_unset (&next);
}
static void
test_spa_pod_port_config (void)
{
const gint32 rate = 48000;
const gint32 channels = 2;
/* Build the format to make sure the types exist */
g_autoptr (WpSpaPodBuilder) builder = wp_spa_pod_builder_new_object (
"Spa:Pod:Object:Param:Format", "Format");
wp_spa_pod_builder_add (builder,
"mediaType", "K", "audio",
"mediaSubtype", "K", "raw",
"format", "K", "S16LE",
"rate", "i", rate,
"channels", "i", channels,
NULL);
g_autoptr (WpSpaPodBuilder) position_builder = wp_spa_pod_builder_new_array ();
for (gint i = 0; i < channels; i++)
wp_spa_pod_builder_add_id (position_builder, 0);
wp_spa_pod_builder_add_property (builder, "position");
g_autoptr (WpSpaPod) position = wp_spa_pod_builder_end (position_builder);
wp_spa_pod_builder_add_pod (builder, position);
g_autoptr (WpSpaPod) format = wp_spa_pod_builder_end (builder);
g_assert_nonnull (format);
/* Build the port config to make sure the types exist */
g_autoptr (WpSpaPod) pod = wp_spa_pod_new_object (
"Spa:Pod:Object:Param:PortConfig", "PortConfig",
"direction", "K", "Input",
"mode", "K", "dsp",
"monitor", "b", FALSE,
"control", "b", FALSE,
"format", "P", format,
NULL);
g_assert_nonnull (pod);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_log_set_writer_func (wp_log_writer_default, NULL, NULL);
g_test_add_func ("/wp/spa-pod/basic", test_spa_pod_basic);
g_test_add_func ("/wp/spa-pod/choice", test_spa_pod_choice);
g_test_add_func ("/wp/spa-pod/array", test_spa_pod_array);
g_test_add_func ("/wp/spa-pod/object", test_spa_pod_object);
g_test_add_func ("/wp/spa-pod/struct", test_spa_pod_struct);
g_test_add_func ("/wp/spa-pod/sequence", test_spa_pod_sequence);
g_test_add_func ("/wp/spa-pod/iterator", test_spa_pod_iterator);
g_test_add_func ("/wp/spa-pod/unique-owner", test_spa_pod_unique_owner);
g_test_add_func ("/wp/spa-pod/port-config", test_spa_pod_port_config);
return g_test_run ();
}