mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-29 20:35:40 +00:00
validate:scenario: Replace the sub-action
with a foreach
action type
Sub-actions were really hard to use and conceptually weird. The implementation was ugly and made the code complex for nothing. Instead this commit introduces a `foreach` action type which allows repeating actions passed in an `actions` array the number of time specified by any `GstIntRange` value defined in the structure or its `repeat` field. This commit also makes sure that all action got through gst_validate_action_set_done upon finalization. + Cleanup surrounding code + Add tests Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/merge_requests/207>
This commit is contained in:
parent
e7355ea039
commit
9c08bfcaca
10 changed files with 528 additions and 206 deletions
|
@ -1,3 +1,8 @@
|
|||
description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true
|
||||
set-state, state="playing", sub-action="set-state, state=null", repeat=40
|
||||
|
||||
foreach, i=[0, 40],
|
||||
actions = {
|
||||
"set-state, state=playing",
|
||||
"set-state, state=null",
|
||||
}
|
||||
stop;
|
||||
|
|
|
@ -47,7 +47,7 @@ void register_action_types (void);
|
|||
* as we used to have to print actions in the action execution function
|
||||
* and this is done by the scenario itself now */
|
||||
G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action);
|
||||
G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action);
|
||||
G_GNUC_INTERNAL gboolean gst_validate_action_get_level (GstValidateAction *action);
|
||||
G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta);
|
||||
|
||||
#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario"
|
||||
|
|
|
@ -834,27 +834,36 @@ gst_validate_printf (gpointer source, const gchar * format, ...)
|
|||
va_end (var_args);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GString *str;
|
||||
gint indent;
|
||||
gint printed;
|
||||
} PrintActionFieldData;
|
||||
|
||||
static gboolean
|
||||
_append_value (GQuark field_id, const GValue * value, GString * string)
|
||||
_append_value (GQuark field_id, const GValue * value, PrintActionFieldData * d)
|
||||
{
|
||||
gchar *val_str = NULL;
|
||||
const gchar *fieldname = g_quark_to_string (field_id);
|
||||
|
||||
if (g_strcmp0 (g_quark_to_string (field_id), "sub-action") == 0)
|
||||
if (g_str_has_prefix (fieldname, "__") && g_str_has_suffix (fieldname, "__"))
|
||||
return TRUE;
|
||||
|
||||
if (g_strcmp0 (g_quark_to_string (field_id), "repeat") == 0)
|
||||
if (g_strcmp0 (fieldname, "repeat") == 0)
|
||||
return TRUE;
|
||||
|
||||
d->printed++;
|
||||
if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
|
||||
val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (g_value_get_uint64 (value)));
|
||||
else
|
||||
val_str = gst_value_serialize (value);
|
||||
|
||||
g_string_append (string, "\n - ");
|
||||
g_string_append (string, g_quark_to_string (field_id));
|
||||
g_string_append_len (string, "=", 1);
|
||||
g_string_append (string, val_str);
|
||||
g_string_append_printf (d->str, "\n%*c - ", d->indent, ' ');
|
||||
g_string_append (d->str, fieldname);
|
||||
g_string_append_len (d->str, "=", 1);
|
||||
g_string_append (d->str, val_str);
|
||||
|
||||
g_free (val_str);
|
||||
|
||||
|
@ -874,26 +883,24 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message)
|
|||
GString *string = NULL;
|
||||
|
||||
if (message == NULL) {
|
||||
gint nrepeats;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
|
||||
if (gst_validate_action_is_subaction (action))
|
||||
g_string_append_printf (string, "(subaction)");
|
||||
|
||||
if (gst_structure_get_int (action->structure, "repeat", &nrepeats))
|
||||
g_string_append_printf (string, "(%d/%d)", nrepeats - action->repeat + 1,
|
||||
nrepeats);
|
||||
gint indent = (gst_validate_action_get_level (action) * 2);
|
||||
PrintActionFieldData d = { NULL, indent, 0 };
|
||||
d.str = string = g_string_new (NULL);
|
||||
|
||||
g_string_append_printf (string, "%s",
|
||||
gst_structure_get_name (action->structure));
|
||||
|
||||
g_string_append_len (string, " ( ", 3);
|
||||
gst_structure_foreach (action->structure,
|
||||
(GstStructureForeachFunc) _append_value, string);
|
||||
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||
g_string_append_printf (string, " [%s=%d/%d]",
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) ?
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", action->repeat,
|
||||
GST_VALIDATE_ACTION_N_REPEATS (action));
|
||||
|
||||
if (gst_structure_n_fields (action->structure))
|
||||
g_string_append (string, "\n)\n");
|
||||
g_string_append (string, " ( ");
|
||||
gst_structure_foreach (action->structure,
|
||||
(GstStructureForeachFunc) _append_value, &d);
|
||||
if (d.printed)
|
||||
g_string_append_printf (string, "\n%*c)\n", indent, ' ');
|
||||
else
|
||||
g_string_append (string, ")\n");
|
||||
message = string->str;
|
||||
|
@ -980,12 +987,15 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args)
|
|||
if (source) {
|
||||
if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
|
||||
GstValidateAction *action = (GstValidateAction *) source;
|
||||
gint indent = gst_validate_action_get_level (action) * 2;
|
||||
|
||||
if (_action_check_and_set_printed (action))
|
||||
goto out;
|
||||
|
||||
g_string_assign (string, "\nExecuting ");
|
||||
|
||||
if (!indent)
|
||||
g_string_assign (string, "Executing ");
|
||||
else
|
||||
g_string_append_printf (string, "%*c↳ Executing ", indent - 2, ' ');
|
||||
} else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) {
|
||||
gint i;
|
||||
gint n_params;
|
||||
|
|
|
@ -345,28 +345,37 @@ gst_validate_report_action (GstValidateReporter * reporter,
|
|||
const gchar * format, ...)
|
||||
{
|
||||
va_list var_args;
|
||||
gint nrepeats;
|
||||
gchar *f, *repeat = NULL;
|
||||
GString *f;
|
||||
|
||||
if (action && gst_structure_get_int (action->structure, "repeat", &nrepeats))
|
||||
repeat =
|
||||
g_strdup_printf (" (repeat: %d/%d)", nrepeats - action->repeat + 1,
|
||||
nrepeats);
|
||||
if (!action) {
|
||||
f = g_string_new (format);
|
||||
goto done;
|
||||
}
|
||||
|
||||
f = action ? g_strdup_printf ("\n> %s:%d%s\n> %d | %s\n> %*c|\n",
|
||||
GST_VALIDATE_ACTION_FILENAME (action),
|
||||
GST_VALIDATE_ACTION_LINENO (action), repeat ? repeat : "",
|
||||
GST_VALIDATE_ACTION_LINENO (action), format,
|
||||
(gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1,
|
||||
' ')
|
||||
: g_strdup (format);
|
||||
f = g_string_new (NULL);
|
||||
g_string_append_printf (f, "\n> %s:%d", GST_VALIDATE_ACTION_FILENAME (action),
|
||||
GST_VALIDATE_ACTION_LINENO (action));
|
||||
|
||||
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||
g_string_append_printf (f, " (repeat: %d/%d)",
|
||||
action->repeat, GST_VALIDATE_ACTION_N_REPEATS (action));
|
||||
|
||||
g_string_append_printf (f, "\n%s", GST_VALIDATE_ACTION_DEBUG (action));
|
||||
if (gst_validate_action_get_level (action)) {
|
||||
gchar *subaction_str = gst_structure_to_string (action->structure);
|
||||
|
||||
g_string_append_printf (f, "\n |-> %s", subaction_str);
|
||||
g_free (subaction_str);
|
||||
}
|
||||
|
||||
g_string_append_printf (f, "\n >\n > %s", format);
|
||||
|
||||
done:
|
||||
va_start (var_args, format);
|
||||
gst_validate_report_valist (reporter, issue_id, f, var_args);
|
||||
gst_validate_report_valist (reporter, issue_id, f->str, var_args);
|
||||
va_end (var_args);
|
||||
|
||||
g_free (f);
|
||||
g_free (repeat);
|
||||
g_string_free (f, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -374,9 +374,11 @@ struct _GstValidateActionPrivate
|
|||
GstValidateExecuteActionReturn state; /* Actually ActionState */
|
||||
gboolean printed;
|
||||
gboolean executing_last_subaction;
|
||||
gboolean subaction_level;
|
||||
gboolean optional;
|
||||
|
||||
GstClockTime execution_time;
|
||||
GstClockTime execution_duration;
|
||||
GstClockTime timeout;
|
||||
|
||||
GWeakRef scenario;
|
||||
|
@ -457,6 +459,31 @@ _action_copy (GstValidateAction * act)
|
|||
return copy;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_validate_action_return_get_name (GstValidateActionReturn r)
|
||||
{
|
||||
switch (r) {
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ERROR:
|
||||
return "ERROR";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_OK:
|
||||
return "OK";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||
return "ASYNC";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||
return "INTERLACED";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED:
|
||||
return "ERROR(reported)";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||
return "IN_PROGRESS";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||
return "NONE";
|
||||
case GST_VALIDATE_EXECUTE_ACTION_SKIP:
|
||||
return "SKIP";
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return "???";
|
||||
}
|
||||
|
||||
static void
|
||||
_action_free (GstValidateAction * action)
|
||||
{
|
||||
|
@ -508,6 +535,7 @@ gst_validate_action_new (GstValidateScenario * scenario,
|
|||
gst_validate_action_init (action);
|
||||
action->playback_time = GST_CLOCK_TIME_NONE;
|
||||
action->priv->timeout = GST_CLOCK_TIME_NONE;
|
||||
action->priv->state = GST_VALIDATE_EXECUTE_ACTION_NONE;
|
||||
action->type = action_type->name;
|
||||
action->repeat = -1;
|
||||
|
||||
|
@ -541,11 +569,10 @@ _action_check_and_set_printed (GstValidateAction * action)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_validate_action_is_subaction (GstValidateAction * action)
|
||||
gint
|
||||
gst_validate_action_get_level (GstValidateAction * action)
|
||||
{
|
||||
return !gst_structure_is_equal (action->structure,
|
||||
action->priv->main_structure);
|
||||
return action->priv->subaction_level;
|
||||
}
|
||||
|
||||
/* GstValidateActionType implementation */
|
||||
|
@ -1186,7 +1213,7 @@ _set_timed_value (GQuark field_id, const GValue * gvalue,
|
|||
const gchar *unused_fields[] =
|
||||
{ "binding-type", "source-type", "interpolation-mode",
|
||||
"timestamp", "__scenario__", "__action__", "__res__", "repeat",
|
||||
"sub-action", "playback-time", NULL
|
||||
"playback-time", NULL
|
||||
};
|
||||
|
||||
if (g_strv_contains (unused_fields, field))
|
||||
|
@ -1348,7 +1375,7 @@ _set_or_check_properties (GQuark field_id, const GValue * value,
|
|||
GParamSpec *paramspec = NULL;
|
||||
const gchar *field = g_quark_to_string (field_id);
|
||||
const gchar *unused_fields[] = { "__scenario__", "__action__", "__res__",
|
||||
"sub-action", "playback-time", "repeat", NULL
|
||||
"playback-time", "repeat", NULL
|
||||
};
|
||||
|
||||
if (g_strv_contains (unused_fields, field))
|
||||
|
@ -2381,6 +2408,27 @@ gst_validate_parse_next_action_playback_time (GstValidateScenario * self)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_foreach_find_iterator (GQuark field_id, GValue * value,
|
||||
GstValidateAction * action)
|
||||
{
|
||||
if (!g_strcmp0 (g_quark_to_string (field_id), "actions"))
|
||||
return TRUE;
|
||||
|
||||
if (!GST_VALUE_HOLDS_INT_RANGE (value))
|
||||
return TRUE;
|
||||
|
||||
if (GST_VALIDATE_ACTION_RANGE_NAME (action)) {
|
||||
gst_validate_error_structure (action, "Found several ranges in structure, "
|
||||
"it is not supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) = g_quark_to_string (field_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GstValidateExecuteActionReturn
|
||||
gst_validate_execute_action (GstValidateActionType * action_type,
|
||||
GstValidateAction * action)
|
||||
|
@ -2395,6 +2443,11 @@ gst_validate_execute_action (GstValidateActionType * action_type,
|
|||
|
||||
if (action_type->prepare) {
|
||||
res = action_type->prepare (action);
|
||||
if (res == GST_VALIDATE_EXECUTE_ACTION_SKIP) {
|
||||
gst_validate_print_action (action, NULL);
|
||||
return GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
}
|
||||
|
||||
if (res != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||
GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT
|
||||
" could not be prepared", action->structure);
|
||||
|
@ -2412,18 +2465,6 @@ gst_validate_execute_action (GstValidateActionType * action_type,
|
|||
res = action_type->execute (scenario, action);
|
||||
gst_object_unref (scenario);
|
||||
|
||||
if (!gst_structure_has_field (action->structure, "sub-action")) {
|
||||
gst_structure_free (action->structure);
|
||||
action->priv->printed = FALSE;
|
||||
action->structure = gst_structure_copy (action->priv->main_structure);
|
||||
|
||||
if (!(action->name = gst_structure_get_string (action->structure, "name")))
|
||||
action->name = "";
|
||||
|
||||
if (res == GST_VALIDATE_EXECUTE_ACTION_ASYNC)
|
||||
action->priv->executing_last_subaction = TRUE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -2540,75 +2581,24 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action,
|
|||
return res;
|
||||
}
|
||||
|
||||
static GstValidateExecuteActionReturn
|
||||
_execute_sub_action_action (GstValidateAction * action)
|
||||
static gboolean
|
||||
gst_validate_scenario_execute_next_or_restart_looping (GstValidateScenario *
|
||||
scenario)
|
||||
{
|
||||
const gchar *subaction_str;
|
||||
GstStructure *subaction_struct = NULL;
|
||||
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
GstValidateScenario *scenario = NULL;
|
||||
|
||||
if (action->priv->executing_last_subaction) {
|
||||
action->priv->executing_last_subaction = FALSE;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
scenario = gst_validate_action_get_scenario (action);
|
||||
g_assert (scenario);
|
||||
subaction_str = gst_structure_get_string (action->structure, "sub-action");
|
||||
if (subaction_str) {
|
||||
subaction_struct = gst_structure_from_string (subaction_str, NULL);
|
||||
|
||||
if (subaction_struct == NULL) {
|
||||
GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_FILE_MALFORMED,
|
||||
"Sub action %s could not be parsed", subaction_str);
|
||||
|
||||
res = GST_VALIDATE_EXECUTE_ACTION_ERROR;
|
||||
goto done;
|
||||
}
|
||||
/* Recurse to the next action if it is possible
|
||||
* to execute right away */
|
||||
if (!scenario->priv->execute_on_idle) {
|
||||
GST_DEBUG_OBJECT (scenario, "linking next action execution");
|
||||
|
||||
return execute_next_action (scenario);
|
||||
} else {
|
||||
gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE,
|
||||
&subaction_struct, NULL);
|
||||
_add_execute_actions_gsource (scenario);
|
||||
GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for"
|
||||
" next dispatch");
|
||||
}
|
||||
|
||||
if (subaction_struct) {
|
||||
if (action->structure) {
|
||||
GST_INFO_OBJECT (scenario, "Clearing old action structure");
|
||||
gst_structure_free (action->structure);
|
||||
}
|
||||
|
||||
res = _fill_action (scenario, action, subaction_struct, FALSE);
|
||||
if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) {
|
||||
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
||||
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||
"Sub action %" GST_PTR_FORMAT " could not be filled",
|
||||
subaction_struct);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) {
|
||||
GstValidateActionType *action_type = _find_action_type (action->type);
|
||||
|
||||
action->priv->printed = FALSE;
|
||||
res = gst_validate_execute_action (action_type, action);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
if (scenario)
|
||||
gst_object_unref (scenario);
|
||||
if (subaction_struct)
|
||||
gst_structure_free (subaction_struct);
|
||||
return res;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/* This is the main action execution function
|
||||
* it checks whether it is time to run the next action
|
||||
* and if it is the case executes it.
|
||||
|
@ -2620,7 +2610,6 @@ done:
|
|||
static gboolean
|
||||
execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||
{
|
||||
GList *tmp;
|
||||
gdouble rate = 1.0;
|
||||
GstClockTime position = -1;
|
||||
GstValidateAction *act = NULL;
|
||||
|
@ -2642,13 +2631,39 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
|||
if (scenario->priv->actions)
|
||||
act = scenario->priv->actions->data;
|
||||
|
||||
if (act) {
|
||||
if (!act)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS) {
|
||||
switch (act->priv->state) {
|
||||
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||
break;
|
||||
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||
GST_INFO_OBJECT (scenario, "Action %s:%d still running",
|
||||
GST_VALIDATE_ACTION_FILENAME (act), GST_VALIDATE_ACTION_LINENO (act));
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||
tmp = priv->actions;
|
||||
priv->actions = g_list_remove_link (priv->actions, tmp);
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ERROR:
|
||||
GST_VALIDATE_REPORT_ACTION (scenario, act,
|
||||
SCENARIO_ACTION_EXECUTION_ERROR, "Action %s failed", act->type);
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED:
|
||||
case GST_VALIDATE_EXECUTE_ACTION_OK:
|
||||
{
|
||||
gchar *repeat = NULL;
|
||||
|
||||
if (GST_VALIDATE_ACTION_N_REPEATS (act))
|
||||
repeat =
|
||||
g_strdup_printf ("[%d/%d]", act->repeat,
|
||||
GST_VALIDATE_ACTION_N_REPEATS (act));
|
||||
|
||||
gst_validate_printf (NULL,
|
||||
"%*c⇨ Action %s '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n",
|
||||
(act->priv->subaction_level * 2) - 1, ' ',
|
||||
gst_structure_get_name (act->priv->main_structure),
|
||||
gst_validate_action_return_get_name (act->priv->state),
|
||||
repeat ? repeat : "", GST_TIME_ARGS (act->priv->execution_duration));
|
||||
g_free (repeat);
|
||||
|
||||
priv->actions = g_list_remove (priv->actions, act);
|
||||
gst_validate_action_unref (act);
|
||||
|
||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
||||
gst_validate_error_structure (priv->actions ? priv->
|
||||
|
@ -2662,16 +2677,15 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
|||
GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now"
|
||||
" executing next", act->structure);
|
||||
|
||||
gst_validate_action_unref (act);
|
||||
g_list_free (tmp);
|
||||
|
||||
if (scenario->priv->actions) {
|
||||
act = scenario->priv->actions->data;
|
||||
} else {
|
||||
_check_scenario_is_done (scenario);
|
||||
act = NULL;
|
||||
}
|
||||
} else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
||||
break;
|
||||
}
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||
if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) {
|
||||
GstClockTime etime =
|
||||
gst_util_get_timestamp () - act->priv->execution_time;
|
||||
|
@ -2691,7 +2705,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
|||
act->structure);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (message) {
|
||||
|
@ -2721,68 +2736,25 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
|||
gst_structure_remove_field (act->structure, "on-message");
|
||||
|
||||
act->priv->state = gst_validate_execute_action (type, act);
|
||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) {
|
||||
gchar *str = gst_structure_to_string (act->structure);
|
||||
switch (act->priv->state) {
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||
GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action"
|
||||
" to be done.");
|
||||
|
||||
GST_VALIDATE_REPORT_ACTION (scenario, act,
|
||||
SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str);
|
||||
SCENARIO_LOCK (scenario);
|
||||
priv->execute_actions_source_id = 0;
|
||||
SCENARIO_UNLOCK (scenario);
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||
act->priv->state = _execute_sub_action_action (act);
|
||||
}
|
||||
|
||||
if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
||||
tmp = priv->actions;
|
||||
priv->actions = g_list_remove_link (priv->actions, tmp);
|
||||
|
||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
||||
gst_validate_error_structure (priv->actions ? priv->actions->data : NULL,
|
||||
"Could not determine next action playback time!");
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED)
|
||||
gst_validate_action_unref (act);
|
||||
else {
|
||||
return G_SOURCE_CONTINUE;
|
||||
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||
SCENARIO_LOCK (scenario);
|
||||
priv->interlaced_actions = g_list_append (priv->interlaced_actions, act);
|
||||
SCENARIO_UNLOCK (scenario);
|
||||
}
|
||||
|
||||
if (priv->actions == NULL)
|
||||
_check_scenario_is_done (scenario);
|
||||
|
||||
g_list_free (tmp);
|
||||
|
||||
/* Recurse to the next action if it is possible
|
||||
* to execute right away */
|
||||
if (!scenario->priv->execute_on_idle) {
|
||||
GST_DEBUG_OBJECT (scenario, "linking next action execution");
|
||||
|
||||
return execute_next_action (scenario);
|
||||
} else {
|
||||
_add_execute_actions_gsource (scenario);
|
||||
GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for"
|
||||
" next dispatch");
|
||||
|
||||
return gst_validate_scenario_execute_next_or_restart_looping (scenario);
|
||||
default:
|
||||
gst_validate_action_set_done (act);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action"
|
||||
" to be done.");
|
||||
|
||||
SCENARIO_LOCK (scenario);
|
||||
priv->execute_actions_source_id = 0;
|
||||
SCENARIO_UNLOCK (scenario);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -3157,6 +3129,24 @@ _execute_check_action_type_calls (GstValidateScenario * scenario,
|
|||
"%s called %d times instead of expected %d", type, t->priv->n_calls, n);
|
||||
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstValidateExecuteActionReturn
|
||||
_execute_check_subaction_level (GstValidateScenario * scenario,
|
||||
GstValidateAction * action)
|
||||
{
|
||||
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
gint n;
|
||||
|
||||
REPORT_UNLESS (gst_structure_get_int (action->structure, "level", &n),
|
||||
done, "No `n`!");
|
||||
REPORT_UNLESS (gst_validate_action_get_level (action) == n, done,
|
||||
"Expected subaction level %d, got %d", n,
|
||||
gst_validate_action_get_level (action));
|
||||
|
||||
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
@ -3679,7 +3669,9 @@ gst_validate_action_default_prepare_func (GstValidateAction * action)
|
|||
|
||||
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||
gst_structure_set (scenario->priv->vars,
|
||||
"repeat", G_TYPE_INT, action->repeat, NULL);
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) ?
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", G_TYPE_INT,
|
||||
action->repeat, NULL);
|
||||
gst_validate_structure_resolve_variables (action, action->structure,
|
||||
scenario->priv->vars);
|
||||
for (i = 0; type->parameters[i].name; i++) {
|
||||
|
@ -3710,6 +3702,136 @@ gst_validate_set_property_prepare_func (GstValidateAction * action)
|
|||
return gst_validate_action_default_prepare_func (action);
|
||||
}
|
||||
|
||||
static GList *
|
||||
add_gvalue_to_list_as_struct (gpointer source, GList * list, const GValue * v)
|
||||
{
|
||||
if (G_VALUE_HOLDS_STRING (v)) {
|
||||
GstStructure *structure =
|
||||
gst_structure_new_from_string (g_value_get_string (v));
|
||||
|
||||
if (!structure)
|
||||
gst_validate_error_structure (source, "Invalid structure: %s",
|
||||
g_value_get_string (v));
|
||||
|
||||
return g_list_append (list, structure);
|
||||
}
|
||||
|
||||
if (GST_VALUE_HOLDS_STRUCTURE (v))
|
||||
return g_list_append (list,
|
||||
gst_structure_copy (gst_value_get_structure (v)));
|
||||
|
||||
|
||||
gst_validate_error_structure (source, "Expected a string or a structure,"
|
||||
" got %s instead", gst_value_serialize (v));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GList *
|
||||
gst_validate_utils_get_structures (gpointer source,
|
||||
GstStructure * str, const gchar * fieldname)
|
||||
{
|
||||
guint i, size;
|
||||
GList *res = NULL;
|
||||
const GValue *value = gst_structure_get_value (str, fieldname);
|
||||
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (value) || GST_VALUE_HOLDS_STRUCTURE (value))
|
||||
return add_gvalue_to_list_as_struct (source, res, value);
|
||||
|
||||
if (!GST_VALUE_HOLDS_LIST (value)) {
|
||||
g_error ("%s must have type list of structure/string (or a string), "
|
||||
"e.g. %s={ [struct1, a=val1], [struct2, a=val2] }, got: \"%s\" in %s",
|
||||
fieldname, fieldname, gst_value_serialize (value),
|
||||
gst_structure_to_string (str));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = gst_value_list_get_size (value);
|
||||
for (i = 0; i < size; i++)
|
||||
res =
|
||||
add_gvalue_to_list_as_struct (source, res,
|
||||
gst_value_list_get_value (value, i));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstValidateExecuteActionReturn
|
||||
gst_validate_foreach_prepare (GstValidateAction * action)
|
||||
{
|
||||
gint it, i;
|
||||
gint min = 0, max = 1, step = 1;
|
||||
GstValidateScenario *scenario;
|
||||
GList *actions, *tmp;
|
||||
|
||||
scenario = gst_validate_action_get_scenario (action);
|
||||
g_assert (scenario);
|
||||
_update_well_known_vars (scenario);
|
||||
gst_validate_action_setup_repeat (scenario, action);
|
||||
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action) = NULL;
|
||||
gst_structure_foreach (action->structure,
|
||||
(GstStructureForeachFunc) _foreach_find_iterator, action);
|
||||
|
||||
/* Allow using the repeat field here too */
|
||||
if (!GST_VALIDATE_ACTION_RANGE_NAME (action)
|
||||
&& !GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||
gst_validate_error_structure (action, "Missing range specifier field.");
|
||||
|
||||
if (GST_VALIDATE_ACTION_RANGE_NAME (action)) {
|
||||
const GValue *range = gst_structure_get_value (action->structure,
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action));
|
||||
min = gst_value_get_int_range_min (range);
|
||||
max = gst_value_get_int_range_max (range);
|
||||
step = gst_value_get_int_range_step (range);
|
||||
|
||||
if (min % step != 0)
|
||||
gst_validate_error_structure (action,
|
||||
"Range min[%d] must be a multiple of step[%d].", min, step);
|
||||
|
||||
if (max % step != 0)
|
||||
gst_validate_error_structure (action,
|
||||
"Range max[%d] must be a multiple of step[%d].", max, step);
|
||||
} else {
|
||||
min = action->repeat;
|
||||
max = action->repeat + 1;
|
||||
}
|
||||
|
||||
actions = gst_validate_utils_get_structures (action, action->structure,
|
||||
"actions");
|
||||
i = g_list_index (scenario->priv->actions, action);
|
||||
for (it = min; it < max; it = it + step) {
|
||||
for (tmp = actions; tmp; tmp = tmp->next) {
|
||||
GstValidateAction *subaction;
|
||||
GstStructure *nstruct = gst_structure_copy (tmp->data);
|
||||
|
||||
subaction = gst_validate_action_new (scenario,
|
||||
_find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE);
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (subaction) =
|
||||
GST_VALIDATE_ACTION_RANGE_NAME (action);
|
||||
GST_VALIDATE_ACTION_FILENAME (subaction) =
|
||||
g_strdup (GST_VALIDATE_ACTION_FILENAME (action));
|
||||
GST_VALIDATE_ACTION_DEBUG (subaction) =
|
||||
g_strdup (GST_VALIDATE_ACTION_DEBUG (action));
|
||||
GST_VALIDATE_ACTION_LINENO (subaction) =
|
||||
GST_VALIDATE_ACTION_LINENO (action);
|
||||
subaction->repeat = it;
|
||||
subaction->priv->subaction_level = action->priv->subaction_level + 1;
|
||||
GST_VALIDATE_ACTION_N_REPEATS (subaction) = max;
|
||||
scenario->priv->actions =
|
||||
g_list_insert (scenario->priv->actions, subaction, i++);
|
||||
}
|
||||
}
|
||||
g_list_free_full (actions, (GDestroyNotify) gst_structure_free);
|
||||
|
||||
scenario->priv->actions = g_list_remove (scenario->priv->actions, action);
|
||||
gst_structure_remove_field (action->structure, "actions");
|
||||
|
||||
gst_object_unref (scenario);
|
||||
return GST_VALIDATE_EXECUTE_ACTION_SKIP;
|
||||
}
|
||||
|
||||
static void
|
||||
_check_waiting_for_message (GstValidateScenario * scenario,
|
||||
GstMessage * message)
|
||||
|
@ -4138,7 +4260,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario,
|
|||
}
|
||||
|
||||
gst_validate_error_structure (structure,
|
||||
"We do not handle action types %s", type);
|
||||
"Unknown action type: '%s'", type);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
@ -5635,13 +5757,13 @@ static gboolean
|
|||
_action_set_done (GstValidateAction * action)
|
||||
{
|
||||
JsonBuilder *jbuild;
|
||||
GstClockTime execution_duration;
|
||||
GstValidateScenario *scenario = gst_validate_action_get_scenario (action);
|
||||
|
||||
if (scenario == NULL || !action->priv->pending_set_done)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
execution_duration = gst_util_get_timestamp () - action->priv->execution_time;
|
||||
action->priv->execution_duration =
|
||||
gst_util_get_timestamp () - action->priv->execution_time;
|
||||
|
||||
jbuild = json_builder_new ();
|
||||
json_builder_begin_object (jbuild);
|
||||
|
@ -5651,25 +5773,27 @@ _action_set_done (GstValidateAction * action)
|
|||
json_builder_add_string_value (jbuild, action->type);
|
||||
json_builder_set_member_name (jbuild, "execution-duration");
|
||||
json_builder_add_double_value (jbuild,
|
||||
((gdouble) execution_duration / GST_SECOND));
|
||||
((gdouble) action->priv->execution_duration / GST_SECOND));
|
||||
json_builder_end_object (jbuild);
|
||||
|
||||
gst_validate_send (json_builder_get_root (jbuild));
|
||||
g_object_unref (jbuild);
|
||||
|
||||
gst_validate_printf (NULL, " -> Action %s done (duration: %" GST_TIME_FORMAT
|
||||
")\n", action->type, GST_TIME_ARGS (execution_duration));
|
||||
action->priv->execution_time = GST_CLOCK_TIME_NONE;
|
||||
action->priv->state = _execute_sub_action_action (action);
|
||||
|
||||
if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
||||
|
||||
GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC");
|
||||
execute_next_action (scenario);
|
||||
}
|
||||
gst_object_unref (scenario);
|
||||
|
||||
action->priv->pending_set_done = FALSE;
|
||||
switch (action->priv->state) {
|
||||
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||
action->priv->state = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gst_structure_free (action->structure);
|
||||
action->structure = gst_structure_copy (action->priv->main_structure);
|
||||
gst_validate_scenario_execute_next_or_restart_looping (scenario);
|
||||
gst_object_unref (scenario);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
@ -6844,9 +6968,25 @@ register_action_types (void)
|
|||
}),
|
||||
"Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE);
|
||||
|
||||
REGISTER_ACTION_TYPE("foreach", NULL,
|
||||
((GstValidateActionParameter[]) {
|
||||
{ .name = "actions",
|
||||
.description = "The array of actions to repeat",
|
||||
.mandatory = TRUE,
|
||||
.types = "strv",
|
||||
NULL },
|
||||
{ NULL } }),
|
||||
"Run actions defined in the `actions` array the number of times specified\n"
|
||||
" with a GstIntRange `i=[start, end, step]` parameter passed in, one and only\n"
|
||||
" range is required as parameter.",
|
||||
GST_VALIDATE_ACTION_TYPE_NONE);
|
||||
type->prepare = gst_validate_foreach_prepare;
|
||||
|
||||
/* Internal actions types to test the validate scenario implementation */
|
||||
REGISTER_ACTION_TYPE("priv_check-action-type-calls",
|
||||
_execute_check_action_type_calls, NULL, NULL, 0);
|
||||
REGISTER_ACTION_TYPE("priv_check-subaction-level",
|
||||
_execute_check_subaction_level, NULL, NULL, 0);
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,11 @@ typedef enum
|
|||
GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED,
|
||||
GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS,
|
||||
GST_VALIDATE_EXECUTE_ACTION_NONE,
|
||||
GST_VALIDATE_EXECUTE_ACTION_SKIP,
|
||||
} GstValidateActionReturn;
|
||||
|
||||
const gchar *gst_validate_action_return_get_name (GstValidateActionReturn r);
|
||||
|
||||
/* TODO 2.0 -- Make it an actual enum type */
|
||||
#define GstValidateExecuteActionReturn gint
|
||||
|
||||
|
@ -93,6 +96,7 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate;
|
|||
#define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename)
|
||||
#define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug)
|
||||
#define GST_VALIDATE_ACTION_N_REPEATS(action) (((GstValidateAction*) action)->ABI.abi.n_repeats)
|
||||
#define GST_VALIDATE_ACTION_RANGE_NAME(action) (((GstValidateAction*) action)->ABI.abi.rangename)
|
||||
|
||||
/**
|
||||
* GstValidateAction:
|
||||
|
@ -133,6 +137,7 @@ struct _GstValidateAction
|
|||
gchar *filename;
|
||||
gchar *debug;
|
||||
gint n_repeats;
|
||||
const gchar *rangename;
|
||||
} abi;
|
||||
} ABI;
|
||||
};
|
||||
|
|
47
validate/tests/launcher_tests/foreach.validatetest
Normal file
47
validate/tests/launcher_tests/foreach.validatetest
Normal file
|
@ -0,0 +1,47 @@
|
|||
meta,
|
||||
handles-states=true,
|
||||
args = {
|
||||
"videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||
},
|
||||
expected-issues = {
|
||||
"expected-issue,
|
||||
level=critical,
|
||||
issue-id=scenario::execution-error,
|
||||
details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"",
|
||||
"expected-issue,
|
||||
level=critical,
|
||||
issue-id=scenario::execution-error,
|
||||
details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"",
|
||||
}
|
||||
|
||||
pause;
|
||||
|
||||
foreach, n=[0, 2],
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"check-position, expected-position=\"expr($(n)*0.01)\"", # expected to fail
|
||||
}
|
||||
|
||||
priv_check-action-type-calls, type=seek, n=2
|
||||
priv_check-action-type-calls, type=check-position, n=2
|
||||
|
||||
foreach, n=[0, 6],
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"check-position, expected-position=\"expr((3 + $(n)) * 0.1)\"",
|
||||
}
|
||||
|
||||
priv_check-action-type-calls, type=seek, n=8
|
||||
priv_check-action-type-calls, type=check-position, n=8
|
||||
check-position, expected-position=0.8
|
||||
|
||||
foreach, n=[9, 11],
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"check-position, expected-position=\"expr($(n)*0.1)\"",
|
||||
}
|
||||
priv_check-action-type-calls, type=seek, n=10
|
||||
# We called it once manually
|
||||
priv_check-action-type-calls, type=check-position, n=11
|
||||
check-position, expected-position=1.0
|
||||
stop
|
|
@ -0,0 +1,24 @@
|
|||
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
|
||||
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
|
||||
event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive;
|
||||
event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive;
|
||||
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
|
||||
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
|
||||
buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||
buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||
event flush-start: (no structure)
|
||||
event flush-start: (no structure)
|
||||
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||
event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000
|
||||
event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000
|
||||
buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||
buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||
event flush-start: (no structure)
|
||||
event flush-start: (no structure)
|
||||
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||
event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000
|
||||
event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000
|
||||
buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||
buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
51
validate/tests/launcher_tests/foreach_deep.validatetest
Normal file
51
validate/tests/launcher_tests/foreach_deep.validatetest
Normal file
|
@ -0,0 +1,51 @@
|
|||
meta,
|
||||
handles-states=true,
|
||||
args = {
|
||||
"videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||
},
|
||||
expected-issues = {
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"",
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"",
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Expected subaction level 4, got 3\"",
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Expected subaction level 4, got 3\"",
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Expected subaction level 5, got 4\"",
|
||||
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||
details=\"Expected subaction level 5, got 4\"",
|
||||
}
|
||||
|
||||
pause;
|
||||
|
||||
|
||||
foreach, n=[0, 2],
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"check-position, expected-position=\"expr($(n)*0.01)\"", # Expected failling subaction!
|
||||
}
|
||||
|
||||
priv_check-action-type-calls, type=seek, n=2
|
||||
priv_check-action-type-calls, type=check-position, n=2
|
||||
|
||||
foreach, n=[0, 2],
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"priv_check-subaction-level, level=1",
|
||||
"foreach, n=[0, 1],
|
||||
actions={
|
||||
\"priv_check-subaction-level, level=2\",
|
||||
\"foreach, j=[0, 1], actions={
|
||||
\\\"priv_check-subaction-level, level=4\\\", # Failling... twice
|
||||
\\\"priv_check-subaction-level, level=3\\\",
|
||||
\\\"foreach, j=[0, 1], actions={
|
||||
\\\\\\\"priv_check-subaction-level, level=4\\\\\\\",
|
||||
\\\\\\\"priv_check-subaction-level, level=5\\\\\\\", # Failling... twice
|
||||
}\\\",
|
||||
}\",
|
||||
}",
|
||||
}
|
||||
priv_check-action-type-calls, type=seek, n=4
|
||||
stop
|
31
validate/tests/launcher_tests/foreach_repeat.validatetest
Normal file
31
validate/tests/launcher_tests/foreach_repeat.validatetest
Normal file
|
@ -0,0 +1,31 @@
|
|||
meta,
|
||||
handles-states=true,
|
||||
args = {
|
||||
"videotestsrc name=src pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||
}
|
||||
|
||||
pause;
|
||||
|
||||
foreach, repeat="max(1, 2)",
|
||||
actions = {
|
||||
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||
"check-position, expected-position=\"expr((1+$(repeat))*0.1)\"",
|
||||
}
|
||||
|
||||
priv_check-action-type-calls, type=seek, n=2
|
||||
priv_check-action-type-calls, type=check-position, n=2
|
||||
|
||||
foreach,
|
||||
repeat=2,
|
||||
pattern=[0, 10, 5],
|
||||
actions = {
|
||||
"set-properties, src::horizontal-speed=\"$(pattern)\"",
|
||||
"check-properties, src::horizontal-speed=\"$(pattern)\"",
|
||||
}
|
||||
|
||||
check-properties, src::horizontal-speed=5
|
||||
priv_check-action-type-calls, type=set-properties, n=4
|
||||
priv_check-action-type-calls, type=check-properties, n=5
|
||||
priv_check-action-type-calls, type=seek, n=2
|
||||
priv_check-action-type-calls, type=check-position, n=2
|
||||
stop
|
Loading…
Reference in a new issue