[PATCH 1/5] msi/tests: Add tests for external UI callback.

Zebediah Figura z.figura12 at gmail.com
Sun Jun 25 21:13:52 CDT 2017


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/msi/tests/package.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 247 insertions(+), 2 deletions(-)

diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c
index 146d1fc..0c65d99 100644
--- a/dlls/msi/tests/package.c
+++ b/dlls/msi/tests/package.c
@@ -21,6 +21,7 @@
 
 #define COBJMACROS
 
+#include <assert.h>
 #include <stdio.h>
 #include <windows.h>
 #include <msidefs.h>
@@ -822,6 +823,8 @@ static UINT package_from_db(MSIHANDLE hdb, MSIHANDLE *handle)
     CHAR szPackage[12];
     MSIHANDLE hPackage;
 
+    CoInitialize(NULL);
+
     sprintf(szPackage, "#%u", hdb);
     res = MsiOpenPackageA(szPackage, &hPackage);
     if (res != ERROR_SUCCESS)
@@ -837,22 +840,39 @@ static UINT package_from_db(MSIHANDLE hdb, MSIHANDLE *handle)
         return res;
     }
 
+    CoUninitialize();
+
     *handle = hPackage;
     return ERROR_SUCCESS;
 }
 
-static void create_test_file(const CHAR *name)
+static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
 {
     HANDLE file;
     DWORD written;
 
     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
-    WriteFile(file, name, strlen(name), &written, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+        return;
+
+    WriteFile(file, data, strlen(data), &written, NULL);
     WriteFile(file, "\n", strlen("\n"), &written, NULL);
+
+    if (size)
+    {
+        SetFilePointer(file, size, NULL, FILE_BEGIN);
+        SetEndOfFile(file);
+    }
+
     CloseHandle(file);
 }
 
+static void create_test_file(const CHAR *name)
+{
+    create_file_data(name, name, 0);
+}
+
 typedef struct _tagVS_VERSIONINFO
 {
     WORD wLength;
@@ -9179,6 +9199,229 @@ static void test_externalui(void)
     DeleteFileA(msifile);
 }
 
+struct externalui_message {
+    UINT message;
+    int field_count;
+    char field[4][100];
+    int match[4]; /* should we test for a match */
+    int optional;
+};
+
+static struct externalui_message *sequence;
+static int sequence_count, sequence_size;
+
+static void add_message(const struct externalui_message *msg)
+{
+    if (!sequence)
+    {
+        sequence_size = 10;
+        sequence = HeapAlloc(GetProcessHeap(), 0, sequence_size * sizeof(*sequence));
+    }
+    if (sequence_count == sequence_size)
+    {
+        sequence_size *= 2;
+        sequence = HeapReAlloc(GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence));
+    }
+
+    assert(sequence);
+
+    sequence[sequence_count++] = *msg;
+}
+
+static void flush_sequence(void)
+{
+    HeapFree(GetProcessHeap(), 0, sequence);
+    sequence = NULL;
+    sequence_count = sequence_size = 0;
+}
+
+static void ok_sequence_(const struct externalui_message *expected, const char *context, BOOL todo,
+                         const char *file, int line)
+{
+    static const struct externalui_message end_of_sequence = {0};
+    const struct externalui_message *actual;
+    int failcount = 0;
+    int i;
+
+    add_message(&end_of_sequence);
+
+    actual = sequence;
+
+    while (expected->message && actual->message)
+    {
+        if (expected->message == actual->message)
+        {
+            if (expected->field_count != actual->field_count)
+            {
+                todo_wine_if (todo)
+                    ok_(file, line) (FALSE, "%s: in msg 0x%08x expecting field count %d got %d\n",
+                                     context, expected->message, expected->field_count, actual->field_count);
+                failcount++;
+            }
+
+            for (i = 0; i <= actual->field_count; i++)
+            {
+                if (expected->match[i] && strcmp(expected->field[i], actual->field[i]))
+                {
+                    todo_wine_if (todo)
+                        ok_(file, line) (FALSE, "%s: in msg 0x%08x field %d: expected \"%s\", got \"%s\"\n",
+                                         context, expected->message, i, expected->field[i], actual->field[i]);
+                    failcount++;
+                }
+            }
+
+            expected++;
+            actual++;
+        }
+        else
+        {
+            todo_wine_if (todo)
+                ok_(file, line) (FALSE, "%s: the msg 0x%08x was expected, but got msg 0x%08x instead\n",
+                                 context, expected->message, actual->message);
+            failcount++;
+            if (todo)
+                goto done;
+            expected++;
+            actual++;
+        }
+    }
+
+    if (expected->message || actual->message)
+    {
+        todo_wine_if (todo)
+            ok_(file, line) (FALSE, "%s: the msg sequence is not complete: expected %08x - actual %08x\n",
+                             context, expected->message, actual->message);
+        failcount++;
+    }
+
+    if(todo && !failcount) /* succeeded yet marked todo */
+    {
+        todo_wine
+            ok_(file, line)(TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
+    }
+
+done:
+    flush_sequence();
+}
+
+#define ok_sequence(exp, contx, todo) \
+        ok_sequence_((exp), (contx), (todo), __FILE__, __LINE__)
+
+static const struct externalui_message empty_sequence[] = {
+    {0}
+};
+
+static const struct externalui_message openpackage_nonexistent_sequence[] = {
+    {INSTALLMESSAGE_INITIALIZE, -1},
+    {INSTALLMESSAGE_TERMINATE, -1},
+    {0}
+};
+
+static const struct externalui_message openpackage_sequence[] = {
+    {INSTALLMESSAGE_INITIALIZE, -1},
+    {INSTALLMESSAGE_COMMONDATA, 3, {"", "0", "1033", "1252"}, {1, 1, 1, 1}},
+    {INSTALLMESSAGE_INFO|MB_ICONHAND, 0, {""}, {0}},
+    {INSTALLMESSAGE_COMMONDATA, 3, {"", "0", "1033", "1252"}, {0, 1, 1, 1}},
+    {INSTALLMESSAGE_COMMONDATA, 3, {"", "1", "", ""}, {0, 1, 1, 1}},
+    {0}
+};
+
+static const struct externalui_message doaction_costinitialize_sequence[] = {
+    {INSTALLMESSAGE_ACTIONSTART, 3, {"", "CostInitialize", "", ""}, {0, 1, 0, 1}},
+    {INSTALLMESSAGE_INFO, 2, {"", "CostInitialize", ""}, {0, 1, 1}},
+    {INSTALLMESSAGE_INFO, 2, {"", "CostInitialize", "1"}, {0, 1, 1}},
+    {0}
+};
+
+static const struct externalui_message doaction_custom_sequence[] = {
+    {INSTALLMESSAGE_ACTIONSTART, 3, {"", "custom", "", ""}, {0, 1, 1, 1}},
+    {INSTALLMESSAGE_INFO, 2, {"", "custom", "1"}, {0, 1, 1}},
+    {INSTALLMESSAGE_INFO, 2, {"", "custom", "0"}, {0, 1, 1}},
+    {0}
+};
+
+static const struct externalui_message closehandle_sequence[] = {
+    {INSTALLMESSAGE_TERMINATE, -1},
+    {0}
+};
+
+static INT CALLBACK externalui_message_callback(void *context, UINT message, MSIHANDLE hrecord)
+{
+    struct externalui_message msg;
+    char buffer[100];
+    DWORD length = 100;
+    int i;
+
+    msg.message = message;
+    msg.field_count = MsiRecordGetFieldCount(hrecord);
+    for (i = 0; i <= msg.field_count; i++)
+    {
+        length = 100;
+        MsiRecordGetStringA(hrecord, i, buffer, &length);
+        memcpy(msg.field[i], buffer, length+1);
+    }
+
+    add_message(&msg);
+
+    return 1;
+}
+
+static void test_externalui_message(void)
+{
+    /* test that events trigger the correct sequence of messages */
+
+    INSTALLUI_HANDLER_RECORD prev;
+    const struct externalui_message *sequence = NULL;
+    MSIHANDLE hdb, hpkg;
+    UINT r;
+
+    r = pMsiSetExternalUIRecord(externalui_message_callback, 0xffffffff ^ INSTALLLOGMODE_PROGRESS, &sequence, &prev);
+
+    flush_sequence();
+
+    hdb = create_package_db();
+    ok(hdb, "failed to create database\n");
+
+    create_file_data("forcecodepage.idt", "\r\n\r\n1252\t_ForceCodepage\r\n", 0);
+    r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d", r);
+
+    r = MsiOpenPackageA(NULL, &hpkg);
+    ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
+    ok_sequence(empty_sequence, "MsiOpenPackage with NULL db", FALSE);
+
+    r = MsiOpenPackageA("nonexistent", &hpkg);
+    ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", r);
+    ok_sequence(openpackage_nonexistent_sequence, "MsiOpenPackage with nonexistent db", TRUE);
+
+    r = package_from_db(hdb, &hpkg);
+    if (r == ERROR_INSTALL_PACKAGE_REJECTED)
+    {
+        skip("Not enough rights to perform tests\n");
+        DeleteFileA(msifile);
+        return;
+    }
+    ok(r == ERROR_SUCCESS, "failed to create package %u\n", r);
+    ok_sequence(openpackage_sequence, "MsiOpenPackage with valid db", TRUE);
+
+    /* Test a standard action */
+    r = MsiDoActionA(hpkg, "CostInitialize");
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    ok_sequence(doaction_costinitialize_sequence, "MsiDoAction(\"CostInitialize\")", TRUE);
+
+    /* Test a standard action */
+    r = MsiDoActionA(hpkg, "custom");
+    ok(r == ERROR_FUNCTION_NOT_CALLED, "Expected ERROR_FUNCTION_NOT_CALLED, got %d\n", r);
+    ok_sequence(doaction_custom_sequence, "MsiDoAction(\"custom\")", TRUE);
+
+    /* close the package */
+    MsiCloseHandle(hpkg);
+    ok_sequence(closehandle_sequence, "MsiCloseHandle()", TRUE);
+
+    DeleteFileA(msifile);
+    DeleteFileA("forcecodepage.idt");
+}
+
 START_TEST(package)
 {
     STATEMGRSTATUS status;
@@ -9237,6 +9480,8 @@ START_TEST(package)
     test_MsiEnumComponentCosts();
     test_MsiDatabaseCommit();
     test_externalui();
+    if (pMsiSetExternalUIRecord)
+        test_externalui_message();
 
     if (pSRSetRestorePointA && !pMsiGetComponentPathExA && ret)
     {
-- 
2.7.4




More information about the wine-patches mailing list