diff --git a/tests/Makefile.in b/tests/Makefile.in
index 14da03c03c..cb8c207012 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -212,6 +212,7 @@ TEST_GUI_OBJECTS = \
test_gui_evtlooptest.o \
test_gui_propagation.o \
test_gui_keyboard.o \
+ test_gui_exec.o \
test_gui_fonttest.o \
test_gui_image.o \
test_gui_rawbmp.o \
@@ -895,6 +896,9 @@ test_gui_propagation.o: $(srcdir)/events/propagation.cpp $(TEST_GUI_ODEP)
test_gui_keyboard.o: $(srcdir)/events/keyboard.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/events/keyboard.cpp
+test_gui_exec.o: $(srcdir)/exec/exec.cpp $(TEST_GUI_ODEP)
+ $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/exec/exec.cpp
+
test_gui_fonttest.o: $(srcdir)/font/fonttest.cpp $(TEST_GUI_ODEP)
$(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/font/fonttest.cpp
diff --git a/tests/exec/exec.cpp b/tests/exec/exec.cpp
index d9e61fdfff..7a4ee95b6f 100644
--- a/tests/exec/exec.cpp
+++ b/tests/exec/exec.cpp
@@ -23,14 +23,23 @@
#include "wx/utils.h"
#include "wx/process.h"
#include "wx/sstream.h"
+#include "wx/evtloop.h"
+#include "wx/file.h"
+#include "wx/filename.h"
+#include "wx/mstream.h"
+#include "wx/scopeguard.h"
+#include "wx/txtstrm.h"
+#include "wx/timer.h"
#ifdef __UNIX__
#define COMMAND "echo hi"
+ #define COMMAND_STDERR "cat nonexistentfile"
#define ASYNC_COMMAND "xclock"
#define SHELL_COMMAND "echo hi from shell>/dev/null"
#define COMMAND_NO_OUTPUT "echo -n"
#elif defined(__WINDOWS__)
#define COMMAND "cmd.exe /c \"echo hi\""
+ #define COMMAND_STDERR "cmd.exe /c \"type nonexistentfile\""
#define ASYNC_COMMAND "notepad"
#define SHELL_COMMAND "echo hi > nul:"
#define COMMAND_NO_OUTPUT COMMAND " > nul:"
@@ -38,6 +47,8 @@
#error "no command to exec"
#endif // OS
+#define SLEEP_END_STRING "Done sleeping"
+
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
@@ -52,11 +63,90 @@ private:
CPPUNIT_TEST( TestShell );
CPPUNIT_TEST( TestExecute );
CPPUNIT_TEST( TestProcess );
+ CPPUNIT_TEST( TestAsync );
+ CPPUNIT_TEST( TestAsyncRedirect );
+ CPPUNIT_TEST( TestOverlappedSyncExecute );
CPPUNIT_TEST_SUITE_END();
void TestShell();
void TestExecute();
void TestProcess();
+ void TestAsync();
+ void TestAsyncRedirect();
+ void TestOverlappedSyncExecute();
+
+ // Helper: create an executable file sleeping for the given amount of
+ // seconds with the specified base name.
+ //
+ // Returns the name of the file.
+ static wxString CreateSleepFile(const wxString& basename, int seconds);
+
+ // Return the full command, to be passed to wxExecute(), launching the
+ // specified script file.
+ static wxString MakeShellCommand(const wxString& filename);
+
+
+ // Helper of TestAsyncRedirect(): tests that the output of the given
+ // command on the given stream contains the expected string.
+ enum CheckStream { Check_Stdout, Check_Stderr };
+
+ void DoTestAsyncRedirect(const wxString& command,
+ CheckStream check,
+ const char* expectedContaining);
+
+ enum AsyncExecLoopExitEnum
+ {
+ AsyncExec_DontExitLoop,
+ AsyncExec_ExitLoop
+ };
+
+ // This class is used as a helper in order to run wxExecute(ASYNC)
+ // inside of an event loop.
+ class AsyncInEventLoop : public wxTimer
+ {
+ public:
+ AsyncInEventLoop() { }
+
+ long DoExecute(AsyncExecLoopExitEnum forceExitLoop_,
+ const wxString& command_,
+ int flags_ = wxEXEC_ASYNC,
+ wxProcess* callback_ = NULL)
+ {
+ forceExitLoop = forceExitLoop_;
+ command = command_;
+ flags = flags_;
+ callback = callback_;
+
+ wxEventLoop loop;
+
+ // Trigger the timer to go off inside the event loop
+ // so that we can run wxExecute there.
+ StartOnce(10);
+
+ // Run the event loop.
+ loop.Run();
+
+ return wxExecuteReturnCode;
+ }
+
+ void Notify()
+ {
+ // Run wxExecute inside the event loop.
+ wxExecuteReturnCode = wxExecute(command, flags, callback);
+
+ if (forceExitLoop == AsyncExec_ExitLoop)
+ {
+ wxEventLoop::GetActive()->Exit();
+ }
+ }
+
+ private:
+ AsyncExecLoopExitEnum forceExitLoop;
+ wxString command;
+ int flags;
+ wxProcess* callback;
+ long wxExecuteReturnCode;
+ };
DECLARE_NO_COPY_CLASS(ExecTestCase)
};
@@ -75,12 +165,18 @@ void ExecTestCase::TestShell()
void ExecTestCase::TestExecute()
{
- // test sync exec (with a command not producing any output to avoid
- // interfering with the test):
- CPPUNIT_ASSERT( wxExecute(COMMAND_NO_OUTPUT, wxEXEC_SYNC) == 0 );
+ AsyncInEventLoop asyncInEventLoop;
// test asynch exec
- long pid = wxExecute(ASYNC_COMMAND, wxEXEC_ASYNC);
+ //
+ // asyncInEventLoop.DoExecute will perform the
+ // call to wxExecute(ASYNC) in an event loop, as required by
+ // console test (and this same event loop will also
+ // be used in GUI test too, even though not required, just to have
+ // common code).
+ long pid = asyncInEventLoop.DoExecute(AsyncExec_ExitLoop, // Force exit of event loop right
+ // after the call to wxExecute()
+ ASYNC_COMMAND, wxEXEC_ASYNC);
CPPUNIT_ASSERT( pid != 0 );
// NOTE: under Windows the first wxKill() invocation with wxSIGTERM
@@ -91,17 +187,62 @@ void ExecTestCase::TestExecute()
CPPUNIT_ASSERT( wxKill(pid, wxSIGTERM) == 0 ||
wxKill(pid, wxSIGKILL) == 0 );
- // test running COMMAND again, but this time with redirection:
- wxArrayString stdout_arr;
- CPPUNIT_ASSERT_EQUAL( 0, wxExecute(COMMAND, stdout_arr, wxEXEC_SYNC) );
- CPPUNIT_ASSERT_EQUAL( "hi", stdout_arr[0] );
+ int useNoeventsFlag;
+
+ // Test the sync execution case with/without wxEXEC_NOEVENTS flag
+ // because we use either an event loop or wxSelectDispatcher
+ // depending on this flag, and we want to test both cases.
+ for (useNoeventsFlag = 0; useNoeventsFlag <=1 ; ++useNoeventsFlag )
+ {
+ int execFlags = wxEXEC_SYNC;
+
+ if (useNoeventsFlag)
+ {
+ execFlags |= wxEXEC_NOEVENTS;
+ }
+
+ // test sync exec (with a command not producing any output to avoid
+ // interfering with the test):
+ CPPUNIT_ASSERT( wxExecute(COMMAND_NO_OUTPUT, execFlags) == 0 );
+
+ // test running COMMAND again, but this time with redirection:
+ // and the expected data is on stdout.
+ wxArrayString stdout_arr;
+ CPPUNIT_ASSERT_EQUAL( 0, wxExecute(COMMAND, stdout_arr, execFlags) );
+ CPPUNIT_ASSERT_EQUAL( "hi", stdout_arr[0] );
+
+ // test running COMMAND_STDERR with redirection and the expected data
+ // is on stderr.
+ wxArrayString stderr_arr;
+ stdout_arr.Empty();
+ CPPUNIT_ASSERT( wxExecute(COMMAND_STDERR, stdout_arr, stderr_arr, execFlags) != 0 );
+
+ // Check that there is something on stderr.
+ // In Unix systems, the 'cat' command has the name of the file it could not
+ // find in the error output.
+ // In Windows, the 'type' command outputs the following when it can't find
+ // a file:
+ // "The system cannot find the file specified"
+ // In both cases, we expect the word 'file' to be in the stderr.
+ CPPUNIT_ASSERT( stderr_arr[0].Contains("file") );
+ }
}
void ExecTestCase::TestProcess()
{
+ AsyncInEventLoop asyncInEventLoop;
+
// test wxExecute with wxProcess
wxProcess *proc = new wxProcess;
- long pid = wxExecute(ASYNC_COMMAND, wxEXEC_ASYNC, proc);
+
+ // asyncInEventLoop.DoExecute will perform the
+ // call to wxExecute(ASYNC) in an event loop, as required by
+ // console test (and this same event loop will also
+ // be used in GUI test too, even though not required, just to have
+ // common code).
+ long pid = asyncInEventLoop.DoExecute(AsyncExec_ExitLoop, // Force exit of event loop right
+ // after the call to wxExecute()
+ ASYNC_COMMAND, wxEXEC_ASYNC, proc);
CPPUNIT_ASSERT( proc->GetPid() == pid && pid != 0 );
// we're not going to process the wxEVT_END_PROCESS event,
@@ -112,16 +253,244 @@ void ExecTestCase::TestProcess()
// test wxExecute with wxProcess and REDIRECTION
- wxProcess *proc2 = new wxProcess;
- proc2->Redirect();
- CPPUNIT_ASSERT( wxExecute(COMMAND, wxEXEC_SYNC, proc2) == 0 );
- wxStringOutputStream stdout_stream;
- CPPUNIT_ASSERT( proc2->GetInputStream() );
- CPPUNIT_ASSERT_EQUAL( wxSTREAM_EOF,
- proc2->GetInputStream()->Read(stdout_stream).GetLastError() );
+ // Test the sync execution case with/without wxEXEC_NOEVENTS flag
+ // because we use either an event loop or wxSelectDispatcher
+ // depending on this flag, and we want to test both cases.
- wxString str(stdout_stream.GetString());
- CPPUNIT_ASSERT_EQUAL( "hi", str.Trim() );
+ // First the default case, dispatching the events while waiting.
+ {
+ wxProcess proc2;
+ proc2.Redirect();
+ CPPUNIT_ASSERT_EQUAL( 0, wxExecute(COMMAND, wxEXEC_SYNC, &proc2) );
+
+ wxStringOutputStream procOutput;
+ CPPUNIT_ASSERT( proc2.GetInputStream() );
+ CPPUNIT_ASSERT_EQUAL( wxSTREAM_EOF,
+ proc2.GetInputStream()->Read(procOutput).GetLastError() );
+
+ wxString output = procOutput.GetString();
+ CPPUNIT_ASSERT_EQUAL( "hi", output.Trim() );
+ }
+
+ // And now without event dispatching.
+ {
+ wxProcess proc2;
+ proc2.Redirect();
+ CPPUNIT_ASSERT_EQUAL( 0,
+ wxExecute(COMMAND, wxEXEC_SYNC | wxEXEC_NOEVENTS, &proc2) );
+
+ wxStringOutputStream procOutput;
+ CPPUNIT_ASSERT( proc2.GetInputStream() );
+ CPPUNIT_ASSERT_EQUAL( wxSTREAM_EOF,
+ proc2.GetInputStream()->Read(procOutput).GetLastError() );
+
+ wxString output = procOutput.GetString();
+ CPPUNIT_ASSERT_EQUAL( "hi", output.Trim() );
+ }
}
+
+// This class exits the event loop associated with it when the child process
+// terminates.
+class TestAsyncProcess : public wxProcess
+{
+public:
+ wxEXPLICIT TestAsyncProcess()
+ {
+ }
+
+ // may be overridden to be notified about process termination
+ virtual void OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
+ {
+ wxEventLoop::GetActive()->ScheduleExit();
+ }
+
+private:
+ wxDECLARE_NO_COPY_CLASS(TestAsyncProcess);
+};
+
+void ExecTestCase::TestAsync()
+{
+ // Test asynchronous execution with no redirection, just to make sure we
+ // get the OnTerminate() call.
+ TestAsyncProcess proc;
+ AsyncInEventLoop asyncInEventLoop;
+
+ CPPUNIT_ASSERT( asyncInEventLoop.DoExecute(
+ AsyncExec_DontExitLoop, // proc is expected (inside of its OnTerminate())
+ // to trigger the exit of the event loop.
+ COMMAND_NO_OUTPUT, wxEXEC_ASYNC, &proc) != 0 );
+}
+
+void
+ExecTestCase::DoTestAsyncRedirect(const wxString& command,
+ CheckStream check,
+ const char* expectedContaining)
+{
+ AsyncInEventLoop asyncInEventLoop;
+ TestAsyncProcess proc;
+
+ proc.Redirect();
+
+ CPPUNIT_ASSERT( asyncInEventLoop.DoExecute(
+ AsyncExec_DontExitLoop, // proc is expected (inside of its OnTerminate())
+ // to trigger the exit of the event loop.
+ command, wxEXEC_ASYNC, &proc) != 0 );
+
+ wxInputStream *streamToCheck = NULL;
+ switch ( check )
+ {
+ case Check_Stdout:
+ streamToCheck = proc.GetInputStream();
+ break;
+
+ case Check_Stderr:
+ streamToCheck = proc.GetErrorStream();
+ break;
+ }
+
+ wxTextInputStream tis(*streamToCheck);
+
+ // Check that the first line of output contains what we expect.
+ CPPUNIT_ASSERT( tis.ReadLine().Contains(expectedContaining) );
+}
+
+void ExecTestCase::TestAsyncRedirect()
+{
+ // Test redirection with reading from the input stream after process termination.
+ DoTestAsyncRedirect(COMMAND, Check_Stdout, "hi");
+
+ // Test redirection with reading from the error stream after process termination.
+ DoTestAsyncRedirect(COMMAND_STDERR, Check_Stderr, "file");
+}
+
+// static
+wxString ExecTestCase::CreateSleepFile(const wxString& basename, int seconds)
+{
+#ifdef __UNIX__
+ static const char* const scriptExt = ".sh";
+
+ // The script text is a format string with a single "%d" appearing in it
+ // which will be replaced by the number of seconds to sleep below.
+ static const char* const scriptText =
+ "sleep %d\n"
+ "echo " SLEEP_END_STRING "\n";
+#elif defined(__WINDOWS__)
+ static const char* const scriptExt = ".bat";
+
+ // Notice that we need to ping N+1 times for it to take N seconds as the
+ // first ping is sent out immediately, without waiting a second.
+ static const char* const scriptText =
+ "@ ping 127.0.0.1 -n 1 > nul\n"
+ "@ ping 127.0.0.1 -n %d > nul\n"
+ "@ echo " SLEEP_END_STRING "\n";
+#else
+ #error "Need code to create sleep file for this platform"
+#endif
+
+ const wxString fnSleep = wxFileName(".", basename, scriptExt).GetFullPath();
+
+ wxFile fileSleep;
+ CPPUNIT_ASSERT
+ (
+ fileSleep.Create(fnSleep, true, wxS_IRUSR | wxS_IWUSR | wxS_IXUSR)
+ );
+
+ fileSleep.Write(wxString::Format(scriptText, seconds));
+
+ return fnSleep;
+}
+
+// static
+wxString ExecTestCase::MakeShellCommand(const wxString& filename)
+{
+ wxString command;
+
+#ifdef __UNIX__
+ command = "/bin/sh " + filename;
+#elif defined(__WINDOWS__)
+ command = wxString::Format("cmd.exe /c \"%s\"", filename);
+#else
+ #error "Need to code to launch shell for this platform"
+#endif
+
+ return command;
+}
+
+void ExecTestCase::TestOverlappedSyncExecute()
+{
+ // Windows Synchronous wxExecute implementation does not currently
+ // support overlapped event loops. It is still using wxYield, which is
+ // not nestable. Therefore, this test would fail in Windows.
+ // If someday somebody changes that in Windows, they could use this
+ // test to verify it.
+ //
+ // Because MSW is not yet ready for this test, it may make sense to
+ // separate it out to its own test suite, so we could register it under
+ // "fixme" for Windows, but a real test for Unix. But that is more work,
+ // so just #ifndefing it here for now.
+ //
+ // Too bad you can't just register one test case of a test suite as a
+ // "fixme".
+#ifndef __WXMSW__
+ // Simple helper delaying the call to wxExecute(): instead of running it
+ // immediately, it runs it when we re-enter the event loop.
+ class DelayedExecuteTimer : public wxTimer
+ {
+ public:
+ DelayedExecuteTimer(const wxString& command, wxArrayString& outputArray)
+ : m_command(command),
+ m_outputArray(outputArray)
+ {
+ // The exact delay doesn't matter, anything short enough will do.
+ StartOnce(10);
+ }
+
+ virtual void Notify()
+ {
+ wxExecute(m_command, m_outputArray);
+ }
+
+ private:
+ wxString m_command;
+ wxArrayString& m_outputArray;
+ };
+
+ // Create two scripts with one of them taking longer than the other one to
+ // execute.
+ const wxString shortSleepFile = CreateSleepFile("shortsleep", 1);
+ wxON_BLOCK_EXIT1( wxRemoveFile, shortSleepFile );
+ const wxString longSleepFile = CreateSleepFile("longsleep", 2);
+ wxON_BLOCK_EXIT1( wxRemoveFile, longSleepFile );
+
+ const wxString shortSleepCommand = MakeShellCommand(shortSleepFile);
+ const wxString longSleepCommand = MakeShellCommand(longSleepFile);
+
+ // Collect the child process output
+ wxArrayString shortSleepOutput,
+ longSleepOutput;
+
+ // Test that launching a process taking a longer time to run while the
+ // shorter process is running works, i.e. that our outer wxExecute()
+ // doesn't return until both process terminate.
+ DelayedExecuteTimer delayLongSleep(longSleepCommand, longSleepOutput);
+ wxExecute(shortSleepCommand, shortSleepOutput);
+ CPPUNIT_ASSERT( !shortSleepOutput.empty() );
+ CPPUNIT_ASSERT_EQUAL( SLEEP_END_STRING, shortSleepOutput.Last() );
+
+ CPPUNIT_ASSERT( !longSleepOutput.empty() );
+ CPPUNIT_ASSERT_EQUAL( SLEEP_END_STRING, longSleepOutput.Last() );
+
+ // And also that, vice versa, running a short-lived child process that both
+ // starts and ends while a longer-lived parent process is still running
+ // works too.
+ DelayedExecuteTimer delayShortSleep(shortSleepCommand, shortSleepOutput);
+ wxExecute(longSleepCommand, longSleepOutput);
+ CPPUNIT_ASSERT( !shortSleepOutput.empty() );
+ CPPUNIT_ASSERT_EQUAL( SLEEP_END_STRING, shortSleepOutput.Last() );
+
+ CPPUNIT_ASSERT( !longSleepOutput.empty() );
+ CPPUNIT_ASSERT_EQUAL( SLEEP_END_STRING, longSleepOutput.Last() );
+#endif // !__WXMSW__
+}
diff --git a/tests/makefile.bcc b/tests/makefile.bcc
index 4013df583e..cfeaf4e58d 100644
--- a/tests/makefile.bcc
+++ b/tests/makefile.bcc
@@ -198,6 +198,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_evtlooptest.obj \
$(OBJS)\test_gui_propagation.obj \
$(OBJS)\test_gui_keyboard.obj \
+ $(OBJS)\test_gui_exec.obj \
$(OBJS)\test_gui_fonttest.obj \
$(OBJS)\test_gui_image.obj \
$(OBJS)\test_gui_rawbmp.obj \
@@ -953,6 +954,9 @@ $(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp
$(OBJS)\test_gui_keyboard.obj: .\events\keyboard.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\events\keyboard.cpp
+$(OBJS)\test_gui_exec.obj: .\exec\exec.cpp
+ $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\exec\exec.cpp
+
$(OBJS)\test_gui_fonttest.obj: .\font\fonttest.cpp
$(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\font\fonttest.cpp
diff --git a/tests/makefile.gcc b/tests/makefile.gcc
index 875dd6c0c9..6f9766096d 100644
--- a/tests/makefile.gcc
+++ b/tests/makefile.gcc
@@ -192,6 +192,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_evtlooptest.o \
$(OBJS)\test_gui_propagation.o \
$(OBJS)\test_gui_keyboard.o \
+ $(OBJS)\test_gui_exec.o \
$(OBJS)\test_gui_fonttest.o \
$(OBJS)\test_gui_image.o \
$(OBJS)\test_gui_rawbmp.o \
@@ -942,6 +943,9 @@ $(OBJS)\test_gui_propagation.o: ./events/propagation.cpp
$(OBJS)\test_gui_keyboard.o: ./events/keyboard.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+$(OBJS)\test_gui_exec.o: ./exec/exec.cpp
+ $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
+
$(OBJS)\test_gui_fonttest.o: ./font/fonttest.cpp
$(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $<
diff --git a/tests/makefile.vc b/tests/makefile.vc
index 09066b2462..e0e9237a10 100644
--- a/tests/makefile.vc
+++ b/tests/makefile.vc
@@ -195,6 +195,7 @@ TEST_GUI_OBJECTS = \
$(OBJS)\test_gui_evtlooptest.obj \
$(OBJS)\test_gui_propagation.obj \
$(OBJS)\test_gui_keyboard.obj \
+ $(OBJS)\test_gui_exec.obj \
$(OBJS)\test_gui_fonttest.obj \
$(OBJS)\test_gui_image.obj \
$(OBJS)\test_gui_rawbmp.obj \
@@ -1093,6 +1094,9 @@ $(OBJS)\test_gui_propagation.obj: .\events\propagation.cpp
$(OBJS)\test_gui_keyboard.obj: .\events\keyboard.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\events\keyboard.cpp
+$(OBJS)\test_gui_exec.obj: .\exec\exec.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\exec\exec.cpp
+
$(OBJS)\test_gui_fonttest.obj: .\font\fonttest.cpp
$(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\font\fonttest.cpp
diff --git a/tests/makefile.wat b/tests/makefile.wat
index 505bfa3232..916f203450 100644
--- a/tests/makefile.wat
+++ b/tests/makefile.wat
@@ -467,6 +467,7 @@ TEST_GUI_OBJECTS = &
$(OBJS)\test_gui_evtlooptest.obj &
$(OBJS)\test_gui_propagation.obj &
$(OBJS)\test_gui_keyboard.obj &
+ $(OBJS)\test_gui_exec.obj &
$(OBJS)\test_gui_fonttest.obj &
$(OBJS)\test_gui_image.obj &
$(OBJS)\test_gui_rawbmp.obj &
@@ -1002,6 +1003,9 @@ $(OBJS)\test_gui_propagation.obj : .AUTODEPEND .\events\propagation.cpp
$(OBJS)\test_gui_keyboard.obj : .AUTODEPEND .\events\keyboard.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
+$(OBJS)\test_gui_exec.obj : .AUTODEPEND .\exec\exec.cpp
+ $(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
+
$(OBJS)\test_gui_fonttest.obj : .AUTODEPEND .\font\fonttest.cpp
$(CXX) -bt=nt -zq -fo=$^@ $(TEST_GUI_CXXFLAGS) $<
diff --git a/tests/test.bkl b/tests/test.bkl
index afe4637ef0..6fc4e1802a 100644
--- a/tests/test.bkl
+++ b/tests/test.bkl
@@ -196,6 +196,11 @@
events/evtlooptest.cpp
events/propagation.cpp
events/keyboard.cpp
+
+ exec/exec.cpp
font/fonttest.cpp
image/image.cpp
image/rawbmp.cpp
diff --git a/tests/test_test.dsp b/tests/test_test.dsp
index 287a816edc..7b919a7755 100644
--- a/tests/test_test.dsp
+++ b/tests/test_test.dsp
@@ -27,13 +27,13 @@ CFG=test - Win32 Debug
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "test - Win32 DLL Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test - Win32 DLL Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "vc_mswudll"
# PROP BASE Intermediate_Dir "vc_mswudll\test"
# PROP BASE Target_Dir ""
diff --git a/tests/test_test_gui.dsp b/tests/test_test_gui.dsp
index 14a6c42d77..ff7a82e362 100644
--- a/tests/test_test_gui.dsp
+++ b/tests/test_test_gui.dsp
@@ -27,13 +27,13 @@ CFG=test_gui - Win32 Debug
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "test_gui - Win32 DLL Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_gui - Win32 DLL Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "vc_mswudll"
# PROP BASE Intermediate_Dir "vc_mswudll\test_gui"
# PROP BASE Target_Dir ""
@@ -233,6 +233,10 @@ SOURCE=.\events\evtlooptest.cpp
# End Source File
# Begin Source File
+SOURCE=.\exec\exec.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\font\fonttest.cpp
# End Source File
# Begin Source File
@@ -378,16 +382,16 @@ SOURCE=.\controls\richtextctrltest.cpp
# Begin Source File
SOURCE=.\..\samples\sample.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\controls\searchctrltest.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\misc\selstoretest.cpp
-# End Source File
-# Begin Source File
+# End Source File
+# Begin Source File
+
+SOURCE=.\controls\searchctrltest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\misc\selstoretest.cpp
+# End Source File
+# Begin Source File
SOURCE=.\window\setsize.cpp
# End Source File
diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj
index 012dcdaf5a..7b39bc6cdb 100644
--- a/tests/test_vc7_test_gui.vcproj
+++ b/tests/test_vc7_test_gui.vcproj
@@ -391,6 +391,9 @@
+
+
diff --git a/tests/test_vc8_test_gui.vcproj b/tests/test_vc8_test_gui.vcproj
index a9abb0833f..dbf7879e77 100644
--- a/tests/test_vc8_test_gui.vcproj
+++ b/tests/test_vc8_test_gui.vcproj
@@ -557,6 +557,10 @@
RelativePath=".\events\evtlooptest.cpp"
>
+
+
diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj
index 640de7a67d..fe1efbf348 100644
--- a/tests/test_vc9_test_gui.vcproj
+++ b/tests/test_vc9_test_gui.vcproj
@@ -543,6 +543,10 @@
RelativePath=".\events\evtlooptest.cpp"
>
+
+