mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-05-27 21:37:37 -04:00
566 lines
16 KiB
C
566 lines
16 KiB
C
|
|
/* PipeWire */
|
||
|
|
/* SPDX-FileCopyrightText: Copyright © 2024 Wim Taymans */
|
||
|
|
/* SPDX-License-Identifier: MIT */
|
||
|
|
|
||
|
|
#include "pwtest.h"
|
||
|
|
|
||
|
|
#include <pipewire/pipewire.h>
|
||
|
|
#include <pipewire/conf.h>
|
||
|
|
|
||
|
|
struct match_result {
|
||
|
|
int count;
|
||
|
|
char action[64];
|
||
|
|
char value[1024];
|
||
|
|
};
|
||
|
|
|
||
|
|
static int match_callback(void *data, const char *location, const char *action,
|
||
|
|
const char *str, size_t len)
|
||
|
|
{
|
||
|
|
struct match_result *r = data;
|
||
|
|
r->count++;
|
||
|
|
snprintf(r->action, sizeof(r->action), "%s", action);
|
||
|
|
snprintf(r->value, sizeof(r->value), "%.*s", (int)len, str);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int match_count_callback(void *data, const char *location, const char *action,
|
||
|
|
const char *str, size_t len)
|
||
|
|
{
|
||
|
|
int *count = data;
|
||
|
|
(*count)++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int match_error_callback(void *data, const char *location, const char *action,
|
||
|
|
const char *str, size_t len)
|
||
|
|
{
|
||
|
|
return -EPERM;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_basic)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci } ]"
|
||
|
|
" actions = { update-props = { priority = 100 } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 1);
|
||
|
|
pwtest_str_eq(r.action, "update-props");
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_no_match)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "bluez_sink"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci } ]"
|
||
|
|
" actions = { update-props = { priority = 100 } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_regex)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci-0000_00_1f.3.analog-stereo"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = \"~alsa_output.*\" } ]"
|
||
|
|
" actions = { update-props = { priority = 100 } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_negation)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "bluez_sink.XX_XX_XX"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = \"!alsa_output.pci\" } ]"
|
||
|
|
" actions = { update-props = { priority = 50 } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_negation_no_match)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = \"!alsa_output.pci\" } ]"
|
||
|
|
" actions = { update-props = { priority = 50 } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_negated_regex)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "v4l2_source.camera"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = \"!~alsa_.*\" } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_multiple_properties)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci"),
|
||
|
|
SPA_DICT_ITEM_INIT("media.class", "Audio/Sink"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci"
|
||
|
|
" media.class = Audio/Sink } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_multiple_properties_partial_fail)
|
||
|
|
{
|
||
|
|
struct match_result r = { 0 };
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci"),
|
||
|
|
SPA_DICT_ITEM_INIT("media.class", "Audio/Source"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci"
|
||
|
|
" media.class = Audio/Sink } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_callback, &r), 0);
|
||
|
|
pwtest_int_eq(r.count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_alternative_matches)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "bluez_sink.XX"));
|
||
|
|
/* matches array has two objects — OR semantics */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci }"
|
||
|
|
" { node.name = bluez_sink.XX } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_multiple_rules)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "alsa_output.pci"),
|
||
|
|
SPA_DICT_ITEM_INIT("media.class", "Audio/Sink"));
|
||
|
|
/* two separate rules, both match */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = alsa_output.pci } ]"
|
||
|
|
" actions = { update-props = { } } }"
|
||
|
|
" { matches = [ { media.class = Audio/Sink } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 2);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_null_property)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"));
|
||
|
|
/* match when property is absent: null matches missing prop */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.nick = null } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_null_no_match)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"),
|
||
|
|
SPA_DICT_ITEM_INIT("node.nick", "present"));
|
||
|
|
/* null does not match when property exists */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.nick = null } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_negated_null)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"),
|
||
|
|
SPA_DICT_ITEM_INIT("node.nick", "present"));
|
||
|
|
/* !null matches when property exists */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.nick = \"!null\" } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_empty_props)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_INIT(NULL, 0);
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = test } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_callback_error)
|
||
|
|
{
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = test } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_error_callback, NULL), -EPERM);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_not_array)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_INIT(NULL, 0);
|
||
|
|
const char rules[] = "{ not = an-array }";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_no_actions)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"));
|
||
|
|
/* matches but no actions key */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = test } ] } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_multiple_actions)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { node.name = test } ]"
|
||
|
|
" actions = { update-props = { a = b }"
|
||
|
|
" create-object = { factory = adapter } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 2);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_empty_array)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"));
|
||
|
|
const char rules[] = "[ ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_array_property_value)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("node.name", "test"),
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp a2dp ]"));
|
||
|
|
/* match against one element of an array-valued property */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { device.features = a2dp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_array_property_either)
|
||
|
|
{
|
||
|
|
int count;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp a2dp ]"));
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
|
||
|
|
/* first element matches */
|
||
|
|
count = 0;
|
||
|
|
const char rules_first[] =
|
||
|
|
"[ { matches = [ { device.features = hfp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules_first, strlen(rules_first), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
|
||
|
|
/* last element matches */
|
||
|
|
count = 0;
|
||
|
|
const char rules_last[] =
|
||
|
|
"[ { matches = [ { device.features = a2dp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules_last, strlen(rules_last), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
|
||
|
|
/* neither matches */
|
||
|
|
count = 0;
|
||
|
|
const char rules_none[] =
|
||
|
|
"[ { matches = [ { device.features = sbc } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules_none, strlen(rules_none), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_array_property_or)
|
||
|
|
{
|
||
|
|
int count;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp ]"));
|
||
|
|
/* match when array contains hfp or a2dp */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { device.features = hfp }"
|
||
|
|
" { device.features = a2dp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
|
||
|
|
/* has hfp but not a2dp — should match */
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
|
||
|
|
/* has a2dp but not hfp — should match */
|
||
|
|
struct spa_dict props2 = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ sbc a2dp ]"));
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props2, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
|
||
|
|
/* has neither — should not match */
|
||
|
|
struct spa_dict props3 = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ sbc aac ]"));
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props3, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_array_property_and)
|
||
|
|
{
|
||
|
|
int count;
|
||
|
|
/* match when array contains both hfp and a2dp */
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { device.features = hfp"
|
||
|
|
" device.features = a2dp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
|
||
|
|
/* has both — should match */
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp a2dp ]"));
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
|
||
|
|
/* has only hfp — should not match */
|
||
|
|
struct spa_dict props2 = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp ]"));
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props2, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
|
||
|
|
/* has only a2dp — should not match */
|
||
|
|
struct spa_dict props3 = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ sbc a2dp ]"));
|
||
|
|
count = 0;
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props3, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_array_property_no_match)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.features", "[ hfp hsp ]"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { device.features = a2dp } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 0);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST(match_rules_regex_array_property)
|
||
|
|
{
|
||
|
|
int count = 0;
|
||
|
|
struct spa_dict props = SPA_DICT_ITEMS(
|
||
|
|
SPA_DICT_ITEM_INIT("device.profiles", "[ analog-stereo hdmi-stereo ]"));
|
||
|
|
const char rules[] =
|
||
|
|
"[ { matches = [ { device.profiles = \"~hdmi-.*\" } ]"
|
||
|
|
" actions = { update-props = { } } } ]";
|
||
|
|
|
||
|
|
pw_init(0, NULL);
|
||
|
|
pwtest_int_eq(pw_conf_match_rules(rules, strlen(rules), NULL, &props, match_count_callback, &count), 0);
|
||
|
|
pwtest_int_eq(count, 1);
|
||
|
|
pw_deinit();
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|
||
|
|
|
||
|
|
PWTEST_SUITE(context)
|
||
|
|
{
|
||
|
|
pwtest_add(match_rules_basic, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_no_match, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_regex, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_negation, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_negation_no_match, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_negated_regex, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_multiple_properties, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_multiple_properties_partial_fail, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_alternative_matches, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_multiple_rules, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_null_property, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_null_no_match, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_negated_null, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_empty_props, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_callback_error, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_not_array, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_no_actions, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_multiple_actions, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_empty_array, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_array_property_value, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_array_property_either, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_array_property_or, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_array_property_and, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_array_property_no_match, PWTEST_NOARG);
|
||
|
|
pwtest_add(match_rules_regex_array_property, PWTEST_NOARG);
|
||
|
|
|
||
|
|
return PWTEST_PASS;
|
||
|
|
}
|