[1/2] Extend the testing framework to include IDL files and RPC clients (take 2)

Dan Hipschman dsh at linux.ucla.edu
Thu Apr 19 16:31:34 CDT 2007


This extends the testing framework to allow for tests that need IDL
files and RPC clients.  It's the same as the last attempt, but I've
removed two little development artifacts that slipped in last time,
I fixed an indentation glitch, fixed one more thing in the Makefile
so "make depend" works for ClientMakefile as well, and I separated
the first test case from the infrastructure change (see next patch).

---
 dlls/Maketest.rules.in   |   29 ++++++++++++++----
 include/wine/test.h      |   69 ++++++++++++++++++++++++++++++++++++++++++++++
 programs/winetest/main.c |   36 +++++++++++++++++++----
 tools/make_makefiles     |   16 ++++++++--
 4 files changed, 132 insertions(+), 18 deletions(-)

diff --git a/dlls/Maketest.rules.in b/dlls/Maketest.rules.in
index 73bf4d9..18b578a 100644
--- a/dlls/Maketest.rules.in
+++ b/dlls/Maketest.rules.in
@@ -8,20 +8,25 @@
 #
 # plus all variables required by the global Make.rules.in
 #
+# Optionally, the variable CLIENT may be set to the value `client' if the
+# module to be built is a test client for an RPC server.
+#
 
 DLLFLAGS     = @DLLFLAGS@
-DEFS         = $(EXTRADEFS)
+DEFS         = $(EXTRADEFS) -DTESTBASE=\"$(DLLBASE)\"
 
-MODULE       = $(TESTDLL:%.dll=%)_test.exe
+DLLBASE      = $(TESTDLL:%.dll=%)
+MODULE       = $(DLLBASE)_test$(CLIENT).exe
 TESTRESULTS  = $(CTESTS:.c=.ok)
 TESTPROGRAM  = $(MODULE)$(DLLEXT)
 RUNTESTFLAGS = -q -P wine -M $(TESTDLL) -T $(TOPOBJDIR) -p $(TESTPROGRAM)
 
 C_SRCS       = $(CTESTS)
 ALL_LIBS     = $(IMPORTS:%=-l%) $(EXTRALIBS) $(LDFLAGS) $(LIBS)
-EXTRA_OBJS   = testlist.o
+TESTLIST     = test$(CLIENT)list
+EXTRA_OBJS   = $(TESTLIST).o
 
-CROSSTEST    = $(TESTDLL:%.dll=%)_crosstest.exe
+CROSSTEST    = $(TESTDLL:%.dll=%)_crosstest$(CLIENT).exe
 CROSSOBJS    = $(C_SRCS:.c=.cross.o) $(RC_SRCS:.rc=.res.cross.o) $(BISON_SRCS:.y=.tab.cross.o) $(LEX_SRCS:.l=.yy.cross.o) $(IDL_GEN_C_SRCS:.c=.cross.o) testlist.cross.o
 CROSSCC      = @CROSSCC@
 CROSSWINDRES = @CROSSWINDRES@
@@ -29,6 +34,7 @@ CROSSWINDRES = @CROSSWINDRES@
 @MAKE_RULES@
 
 all: $(TESTPROGRAM)
+	if test x"$(CLIENT)" = x && test -f ClientMakefile ; then $(MAKE) -f ClientMakefile ; fi
 
 # Rules for .so main module
 
@@ -42,10 +48,10 @@ $(MODULE): $(OBJS) $(RCOBJS) Makefile.in
 
 # Rules for building test list
 
-testlist.c: Makefile.in $(MAKECTESTS)
+$(TESTLIST).c: Makefile.in $(MAKECTESTS)
 	$(MAKECTESTS) -o $@ $(CTESTS)
 
-testlist.o: testlist.c $(TOPSRCDIR)/include/wine/test.h
+$(TESTLIST).o: $(TESTLIST).c $(TOPSRCDIR)/include/wine/test.h
 
 # Rules for testing
 
@@ -72,6 +78,15 @@ $(CROSSTEST): $(CROSSOBJS) Makefile.in
 
 testclean::
 	$(RM) $(TESTRESULTS)
+	if test x"$(CLIENT)" = x && test -f ClientMakefile ; then $(MAKE) -f ClientMakefile testclean ; fi
 
 clean::
