regsvr32/tests: Add initial tests

Hugh McMaster hugh.mcmaster at outlook.com
Mon Jan 11 20:18:04 CST 2016


Signed-off-by: Hugh McMaster <hugh.mcmaster at outlook.com>
---
 configure                           |   1 +
 configure.ac                        |   1 +
 programs/regsvr32/tests/Makefile.in |  33 +++++
 programs/regsvr32/tests/dll.c       |  59 +++++++++
 programs/regsvr32/tests/dll.def     |   4 +
 programs/regsvr32/tests/regsvr32.c  | 247 ++++++++++++++++++++++++++++++++++++
 programs/regsvr32/tests/resource.rc |  29 +++++
 7 files changed, 374 insertions(+)
 create mode 100644 programs/regsvr32/tests/Makefile.in
 create mode 100644 programs/regsvr32/tests/dll.c
 create mode 100644 programs/regsvr32/tests/dll.def
 create mode 100644 programs/regsvr32/tests/regsvr32.c
 create mode 100644 programs/regsvr32/tests/resource.rc

diff --git a/configure b/configure
index c11b266..217feba 100755
--- a/configure
+++ b/configure
@@ -18096,6 +18096,7 @@ wine_fn_config_program regedit enable_regedit install,installbin,manpage,po
 wine_fn_config_test programs/regedit/tests regedit.exe_test
 wine_fn_config_program regsvcs enable_regsvcs install
 wine_fn_config_program regsvr32 enable_regsvr32 install,installbin,manpage,po
+wine_fn_config_test programs/regsvr32/tests regsvr32.exe_test
 wine_fn_config_program rpcss enable_rpcss clean,install
 wine_fn_config_program rundll.exe16 enable_win16 install
 wine_fn_config_program rundll32 enable_rundll32 install
diff --git a/configure.ac b/configure.ac
index 6f6423b..8bb2584 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3440,6 +3440,7 @@ WINE_CONFIG_PROGRAM(regedit,,[install,installbin,manpage,po])
 WINE_CONFIG_TEST(programs/regedit/tests)
 WINE_CONFIG_PROGRAM(regsvcs,,[install])
 WINE_CONFIG_PROGRAM(regsvr32,,[install,installbin,manpage,po])
+WINE_CONFIG_TEST(programs/regsvr32/tests)
 WINE_CONFIG_PROGRAM(rpcss,,[clean,install])
 WINE_CONFIG_PROGRAM(rundll.exe16,enable_win16,[install])
 WINE_CONFIG_PROGRAM(rundll32,,[install])
