From a409daf2170c006860562f88eacebc3b8dd11b61 Mon Sep 17 00:00:00 2001
From: David Adam <david.adam.cnrs@gmail.com>
Date: Tue, 2 Apr 2019 18:41:48 -1000
Subject: [PATCH 1/4] Port Enumdevices tests to ddraw7

Signed-off-by: David Adam <david.adam.cnrs@gmail.com>
---
 dlls/ddraw/tests/ddraw7.c | 213 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 213 insertions(+)

diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 423dba57c9..9a663c2833 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -15822,6 +15822,217 @@ static void test_clipper_refcount(void)
     DestroyWindow(window);
 }
 
+typedef struct {
+    int total;
+    int rgb;
+    int hal;
+    int tnlhal;
+    int unk;
+} D3D7ETest;
+
+typedef struct {
+    HRESULT desired_ret;
+    int total;
+} D3D7ECancelTest;
+
+#define MAX_ENUMERATION_COUNT 10
+typedef struct
+{
+    unsigned int count;
+    char *callback_description_ptrs[MAX_ENUMERATION_COUNT];
+    char callback_description_strings[MAX_ENUMERATION_COUNT][100];
+    char *callback_name_ptrs[MAX_ENUMERATION_COUNT];
+    char callback_name_strings[MAX_ENUMERATION_COUNT][100];
+} D3D7ELifetimeTest;
+
+static HRESULT WINAPI enumDevicesCallbackTest7(char *DeviceDescription, char *DeviceName,
+        D3DDEVICEDESC7 *lpdd7, void *Context)
+{
+    D3D7ETest *d3d7et = Context;
+
+    if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DRGBDevice))
+        d3d7et->rgb++;
+    else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DHALDevice))
+        d3d7et->hal++;
+    else if(IsEqualGUID(&lpdd7->deviceGUID, &IID_IDirect3DTnLHalDevice))
+        d3d7et->tnlhal++;
+    else
+        d3d7et->unk++;
+
+    d3d7et->total++;
+
+    return DDENUMRET_OK;
+}
+
+static HRESULT WINAPI enumDevicesCancelTest7(char *DeviceDescription, char *DeviceName,
+        D3DDEVICEDESC7 *lpdd7, void *Context)
+{
+    D3D7ECancelTest *d3d7et = Context;
+
+    d3d7et->total++;
+
+    return d3d7et->desired_ret;
+}
+
+static HRESULT WINAPI enumDevicesLifetimeTest7(char *DeviceDescription, char *DeviceName,
+        D3DDEVICEDESC7 *lpdd7, void *Context)
+{
+    D3D7ELifetimeTest *ctx = Context;
+
+    if (ctx->count == MAX_ENUMERATION_COUNT)
+    {
+        ok(0, "Enumerated too many devices for context in callback\n");
+        return DDENUMRET_CANCEL;
+    }
+
+    ctx->callback_description_ptrs[ctx->count] = DeviceDescription;
+    strcpy(ctx->callback_description_strings[ctx->count], DeviceDescription);
+    ctx->callback_name_ptrs[ctx->count] = DeviceName;
+    strcpy(ctx->callback_name_strings[ctx->count], DeviceName);
+
+    ctx->count++;
+    return DDENUMRET_OK;
+}
+
+/*  Check the deviceGUID of devices enumerated by
+    IDirect3D7_EnumDevices. */
+static void test_enum_devices(void)
+{
+    IDirectDraw7 *ddraw;
+    IDirect3D7 *d3d7;
+    HRESULT hr;
+    D3D7ETest d3d7et;
+    D3D7ECancelTest d3d7_cancel_test;
+
+    if (!(ddraw = create_ddraw()))
+        return;
+
+    hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d7);
+    IDirectDraw7_Release(ddraw);
+    if (FAILED(hr))
+    {
+        return;
+    }
+
+    hr = IDirect3D7_EnumDevices(d3d7, NULL, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    memset(&d3d7et, 0, sizeof(d3d7et));
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesCallbackTest7, &d3d7et);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    /* A couple of games (Delta Force LW and TFD) rely on this behaviour */
+    ok(d3d7et.tnlhal < d3d7et.total, "TnLHal device enumerated as only device.\n");
+
+    /* We make two additional assumptions. */
+    ok(d3d7et.rgb, "No RGB Device enumerated.\n");
+
+    if(d3d7et.tnlhal)
+        ok(d3d7et.hal, "TnLHal device enumerated, but no Hal device found.\n");
+
+    d3d7_cancel_test.desired_ret = DDENUMRET_CANCEL;
+    d3d7_cancel_test.total = 0;
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesCancelTest7, &d3d7_cancel_test);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    ok(d3d7_cancel_test.total == 1, "Enumerated a total of %u devices\n",
+       d3d7_cancel_test.total);
+
+    /* An enumeration callback can return any value besides DDENUMRET_OK to stop enumeration. */
+    d3d7_cancel_test.desired_ret = E_INVALIDARG;
+    d3d7_cancel_test.total = 0;
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesCancelTest7, &d3d7_cancel_test);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    ok(d3d7_cancel_test.total == 1, "Enumerated a total of %u devices\n",
+       d3d7_cancel_test.total);
+
+    IDirect3D7_Release(d3d7);
+}
+
+static void test_enum_devices_life_time(void)
+{
+    IDirectDraw7 *ddraw;
+    IDirect3D7 *d3d7;
+    HRESULT hr;
+    D3D7ELifetimeTest ctx, ctx2;
+    unsigned int i;
+
+    if (!(ddraw = create_ddraw()))
+        return;
+
+    hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d7);
+    IDirectDraw7_Release(ddraw);
+    if (FAILED(hr))
+    {
+        return;
+    }
+
+    ctx.count = 0;
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesLifetimeTest7, &ctx);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    /* The enumeration strings remain valid even after IDirect3D7_EnumDevices finishes. */
+    for (i = 0; i < ctx.count; i++)
+    {
+        ok(!strcmp(ctx.callback_description_ptrs[i], ctx.callback_description_strings[i]),
+           "Got '%s' and '%s'\n", ctx.callback_description_ptrs[i], ctx.callback_description_strings[i]);
+        ok(!strcmp(ctx.callback_name_ptrs[i], ctx.callback_name_strings[i]),
+           "Got '%s' and '%s'\n", ctx.callback_name_ptrs[i], ctx.callback_name_strings[i]);
+    }
+
+    ctx2.count = 0;
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesLifetimeTest7, &ctx2);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    /* The enumeration strings and their order are identical across enumerations. */
+    ok(ctx.count == ctx2.count, "Enumerated %u and %u devices\n", ctx.count, ctx2.count);
+    if (ctx.count == ctx2.count)
+    {
+        for (i = 0; i < ctx.count; i++)
+        {
+            ok(ctx.callback_description_ptrs[i] == ctx2.callback_description_ptrs[i],
+               "Unequal description pointers %p and %p\n", ctx.callback_description_ptrs[i], ctx2.callback_description_ptrs[i]);
+            ok(!strcmp(ctx.callback_description_strings[i], ctx2.callback_description_strings[i]),
+               "Got '%s' and '%s'\n", ctx.callback_description_strings[i], ctx2.callback_description_strings[i]);
+            ok(ctx.callback_name_ptrs[i] == ctx2.callback_name_ptrs[i],
+               "Unequal name pointers %p and %p\n", ctx.callback_name_ptrs[i], ctx2.callback_name_ptrs[i]);
+            ok(!strcmp(ctx.callback_name_strings[i], ctx2.callback_name_strings[i]),
+               "Got '%s' and '%s'\n", ctx.callback_name_strings[i], ctx2.callback_name_strings[i]);
+        }
+    }
+
+    /* Try altering the contents of the enumeration strings. */
+    for (i = 0; i < ctx2.count; i++)
+    {
+        strcpy(ctx2.callback_description_ptrs[i], "Fake Description");
+        strcpy(ctx2.callback_name_ptrs[i], "Fake Device");
+    }
+
+    ctx2.count = 0;
+    hr = IDirect3D7_EnumDevices(d3d7, enumDevicesLifetimeTest7, &ctx2);
+    ok(hr == D3D_OK, "IDirect3D7_EnumDevices returned 0x%08x\n", hr);
+
+    /* The original contents of the enumeration strings are not restored. */
+    ok(ctx.count == ctx2.count, "Enumerated %u and %u devices\n", ctx.count, ctx2.count);
+    if (ctx.count == ctx2.count)
+    {
+        for (i = 0; i < ctx.count; i++)
+        {
+            ok(ctx.callback_description_ptrs[i] == ctx2.callback_description_ptrs[i],
+               "Unequal description pointers %p and %p\n", ctx.callback_description_ptrs[i], ctx2.callback_description_ptrs[i]);
+            ok(strcmp(ctx.callback_description_strings[i], ctx2.callback_description_strings[i]) != 0,
+               "Got '%s' and '%s'\n", ctx.callback_description_strings[i], ctx2.callback_description_strings[i]);
+            ok(ctx.callback_name_ptrs[i] == ctx2.callback_name_ptrs[i],
+               "Unequal name pointers %p and %p\n", ctx.callback_name_ptrs[i], ctx2.callback_name_ptrs[i]);
+            ok(strcmp(ctx.callback_name_strings[i], ctx2.callback_name_strings[i]) != 0,
+               "Got '%s' and '%s'\n", ctx.callback_name_strings[i], ctx2.callback_name_strings[i]);
+        }
+    }
+
+    IDirect3D7_Release(d3d7);
+}
+
 START_TEST(ddraw7)
 {
     DDDEVICEIDENTIFIER2 identifier;
@@ -15966,4 +16177,6 @@ START_TEST(ddraw7)
     test_multiply_transform();
     test_alphatest();
     test_clipper_refcount();
+    test_enum_devices();
+    test_enum_devices_life_time();
 }
-- 
2.19.1