-	$(RM) testlist.c $(MODULE) $(TESTRESULTS) $(CROSSTEST)
+	$(RM) $(TESTLIST).c $(MODULE) $(TESTRESULTS) $(CROSSTEST)
+	if test x"$(CLIENT)" = x && test -f ClientMakefile ; then $(MAKE) -f ClientMakefile clean ; fi
+
+# Rules for dependencies
+
+depend: client_deps
+
+client_deps:
+	if test x"$(CLIENT)" = x && test -f ClientMakefile ; then $(MAKE) -f ClientMakefile depend ; fi
diff --git a/include/wine/test.h b/include/wine/test.h
index ea79475..ccd3890 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -25,6 +25,10 @@
 #include <stdlib.h>
 #include <windef.h>
 #include <winbase.h>
+#ifdef STANDALONE
+#include <rpc.h>
+#include <rpcndr.h>
+#endif
 
 #ifdef __WINE_WINE_LIBRARY_H
 #error wine/library.h should not be used in Wine tests
@@ -57,6 +61,7 @@ extern void winetest_start_todo( const char* platform );
 extern int winetest_loop_todo(void);
 extern void winetest_end_todo( const char* platform );
 extern int winetest_get_mainargs( char*** pargv );
+extern int winetest_run_testclient( const char *subtest );
 
 #ifdef STANDALONE
 #define START_TEST(name) \
@@ -187,6 +192,70 @@ typedef struct
 } tls_data;
 static DWORD tls_index;
 
