+// 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 __WINDOWS__
+ // 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 // !__WINDOWS__
+}