diff --git a/programs/regsvr32/tests/Makefile.in b/programs/regsvr32/tests/Makefile.in
new file mode 100644
index 0000000..61d25fe
--- /dev/null
+++ b/programs/regsvr32/tests/Makefile.in
@@ -0,0 +1,33 @@
+TESTDLL = regsvr32.exe
+
+C_SRCS = regsvr32.c
+
+DLL_BASENAMES = test1
+GCC = $(CC)
+
+ifneq (,$(filter crosstest mingw,$(MAKECMDGOALS) $(findstring mingw,$(CC))))
+  TARGET_DLLS = $(addsuffix .dll, $(DLL_BASENAMES))
+  RESOURCE_RES = resource.cross.res
+  RCFLAGS = -DWINE_CROSSTEST=1
+else
+  TARGET_DLLS = $(addsuffix .dll.so, $(DLL_BASENAMES))
+  RESOURCE_RES = resource.res
+  RCFLAGS = -DWINE_CROSSTEST=0
+endif
+
+LDFLAGS = $(RESOURCE_RES)
+
+dll.o: $(srcdir)/dll.c
+	$(CC) -c -o $@ $^ -I$(srcdir) -I$(top_srcdir)/include -D__WINESRC__ $(DLLFLAGS) $(EXTRACFLAGS) $(CFLAGS)
+dll.cross.o: $(srcdir)/dll.c
+	$(GCC) -c -o $@ $^ -I$(srcdir) -I$(top_srcdir)/include -D__WINESRC__ -DWINE_CROSSTEST $(EXTRACFLAGS) $(CFLAGS)
+test1.dll.so: dll.o $(srcdir)/dll.def
+	$(TOOLSDIR)/tools/winegcc/winegcc -o $@ $^ -shared -s -B$(TOOLSDIR)/tools/winebuild $(UNWINDFLAGS)
+test1.dll: dll.cross.o $(srcdir)/dll.def
+	$(GCC) -o $@ $^ -shared -s -I$(srcdir) -I$(top_srcdir)/include -D__WINESRC__ -DWINE_CROSSTEST $(CFLAGS) -Wl,--enable-stdcall-fixup
+$(RESOURCE_RES): $(srcdir)/resource.rc $(WRC) $(TARGET_DLLS)
+	$(WRC) -o $@ --nostdinc -I$(srcdir) -I$(top_srcdir)/include -D__WINESRC__ $(RCFLAGS) $<
+all crosstest regsvr32.exe_test.exe.so: $(RESOURCE_RES)
+crosstest: GCC = $(CROSSCC)
+clean::
+	$(RM) dll.o dll.cross.o *.dll *.dll.so *.res
diff --git a/programs/regsvr32/tests/dll.c b/programs/regsvr32/tests/dll.c
new file mode 100644
index 0000000..f2b65c2
--- /dev/null
+++ b/programs/regsvr32/tests/dll.c
@@ -0,0 +1,59 @@
+/*
+ * DLL functions for the regsvr32.exe unit tests
+ *
+ * Copyright 2016 Hugh McMaster
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+#include <stdio.h>
+
+static BOOL output_string(const char *str)
+{
+    DWORD written;
+
+    return WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, strlen(str), &written, NULL);
+}
+
+HRESULT __stdcall DllInstall(BOOL install, const WCHAR *cmdline)
+{
+    BOOL res;
+
+    if (install)
+        res = output_string("Install");
+    else
+        res = output_string("Uninstall");
+
+    if (cmdline)
+    {
+        char buffer[16];
+        WideCharToMultiByte(CP_ACP, 0, cmdline, -1, buffer, sizeof(buffer), NULL, NULL);
+        output_string(buffer);
+    }
+    return res ? S_OK : E_UNEXPECTED;
+}
+
+HRESULT __stdcall DllRegisterServer(void)
+{
+    return output_string("Register") ? S_OK : E_UNEXPECTED;
+}
+
+HRESULT __stdcall DllUnregisterServer(void)
+{
+    return output_string("Unregister") ? S_OK : E_UNEXPECTED;
+}
diff --git a/programs/regsvr32/tests/dll.def b/programs/regsvr32/tests/dll.def
new file mode 100644
index 0000000..08d2f6f
--- /dev/null
+++ b/programs/regsvr32/tests/dll.def
@@ -0,0 +1,4 @@
+EXPORTS
+  DllInstall @1 PRIVATE
+  DllRegisterServer @2 PRIVATE
+  DllUnregisterServer @3 PRIVATE
diff --git a/programs/regsvr32/tests/regsvr32.c b/programs/regsvr32/tests/regsvr32.c
new file mode 100644
index 0000000..746c81f
--- /dev/null
+++ b/programs/regsvr32/tests/regsvr32.c
@@ -0,0 +1,247 @@
+/*
+ * Unit tests for regsvr32.exe
+ *
+ * Copyright 2016 Hugh McMaster
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+
+/* Copyright 2013 Huw Davies. Modified by Hugh McMaster. */
+static void *get_res_data(const char *filename, DWORD *rsrc_size)
+{
+    HRSRC rsrc;
+    void *rsrc_data;
+
+    rsrc = FindResourceA(GetModuleHandleA(NULL), filename, (const char *)RT_RCDATA);
+    if (!rsrc) return NULL;
+
+    rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
+    if (!rsrc_data) return NULL;
+
+    *rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
+    if (!*rsrc_size) return NULL;
+
+    return rsrc_data;
+}
+
+/* Copyright 2013 Huw Davies. Modified by Hugh McMaster. */
+static BOOL write_tmp_file(const void *data, DWORD *size, char *tmp_name)
+{
+    char tmp_path[MAX_PATH];
+    HANDLE hfile;
+    BOOL ret;
+
+    GetTempPathA(MAX_PATH, tmp_path);
+    GetTempFileNameA(tmp_path, "Dll", 0, tmp_name);
+
+    hfile = CreateFileA(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+    if (hfile == INVALID_HANDLE_VALUE) return FALSE;
+
+    ret = WriteFile(hfile, data, *size, size, NULL);
+
+    CloseHandle(hfile);
+    return ret;
+}
+
+/* Copyright 2013 Huw Davies. Modified by Hugh McMaster. */
+static BOOL write_dll_file(const char *filename, char *tmp_name)
+{
+    void *rsrc_data;
+    DWORD rsrc_size;
+
+    rsrc_data = get_res_data(filename, &rsrc_size);
+    if (!rsrc_data) return FALSE;
+
+    return write_tmp_file(rsrc_data, &rsrc_size, tmp_name);
+}
+
+static BOOL run_regsvr32_exe(char *output, DWORD *r, const char *cmd)
+{
+    SECURITY_ATTRIBUTES sa;
+    HANDLE read_pipe = NULL, write_pipe = NULL;
+    STARTUPINFOA si = {0};
+    char cmdline[256];
+    PROCESS_INFORMATION pi;
+    DWORD ret, bytes_read;
+    BOOL res;
+
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = TRUE;
+
+    if (!CreatePipe(&read_pipe, &write_pipe, &sa, 0))
+        return FALSE;
+    SetHandleInformation(read_pipe, HANDLE_FLAG_INHERIT, 0);
+
+    si.cb = sizeof(STARTUPINFOA);
+    si.dwFlags = STARTF_USESTDHANDLES;
+    si.hStdInput = INVALID_HANDLE_VALUE;
+    si.hStdOutput = write_pipe;
+    si.hStdError = write_pipe;
+
+    strcpy(cmdline, cmd);
+    if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
+    {
+        CloseHandle(read_pipe);
+        CloseHandle(write_pipe);
+        return FALSE;
+    }
+    CloseHandle(write_pipe);
+
+    ret = WaitForSingleObject(pi.hProcess, 5000);
+    if (ret == WAIT_TIMEOUT)
+        TerminateProcess(pi.hProcess, STILL_ACTIVE);
+
+    *r = 6;
+    res = GetExitCodeProcess(pi.hProcess, r);
+
+    output[0] = 0;
+    for (;;)
+    {
+        if (!ReadFile(read_pipe, output, 255, &bytes_read, NULL) || !bytes_read)
+            break;
+        output[bytes_read] = 0;
+    }
+
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+    return res;
+}
+
+#define run_test(...) run_test_(output, &r, __VA_ARGS__)
+static BOOL __cdecl run_test_(char *output, DWORD *r, const char *fmt, ...)
+{
+   __ms_va_list va_args;
+    char *cmd;
+    BOOL ret;
+
+    __ms_va_start(va_args, fmt);
+    FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                   fmt, 0, 0, (char *)&cmd, 0, &va_args);
+    __ms_va_end(va_args);
+
+    ret = run_regsvr32_exe(output, r, cmd);
+    LocalFree(cmd);
+    return ret;
+}
+
+static char test1_dll[MAX_PATH];
+
+#define CMP(s) !strcmp(output, s)
+#define EXIT_SUCCESS 0
+#define INVALID_ARG  1
+
+static void test_flags(void)
+{
+    char output[256];
+    DWORD r;
+
+    run_test("regsvr32.exe /s %1", test1_dll);
+    ok(CMP("Register"), "got '%s', expected 'Register'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %u\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /u %1", test1_dll);
+    ok(CMP("Unregister"), "got '%s', expected 'Unregister'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %u\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /i %1", test1_dll);
+    ok(CMP("RegisterInstall"), "got '%s', expected 'RegisterInstall'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %u\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /i:\"Cmd\" %1", test1_dll);
+    ok(CMP("RegisterInstallCmd"), "got '%s', expected 'RegisterInstallCmd'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %u\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /n %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %u\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s /u /i %1", test1_dll);
+    ok(CMP("UninstallUnregister"), "got '%s', expected 'UninstallUnregister'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /i /u %1", test1_dll);
+    ok(CMP("UninstallUnregister"), "got '%s', expected 'UninstallUnregister'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /i:\"Cmd\" /u %1", test1_dll);
+    ok(CMP("UninstallCmdUnregister"), "got '%s', expected 'UninstallCmdUnregister'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /i /n %1", test1_dll);
+    ok(CMP("Install"), "got '%s', expected 'Install'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /n /i %1", test1_dll);
+    ok(CMP("Install"), "got '%s', expected 'Install'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /u /n %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %d\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s /n /u %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %d\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s /i /u /n %1", test1_dll);
+    ok(CMP("Uninstall"), "got '%s', expected 'Uninstall'\n", output);
+    ok(r == EXIT_SUCCESS, "got exit code %u, expected %d\n", r, EXIT_SUCCESS);
+
+    run_test("regsvr32.exe /s /a %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %u\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s /u /a %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %u\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s / %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %u\n", r, INVALID_ARG);
+
+    run_test("regsvr32.exe /s - %1", test1_dll);
+    ok(!output[0], "got '%s', expected '(null)'\n", output);
+    ok(r == INVALID_ARG, "got exit code %u, expected %u\n", r, INVALID_ARG);
+}
+
+START_TEST(regsvr32)
+{
+    char output[256];
+    DWORD r;
+
+    if (!run_regsvr32_exe(output, &r, "regsvr32.exe /s"))
+    {
+        win_skip("Unable to start regsvr32.exe. Skipping tests.\n");
+        return;
+    }
+
+    if (!write_dll_file("test1.dll", test1_dll))
+    {
+        win_skip("Unable to output test DLLs. Skipping tests.\n");
+        return;
+    }
+
+    test_flags();
+
+    DeleteFileA(test1_dll);
+}
diff --git a/programs/regsvr32/tests/resource.rc b/programs/regsvr32/tests/resource.rc
new file mode 100644
index 0000000..db1b52b
--- /dev/null
+++ b/programs/regsvr32/tests/resource.rc
@@ -0,0 +1,29 @@
+/*
+ * Resources for the regsvr32.exe unit tests
+ *
+ * Copyright 2016 Hugh McMaster
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+
+#if WINE_CROSSTEST
+# define SYM(s) s
+#else
+# define SYM(s) s##.so
+#endif
+
+test1.dll RCDATA SYM(test1.dll)
-- 
1.9.1




More information about the wine-patches mailing list