+
+/* Include these for tests that use widl */
+void __RPC_FAR *__RPC_USER midl_user_allocate(size_t n)
+{
+    return malloc(n);
+}
+
+void __RPC_USER midl_user_free(void __RPC_FAR *p)
+{
+    free(p);
+}
+
+
+static int file_exists(const char *name)
+{
+    HANDLE h = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ,
+                           NULL, OPEN_EXISTING, 0, 0);
+
+    if (h != INVALID_HANDLE_VALUE) {
+        CloseHandle(h);
+        return 1;
+    } else
+        return 0;
+}
+
+int winetest_run_testclient(const char *subtest)
+{
+    size_t namelen = strlen(TESTBASE) + 11; /* 11 == strlen("_testclient") */
+    char *filename = malloc(namelen + 8); /* 8 == strlen(".exe.so") + 1 */
+    char *cmdline = malloc(namelen + strlen(subtest) + 9);
+    int status = 0;
+
+    if (filename != NULL && cmdline != NULL)
+    {
+        STARTUPINFO startup_info;
+        PROCESS_INFORMATION client_info;
+        DWORD client_exit;
+
+        sprintf(filename, "%s_testclient.exe.so", TESTBASE);
+        if (!file_exists(filename))
+            filename[namelen + 4] = '\0';
+        sprintf(cmdline, "%s %s", filename, subtest);
+
+        ZeroMemory(&startup_info, sizeof startup_info);
+        startup_info.cb = sizeof startup_info;
+
+        if (CreateProcess(filename, cmdline, NULL, NULL, FALSE, 0,
+                          NULL, NULL, &startup_info, &client_info)
+            && WAIT_OBJECT_0 == WaitForSingleObject(client_info.hProcess, INFINITE)
+            && GetExitCodeProcess(client_info.hProcess, &client_exit)
+            && CloseHandle(client_info.hProcess)
+            && CloseHandle(client_info.hThread)
+            && client_exit == 0)
+        {
+            status = 1;
+        }
+    }
+
+    free(cmdline);
+    free(filename);
+
+    return status;
+}
+
 static tls_data* get_tls_data(void)
 {
     tls_data* data;
diff --git a/programs/winetest/main.c b/programs/winetest/main.c
index f743ffc..da81933 100644
--- a/programs/winetest/main.c
+++ b/programs/winetest/main.c
@@ -248,9 +248,13 @@ extract_test (struct wine_test *test, const char *dir, LPTSTR res_name)
     CharLowerA( test->name );
     test->exename = strmake (NULL, "%s/%s", dir, test->name);
     exepos = strstr (test->name, "_test.exe");
-    if (!exepos) report (R_FATAL, "Not an .exe file: %s", test->name);
-    *exepos = 0;
-    test->name = xrealloc (test->name, exepos - test->name + 1);
+    if (!exepos) {
+        if (!strstr (test->name, "_testclient.exe"))
+            report (R_FATAL, "Not an .exe file: %s", test->name);
+    } else {
+        *exepos = 0;
+        test->name = xrealloc (test->name, exepos - test->name + 1);
+    }
     report (R_STEP, "Extracting: %s", test->name);
 
     if (!(fout = fopen (test->exename, "wb")) ||
@@ -424,7 +428,13 @@ static BOOL CALLBACK
 EnumTestFileProc (HMODULE hModule, LPCTSTR lpszType,
                   LPTSTR lpszName, LONG_PTR lParam)
 {
-    (*(int*)lParam)++;
+    char *name = xstrdup (lpszName);
+    CharLowerA (name);
+
+    if (strstr (name, "_test.exe"))
+        (*(int*)lParam)++;
+
+    free (name);
     return TRUE;
 }
 
@@ -433,9 +443,21 @@ extract_test_proc (HMODULE hModule, LPCTSTR lpszType,
                    LPTSTR lpszName, LONG_PTR lParam)
 {
     const char *tempdir = (const char *)lParam;
-    get_subtests( tempdir, &wine_tests[nr_of_files], lpszName );
-    nr_of_tests += wine_tests[nr_of_files].subtest_count;
-    nr_of_files++;
+    char *name = xstrdup (lpszName);
+    CharLowerA (name);
+
+    if (strstr (name, "_test.exe")) {
+        get_subtests (tempdir, &wine_tests[nr_of_files], lpszName);
+        nr_of_tests += wine_tests[nr_of_files].subtest_count;
+        nr_of_files++;
+    } else {
+        struct wine_test dummy;
+        extract_test (&dummy, tempdir, lpszName);
+        free (dummy.name);
+        free (dummy.exename);
+    }
+
+    free (name);
     return TRUE;
 }
 
diff --git a/tools/make_makefiles b/tools/make_makefiles
index 90f9220..4824162 100755
--- a/tools/make_makefiles
+++ b/tools/make_makefiles
@@ -205,11 +205,11 @@ sub parse_makefile($)
 
 if (-d ".git")
 {
-    @makefiles = map { s/\.in$//; $_; } split /\s/, `git ls-files -c Makefile.in \\*/Makefile.in`;
+    @makefiles = map { s/\.in$//; $_; } split /\s/, `git ls-files -c Makefile.in \\*/Makefile.in \\*/ClientMakefile.in`;
 }
 else
 {
-    @makefiles = map { s/^\.\/(.*)\.in/$1/; $_; } split(/\s/,`find . -name Makefile.in -print`);
+    @makefiles = map { s/^\.\/(.*)\.in/$1/; $_; } split(/\s/,`find . -name Makefile.in -o -name ClientMakefile.in -print`);
 }
 
 foreach my $file (sort values %makerules, @makefiles)
@@ -244,14 +244,16 @@ replace_in_file( "configure.ac", '^MAKE_RULES', '^AC_OUTPUT$', @lines);
 
 sub update_winetest(@)
 {
-    my (@tests, @lines);
+    my (@tests, @testclients, @lines);
 
     foreach my $file (@_)
     {
         if ($file =~ /^dlls\/(.*)\/tests\/Makefile/) { push @tests, $1; }
+        elsif ($file =~ /^dlls\/(.*)\/tests\/ClientMakefile/) { push @testclients, $1; }
     }
     push @lines, "TESTBINS =";
     push @lines, map { " \\\n\t" . $_ . "_test.exe"; } sort @tests;
+    push @lines, map { " \\\n\t" . $_ . "_testclient.exe"; } sort @testclients;
     push @lines, "\n\n";
 
     foreach my $test (sort @tests)
@@ -259,12 +261,18 @@ sub update_winetest(@)
         push @lines, "${test}_test.exe: \$(DLLDIR)/$test/tests/${test}_test.exe\$(DLLEXT)\n";
         push @lines, "\tcp \$(DLLDIR)/$test/tests/${test}_test.exe\$(DLLEXT) \$\@ && \$(STRIP) \$\@\n";
     }
+    foreach $test (sort @testclients)
+    {
+        push @lines, "${test}_testclient.exe: \$(DLLDIR)/$test/tests/${test}_testclient.exe\$(DLLEXT)\n";
+        push @lines, "\tcp \$(DLLDIR)/$test/tests/${test}_testclient.exe\$(DLLEXT) \$\@ && \$(STRIP) \$\@\n";
+    }
     push @lines, "\n# Special rules\n";
 
     replace_in_file( "programs/winetest/Makefile.in", '^TESTBINS\s*=', '^# Special rules', @lines );
 
     replace_in_file( "programs/winetest/winetest.rc", ' TESTRES ', undef,
-                     map { $_ . "_test.exe TESTRES \"" . $_ . "_test.exe\"\n"; } sort @tests );
+                     (map { $_ . "_test.exe TESTRES \"" . $_ . "_test.exe\"\n"; } sort @tests),
+                     map { $_ . "_testclient.exe TESTRES \"" . $_ . "_testclient.exe\"\n"; } sort @testclients);
 
     # return a list of test exe files for .gitignore
     return map { "programs/winetest/" . $_ . "_test.exe"; } sort @tests;



More information about the wine-patches mailing list