[PATCH 3/6] quartz/tests: Add some tests for filter states.

Zebediah Figura z.figura12 at gmail.com
Tue Sep 25 23:30:20 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/quartz/tests/filtergraph.c | 276 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 268 insertions(+), 8 deletions(-)

diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 54afb8a..8dc7341 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -1133,6 +1133,8 @@ struct testfilter
     IFilterGraph *graph;
     WCHAR *name;
     IReferenceClock *clock;
+    FILTER_STATE state;
+    REFERENCE_TIME start_time;
 
     IEnumPins IEnumPins_iface;
     struct testpin *pins;
@@ -1255,28 +1257,73 @@ static HRESULT WINAPI testfilter_GetClassID(IBaseFilter *iface, CLSID *clsid)
     return S_OK;
 }
 
+/* Downstream filters are always stopped before any filters they are connected
+ * to upstream. Native actually implements this by topologically sorting filters
+ * as they are connected. */
+static void check_state_transition(struct testfilter *filter, FILTER_STATE expect)
+{
+    FILTER_STATE state;
+    unsigned int i;
+    PIN_INFO info;
+
+    for (i = 0; i < filter->pin_count; ++i)
+    {
+        if (filter->pins[i].peer)
+        {
+            IPin_QueryPinInfo(filter->pins[i].peer, &info);
+            IBaseFilter_GetState(info.pFilter, 0, &state);
+            if (filter->pins[i].dir == PINDIR_OUTPUT)
+                ok(state == expect, "Expected state %d for downstream filter %p, got %d.\n",
+                        expect, info.pFilter, state);
+            else
+                ok(state == filter->state, "Expected state %d for upstream filter %p, got %d.\n",
+                        filter->state, info.pFilter, state);
+            IBaseFilter_Release(info.pFilter);
+        }
+    }
+}
+
 static HRESULT WINAPI testfilter_Stop(IBaseFilter *iface)
 {
-    if (winetest_debug > 1) trace("%p->Stop()\n", iface);
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IBaseFilter(iface);
+    if (winetest_debug > 1) trace("%p->Stop()\n", filter);
+
+    check_state_transition(filter, State_Stopped);
+
+    filter->state = State_Stopped;
+    return S_OK;
 }
 
 static HRESULT WINAPI testfilter_Pause(IBaseFilter *iface)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IBaseFilter(iface);
+    if (winetest_debug > 1) trace("%p->Pause()\n", filter);
+
+    check_state_transition(filter, State_Paused);
+
+    filter->state = State_Paused;
+    return S_OK;
 }
 
 static HRESULT WINAPI testfilter_Run(IBaseFilter *iface, REFERENCE_TIME start)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IBaseFilter(iface);
+    if (winetest_debug > 1) trace("%p->Run(%s)\n", filter, wine_dbgstr_longlong(start));
+
+    check_state_transition(filter, State_Running);
+
+    filter->state = State_Running;
+    filter->start_time = start;
+    return S_OK;
 }
 
 static HRESULT WINAPI testfilter_GetState(IBaseFilter *iface, DWORD timeout, FILTER_STATE *state)
 {
-    if (winetest_debug > 1) trace("%p->GetState()\n", iface);
-    return E_NOTIMPL;
+    struct testfilter *filter = impl_from_IBaseFilter(iface);
+    if (winetest_debug > 1) trace("%p->GetState(%u)\n", filter, timeout);
+
+    *state = filter->state;
+    return S_OK;
 }
 
 static HRESULT WINAPI testfilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
@@ -1389,6 +1436,7 @@ static void testfilter_init(struct testfilter *filter, struct testpin *pins, int
     filter->pin_count = pin_count;
     for (i = 0; i < pin_count; i++)
         pins[i].filter = &filter->IBaseFilter_iface;
+    filter->state = State_Stopped;
 }
 
 static HRESULT WINAPI testfilter_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out)
@@ -2512,6 +2560,217 @@ todo_wine
     ok(filter2.ref == 1, "Got outstanding refcount %d.\n", filter2.ref);
 }
 
