--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: execmon.cpp
+// Purpose: A simple execution monitor to test if wx samples crash at startup or not
+// Author: Francesco Montorsi
+// Modified by:
+// Created: 25/3/09
+// RCS-ID: $Id$
+// Copyright: (c) 2009 Francesco Montorsi
+// Licence: wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#endif // WX_PRECOMP
+
+#include "wx/cmdline.h"
+#include "wx/vector.h"
+#include "wx/process.h"
+#include "wx/sstream.h"
+#include "wx/utils.h"
+#include "wx/filename.h"
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// utility classes
+// ----------------------------------------------------------------------------
+
+class MonitoredProcess : public wxProcess
+{
+public:
+ MonitoredProcess()
+ { Redirect(); m_crashed=false; m_exitCode=0; }
+
+ void OnTerminate(int WXUNUSED(pid), int status)
+ {
+ wxStringOutputStream stdout, stderr;
+ if (GetInputStream()) stdout.Write(*GetInputStream());
+ if (GetErrorStream()) stderr.Write(*GetErrorStream());
+
+ //wxPrintf("%s\n", stdout.GetString());
+ //wxPrintf("%s\n", stderr.GetString());
+
+ // when wx programs assert on wxGTK/wxMac, they put on stderr a message like:
+ // [Debug] date somefilename.pp(nnnn): assert "xxxxx" failed in yyyy
+ // but then the assert dialog pop-ups and thus the app doesn't exit
+ // FIXME: make assertion detection work also under other platforms
+ // see http://trac.wxwidgets.org/ticket/10697
+ m_crashed = stdout.GetString().Contains("assert") ||
+ stderr.GetString().Contains("assert");
+ m_exitCode = status;
+ }
+
+ void Kill()
+ {
+ wxProcess::Kill(GetPid());
+
+ // wxProcess::Kill doesn't trigger a call to OnTerminate() normally...
+ // but we still need to call it!
+ OnTerminate(0, -1);
+ }
+
+ bool Crashed() const
+ { return m_crashed; }
+
+ int GetExitCode() const
+ { return m_exitCode; }
+
+private:
+ bool m_crashed;
+ int m_exitCode;
+};
+
+class MonitorData
+{
+public:
+ MonitorData(const wxString& cmd) : program(cmd) {}
+
+ wxString program;
+ MonitoredProcess process;
+};
+
+// ----------------------------------------------------------------------------
+// the real main
+// ----------------------------------------------------------------------------
+
+bool TestExec(const wxVector<wxFileName>& programs, long timeout)
+{
+ wxVector<MonitorData*> data;
+
+ // run all programs specified as command line parameters
+ wxArrayLong procID;
+ for (size_t i=0; i<programs.size(); i++)
+ {
+ MonitorData *dt = new MonitorData(programs[i].GetFullPath());
+
+ long pid = wxExecute(programs[i].GetFullPath(), wxEXEC_ASYNC, &dt->process);
+ if (pid == 0)
+ wxLogError("could not run the program '%s'", programs[i].GetFullPath());
+ else
+ {
+ wxLogMessage("started program '%s' (pid %d)...",
+ programs[i].GetFullPath(), pid);
+ wxASSERT(dt->process.GetPid() == pid);
+
+ data.push_back(dt);
+ }
+ }
+
+ // sleep some moments
+ wxSleep(timeout);
+
+ // check if all processes are still running
+ bool allok = true;
+ for (size_t i=0; i<data.size(); i++)
+ {
+ MonitoredProcess& proc = data[i]->process;
+ const wxString& prog = data[i]->program;
+
+ if (wxProcess::Exists(proc.GetPid()))
+ proc.Kill();
+ else
+ {
+ // this typically never happens, at least when running wx-programs
+ // built with debug builds of wx (see MonitoredProcess::OnTerminate;
+ // even if an asserts fail the app doesn't automatically close!):
+
+ wxLogMessage("program '%s' (pid %d) is NOT running anymore...",
+ prog, proc.GetPid());
+ allok = false;
+ }
+
+ if (data[i]->process.Crashed())
+ {
+ allok = false;
+ wxLogMessage("program '%s' (pid %d) crashed...",
+ prog, proc.GetPid());
+ }
+ else
+ wxLogMessage("program '%s' (pid %d) ended with exit code %d...",
+ prog, proc.GetPid(), proc.GetExitCode());
+ }
+
+ return allok;
+}
+
+// ----------------------------------------------------------------------------
+// main
+// ----------------------------------------------------------------------------
+
+int main(int argc, char **argv)
+{
+ wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "execmon");
+
+ wxInitializer initializer;
+ if ( !initializer )
+ {
+ fprintf(stderr, "Failed to initialize the wxWidgets library, aborting.");
+ return -1;
+ }
+
+ static const wxCmdLineEntryDesc cmdLineDesc[] =
+ {
+ { wxCMD_LINE_SWITCH, "h", "help",
+ "show this help message",
+ wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
+ { wxCMD_LINE_OPTION, "t", "timeout",
+ "kills all processes still alive after 'num' seconds",
+ wxCMD_LINE_VAL_NUMBER, 0 },
+ { wxCMD_LINE_PARAM, "", "",
+ "program-to-run",
+ wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE },
+
+ { wxCMD_LINE_NONE }
+ };
+
+ wxLog::DisableTimestamp();
+
+ wxCmdLineParser parser(cmdLineDesc, argc, argv);
+ switch ( parser.Parse() )
+ {
+ case -1:
+ // help was shown
+ break;
+
+ case 0:
+ {
+ // check arguments
+ wxVector<wxFileName> programs;
+ for (unsigned int i=0; i<parser.GetParamCount(); i++)
+ {
+ wxFileName fn(parser.GetParam(i));
+ if (!fn.IsAbsolute())
+ fn.MakeAbsolute();
+
+ programs.push_back(fn);
+ }
+
+ long timeout;
+ if (!parser.Found("t", &timeout))
+ timeout = 3;
+
+ return TestExec(programs, timeout) ? 0 : 1;
+ }
+ break;
+
+ default:
+ // syntax error
+ break;
+ }
+
+ return 0;
+}
+