Packages
membrane_core
0.4.1
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.7
1.2.6
1.2.5
retired
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc1
1.1.2
1.1.1
1.1.0
1.1.0-rc1
1.1.0-rc0
1.0.1
1.0.0
1.0.0-rc1
1.0.0-rc0
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
retired
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Membrane Multimedia Framework (Core)
Current section
Files
Jump to
Current section
Files
lib/membrane/testing/assertions.ex
defmodule Membrane.Testing.Assertions do
@moduledoc """
This module contains a set of assertion functions and macros.
These assertions will work ONLY in conjunction with
`Membrane.Testing.Pipeline` and ONLY when pid of tested pipeline is provided
as an argument to these assertions.
"""
@default_timeout 2000
defp do_assert_receive_from_pipeline(assertion, pid, pattern, timeout, failure_message) do
quote do
import ExUnit.Assertions
pid_value = unquote(pid)
unquote(assertion)(
{Membrane.Testing.Pipeline, ^pid_value, unquote(pattern)},
unquote(timeout),
unquote(failure_message)
)
end
end
defp assert_receive_from_pipeline(pid, pattern, timeout, failure_message \\ nil) do
do_assert_receive_from_pipeline(:assert_receive, pid, pattern, timeout, failure_message)
end
defp refute_receive_from_pipeline(pid, pattern, timeout, failure_message \\ nil) do
do_assert_receive_from_pipeline(:refute_receive, pid, pattern, timeout, failure_message)
end
@doc """
Asserts that pipeline received or will receive a notification from the element
with name `element_name` within the `timeout` period specified in milliseconds.
The `notification_pattern` must be a match pattern.
assert_pipeline_notified(pipeline, :element_name, :hi)
"""
defmacro assert_pipeline_notified(
pipeline,
element_name,
notification_pattern,
timeout \\ @default_timeout
) do
quote do
element_name_value = unquote(element_name)
unquote(
assert_receive_from_pipeline(
pipeline,
{:handle_notification,
{notification_pattern,
quote do
^element_name_value
end}},
timeout
)
)
end
end
@doc """
Asserts that pipeline's playback state (see `Membrane.PlaybackState`)
changed or will change from `previous_state` to `current_state` within
the `timeout` period specified in milliseconds.
The `prev_state` and `current_state` must be match patterns.
Assertion can be either made by providing state before and after the change as
atoms:
assert_pipeline_playback_changed(pipeline, :prepared, :playing)
Or by using an `_` to assert on change from any state to other:
assert_pipeline_playback_changed(pipeline, _, :playing)
"""
defmacro assert_pipeline_playback_changed(
pipeline,
previous_state,
current_state,
timeout \\ @default_timeout
) do
with :ok <- validate_playback_change(previous_state, current_state) do
pattern =
quote do: {:playback_state_changed, unquote(previous_state), unquote(current_state)}
assert_receive_from_pipeline(pipeline, pattern, timeout, nil)
else
{:error, flunk} -> flunk
end
end
defp validate_playback_change(previous_state, current_state) do
valid_changes = [
{:stopped, :prepared},
{:prepared, :playing},
{:playing, :prepared},
{:prepared, :stopped}
]
are_arguments_values = is_atom(previous_state) and is_atom(current_state)
if are_arguments_values and {previous_state, current_state} not in valid_changes do
transitions =
Enum.map(valid_changes, fn {from, to} ->
" " <> to_string(from) <> " -> " <> to_string(to)
end)
|> Enum.join("\n")
message = """
Transition from #{previous_state} to #{current_state} is not valid.
Valid transitions are:
#{transitions}
"""
flunk = quote do: flunk(unquote(message))
{:error, flunk}
else
:ok
end
end
@doc """
Asserts that pipeline received or will receive a message matching
`message_pattern` from another process within the `timeout` period specified
in milliseconds.
The `message_pattern` must be a match pattern.
assert_pipeline_receive(pid, :tick)
Such call would flunk if the message `:tick` has not been handled by
`c:Membrane.Pipeline.handle_other/2` within the `timeout`.
"""
defmacro assert_pipeline_receive(pipeline, message_pattern, timeout \\ @default_timeout) do
do_pipeline_receive(&assert_receive_from_pipeline/3, pipeline, message_pattern, timeout)
end
@doc """
Asserts that pipeline has not received and will not receive a message from
another process matching `message_pattern` within the `timeout` period
specified in milliseconds.
The `message_pattern` must be a match pattern.
refute_pipeline_receive(pid, :tick)
Such call would flunk if the message `:tick` has been handled by
`c:Membrane.Pipeline.handle_other/2`.
"""
defmacro refute_pipeline_receive(pipeline, message_pattern, timeout \\ @default_timeout) do
do_pipeline_receive(&refute_receive_from_pipeline/3, pipeline, message_pattern, timeout)
end
defp do_pipeline_receive(assertion, pipeline, message_pattern, timeout) do
assertion.(pipeline, {:handle_other, message_pattern}, timeout)
end
@doc """
Asserts that `Membrane.Testing.Sink` with name `sink_name` received or will
receive caps matching `pattern` within the `timeout` period specified in
milliseconds.
When the `Membrane.Testing.Sink` is a part of `Membrane.Testing.Pipeline` you
can assert whether it received caps matching provided pattern.
{:ok, pid} = Membrane.Testing.Pipeline.start_link(%Membrane.Testing.Pipeline.Options{
elements: [
....,
the_sink: %Membrane.Testing.Sink{}
]
})
You can match for exact value:
assert_sink_caps(pid, :the_sink , %Caps{prop: ^value})
You can also use pattern to extract data from the caps:
assert_sink_caps(pid, :the_sink , %Caps{prop: value})
do_something(value)
"""
defmacro assert_sink_caps(pipeline, element_name, caps_pattern, timeout \\ @default_timeout) do
do_sink_caps(&assert_receive_from_pipeline/3, pipeline, element_name, caps_pattern, timeout)
end
@doc """
Asserts that `Membrane.Testing.Sink` with name `sink_name` has not received
and will not receive caps matching `caps_pattern` within the `timeout`
period specified in milliseconds.
Similarly as in the `assert_sink_caps/4` `the_sink` needs to be part of a
`Membrane.Testing.Pipeline`.
refute_sink_caps(pipeline, :the_sink, %Caps{prop: ^val})
Such expression will flunk if `the_sink` received or will receive caps with
property equal to value of `val` variable.
"""
defmacro refute_sink_caps(pipeline, element_name, caps_pattern, timeout \\ @default_timeout) do
do_sink_caps(&refute_receive_from_pipeline/3, pipeline, element_name, caps_pattern, timeout)
end
defp do_sink_caps(assertion, pipeline, sink_name, caps, timeout) do
quote do
element_name_value = unquote(sink_name)
unquote(
assertion.(
pipeline,
{:handle_notification,
{quote do
{:caps, :input, unquote(caps)}
end,
quote do
^element_name_value
end}},
timeout
)
)
end
end
@doc """
Asserts that `Membrane.Testing.Sink` with name `sink_name` received or will
receive a buffer matching `pattern` within the `timeout` period specified in
milliseconds.
When the `Membrane.Testing.Sink` is a part of `Membrane.Testing.Pipeline` you
can assert whether it received a buffer matching provided pattern.
{:ok, pid} = Membrane.Testing.Pipeline.start_link(%Membrane.Testing.Pipeline.Options{
elements: [
....,
the_sink: %Membrane.Testing.Sink{}
]
})
You can match for exact value:
assert_sink_buffer(pid, :the_sink ,%Membrane.Buffer{payload: ^specific_payload})
You can also use pattern to extract data from the buffer:
assert_sink_buffer(pid, :sink, %Buffer{payload: <<data::16>> <> <<255>>})
do_something(data)
"""
defmacro assert_sink_buffer(pipeline, sink_name, pattern, timeout \\ @default_timeout) do
do_sink_buffer(&assert_receive_from_pipeline/3, pipeline, sink_name, pattern, timeout)
end
@doc """
Asserts that `Membrane.Testing.Sink` with name `sink_name` has not received
and will not receive a buffer matching `buffer_pattern` within the `timeout`
period specified in milliseconds.
Similarly as in the `assert_sink_buffer/4` `the_sink` needs to be part of a
`Membrane.Testing.Pipeline`.
refute_sink_buffer(pipeline, :the_sink, %Buffer{payload: <<0xA1, 0xB2>>})
Such expression will flunk if `the_sink` received or will receive a buffer
with payload `<<0xA1, 0xB2>>`.
"""
defmacro refute_sink_buffer(pipeline, sink_name, pattern, timeout \\ @default_timeout) do
do_sink_buffer(&refute_receive_from_pipeline/3, pipeline, sink_name, pattern, timeout)
end
defp do_sink_buffer(assertion, pipeline, sink_name, pattern, timeout) do
quote do
element_name_value = unquote(sink_name)
unquote(
assertion.(
pipeline,
{:handle_notification,
{{:buffer, pattern},
quote do
^element_name_value
end}},
timeout
)
)
end
end
@doc """
Asserts that `Membrane.Testing.Sink` with name `sink_name` received or will
receive an event within the `timeout` period specified in milliseconds.
When a `Membrane.Testing.Sink` is part of `Membrane.Testing.Pipeline` you can
assert whether it received an event matching a provided pattern.
assert_sink_event(pid, :the_sink, %Discontinuity{})
"""
defmacro assert_sink_event(pipeline, sink_name, event, timeout \\ @default_timeout) do
do_sink_event(&assert_receive_from_pipeline/3, pipeline, sink_name, event, timeout)
end
@doc """
Asserts that `Membrane.Testing.Sink` has not received and will not receive
event matching provided pattern within the `timeout` period specified in
milliseconds.
refute_sink_event(pid, :the_sink, %Discontinuity{})
"""
defmacro refute_sink_event(pipeline, sink_name, event, timeout \\ @default_timeout) do
do_sink_event(&refute_receive_from_pipeline/3, pipeline, sink_name, event, timeout)
end
defp do_sink_event(assertion, pipeline, sink_name, event, timeout) do
quote do
element_name_value = unquote(sink_name)
unquote(
assertion.(
pipeline,
{:handle_notification,
{{:event, event},
quote do
^element_name_value
end}},
timeout
)
)
end
end
@doc """
Asserts that `Membrane.Testing.Pipeline` received or is going to receive start_of_stream
notification from the element with a name `element_name` within the `timeout` period
specified in milliseconds.
assert_start_of_stream(pipeline, :an_element)
"""
defmacro assert_start_of_stream(
pipeline,
element_name,
pad \\ :input,
timeout \\ @default_timeout
) do
assert_receive_from_pipeline(
pipeline,
{:handle_element_start_of_stream, {element_name, pad}},
timeout
)
end
@doc """
Asserts that `Membrane.Testing.Pipeline` received or is going to receive end_of_stream
notification about from the element with a name `element_name` within the `timeout` period
specified in milliseconds.
assert_end_of_stream(pipeline, :an_element)
"""
defmacro assert_end_of_stream(
pipeline,
element_name,
pad \\ :input,
timeout \\ @default_timeout
) do
assert_receive_from_pipeline(
pipeline,
{:handle_element_end_of_stream, {element_name, pad}},
timeout
)
end
end