+#define check_filter_state(a, b) check_filter_state_(__LINE__, a, b)
+static void check_filter_state_(unsigned int line, IFilterGraph2 *graph, FILTER_STATE expect)
+{
+    IMediaFilter *mediafilter;
+    IEnumFilters *filterenum;
+    IMediaControl *control;
+    OAFilterState oastate;
+    IBaseFilter *filter;
+    FILTER_STATE state;
+    HRESULT hr;
+
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&mediafilter);
+    hr = IMediaFilter_GetState(mediafilter, 1000, &state);
+    ok_(__FILE__, line)(hr == S_OK, "IMediaFilter_GetState() returned %#x.\n", hr);
+    ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
+    IMediaFilter_Release(mediafilter);
+
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+    hr = IMediaControl_GetState(control, 1000, &oastate);
+    ok_(__FILE__, line)(hr == S_OK, "IMediaControl_GetState() returned %#x.\n", hr);
+    ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
+    IMediaControl_Release(control);
+
+    IFilterGraph2_EnumFilters(graph, &filterenum);
+    while (IEnumFilters_Next(filterenum, 1, &filter, NULL) == S_OK)
+    {
+        hr = IBaseFilter_GetState(filter, 1000, &state);
+        ok_(__FILE__, line)(hr == S_OK, "IBaseFilter_GetState() returned %#x.\n", hr);
+        ok_(__FILE__, line)(state == expect, "Expected state %u, got %u.\n", expect, state);
+        IBaseFilter_Release(filter);
+    }
+    IEnumFilters_Release(filterenum);
+}
+
+
+static void test_filter_state(void)
+{
+    struct testpin source_pin, sink_pin;
+    struct testfilter source, sink;
+
+    IFilterGraph2 *graph = create_graph();
+    REFERENCE_TIME start_time;
+    IReferenceClock *clock;
+    IMediaControl *control;
+    IMediaFilter *filter;
+    HRESULT hr;
+    ULONG ref;
+
+    testsource_init(&source_pin, NULL, 0);
+    testsink_init(&sink_pin);
+    testfilter_init(&source, &source_pin, 1);
+    testfilter_init(&sink, &sink_pin, 1);
+
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+
+    source_pin.filter = &source.IBaseFilter_iface;
+    sink_pin.filter = &sink.IBaseFilter_iface;
+
+    IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
+
+    check_filter_state(graph, State_Stopped);
+
+    hr = IMediaControl_Pause(control);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Paused);
+
+    /* Pausing sets the default sync source, if it's not already set. */
+
+    hr = IMediaFilter_GetSyncSource(filter, &clock);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(!!clock, "Reference clock not set.\n");
+    ok(source.clock == clock, "Expected %p, got %p.\n", clock, source.clock);
+    ok(sink.clock == clock, "Expected %p, got %p.\n", clock, sink.clock);
+
+    hr = IReferenceClock_GetTime(clock, &start_time);
+    ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
+    hr = IMediaControl_Run(control);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+    ok(source.start_time >= start_time && source.start_time < start_time + 500 * 10000,
+        "Expected time near %s, got %s.\n",
+        wine_dbgstr_longlong(start_time), wine_dbgstr_longlong(source.start_time));
+    ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
+        wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
+
+    hr = IMediaControl_Pause(control);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Paused);
+
+    hr = IMediaControl_Stop(control);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Stopped);
+
+    hr = IMediaControl_Run(control);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+
+    hr = IMediaControl_Stop(control);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Stopped);
+
+    IReferenceClock_Release(clock);
+    IMediaFilter_Release(filter);
+    IMediaControl_Release(control);
+    IFilterGraph2_Release(graph);
+
+    /* Test same methods using IMediaFilter. */
+
+    graph = create_graph();
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
+    IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+
+    IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
+    IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
+
+    hr = IMediaFilter_Pause(filter);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Paused);
+
+    hr = IMediaFilter_GetSyncSource(filter, &clock);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(!!clock, "Reference clock not set.\n");
+    ok(source.clock == clock, "Expected %p, got %p.\n", clock, source.clock);
+    ok(sink.clock == clock, "Expected %p, got %p.\n", clock, sink.clock);
+
+    hr = IMediaFilter_Run(filter, 0xdeadbeef);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+todo_wine {
+    ok(source.start_time == 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(source.start_time));
+    ok(sink.start_time == 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(sink.start_time));
+}
+
+    hr = IMediaFilter_Pause(filter);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Paused);
+
+    hr = IMediaFilter_Stop(filter);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Stopped);
+
+    hr = IReferenceClock_GetTime(clock, &start_time);
+    ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
+    hr = IMediaFilter_Run(filter, 0);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+    ok(source.start_time >= start_time && source.start_time < start_time + 500 * 10000,
+        "Expected time near %s, got %s.\n",
+        wine_dbgstr_longlong(start_time), wine_dbgstr_longlong(source.start_time));
+    ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
+        wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
+
+    hr = IMediaFilter_Stop(filter);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Stopped);
+
+    /* Test removing the sync source. */
+
+    IReferenceClock_Release(clock);
+    IMediaFilter_SetSyncSource(filter, NULL);
+
+    hr = IMediaControl_Run(control);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+todo_wine
+    ok(source.start_time > 0 && source.start_time < 500 * 10000,
+        "Got time %s.\n", wine_dbgstr_longlong(source.start_time));
+    ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
+        wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
+
+    hr = IMediaControl_Stop(control);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Stopped);
+
+    /* Destroying the graph while it's running stops all filters. */
+
+    hr = IMediaFilter_Run(filter, 0);
+todo_wine
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    check_filter_state(graph, State_Running);
+todo_wine
+    ok(source.start_time > 0 && source.start_time < 500 * 10000,
+        "Got time %s.\n", wine_dbgstr_longlong(source.start_time));
+    ok(sink.start_time == source.start_time, "Expected time %s, got %s.\n",
+        wine_dbgstr_longlong(source.start_time), wine_dbgstr_longlong(sink.start_time));
+
+    IMediaFilter_Release(filter);
+    IMediaControl_Release(control);
+    ref = IFilterGraph2_Release(graph);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+    ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref);
+    ok(sink.ref == 1, "Got outstanding refcount %d.\n", sink.ref);
+    ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref);
+    ok(sink_pin.ref == 1, "Got outstanding refcount %d.\n", sink_pin.ref);
+    ok(source.state == State_Stopped, "Got state %u.\n", source.state);
+    ok(sink.state == State_Stopped, "Got state %u.\n", sink.state);
+}
+
 START_TEST(filtergraph)
 {
     CoInitializeEx(NULL, COINIT_MULTITHREADED);
@@ -2527,6 +2786,7 @@ START_TEST(filtergraph)
     test_add_remove_filter();
     test_connect_direct();
     test_sync_source();
+    test_filter_state();
 
     CoUninitialize();
     test_render_with_multithread();
-- 
2.7.4




More information about the wine-devel mailing list