tests/auto/qsharedpointer/externaltests.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include "externaltests.h"
       
    44 
       
    45 #include <QtCore/QTemporaryFile>
       
    46 #include <QtCore/QProcess>
       
    47 #include <QtCore/QByteArray>
       
    48 #include <QtCore/QString>
       
    49 #include <QtCore/QFileInfo>
       
    50 #include <QtCore/QDir>
       
    51 #include <QtCore/QDirIterator>
       
    52 #include <QtCore/QDateTime>
       
    53 
       
    54 #ifdef Q_OS_SYMBIAN
       
    55 #define DEFAULT_MAKESPEC "X:/STLsupport/mkspecs/symbian-abld/"
       
    56 #endif
       
    57 
       
    58 #ifndef DEFAULT_MAKESPEC
       
    59 # error DEFAULT_MAKESPEC not defined
       
    60 #endif
       
    61 
       
    62 #ifdef Q_OS_UNIX
       
    63 # include <fcntl.h>
       
    64 # include <unistd.h>
       
    65 #endif
       
    66 
       
    67 static QString makespec()
       
    68 {
       
    69     static const char default_makespec[] = DEFAULT_MAKESPEC;
       
    70     const char *p;
       
    71     for (p = default_makespec + sizeof(default_makespec) - 1; p >= default_makespec; --p)
       
    72         if (*p == '/' || *p == '\\')
       
    73             break;
       
    74 
       
    75     return QString::fromLatin1(p + 1);
       
    76 }
       
    77 
       
    78 static bool removeRecursive(const QString &pathname)
       
    79 {
       
    80     QFileInfo fi(pathname);
       
    81     if (!fi.exists())
       
    82         return true;
       
    83 
       
    84     if (fi.isFile())
       
    85         return QFile::remove(pathname);
       
    86 
       
    87     if (!fi.isDir()) {
       
    88         //  not a file or directory. How do I remove it?
       
    89         return false;
       
    90     }
       
    91 
       
    92     // not empty -- we must empty it first
       
    93     QDirIterator di(pathname, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
       
    94     while (di.hasNext()) {
       
    95         di.next();
       
    96         if (!di.fileInfo().exists() && !di.fileInfo().isSymLink())
       
    97             continue;
       
    98         bool ok;
       
    99         if (di.fileInfo().isFile() || di.fileInfo().isSymLink())
       
   100             ok = QFile::remove(di.filePath());
       
   101         else
       
   102             ok = removeRecursive(di.filePath());
       
   103         if (!ok) {
       
   104             return false;
       
   105         }
       
   106     }
       
   107 
       
   108     QDir dir(pathname);
       
   109     QString dirname = dir.dirName();
       
   110     dir.cdUp();
       
   111     return dir.rmdir(dirname);
       
   112 }
       
   113 
       
   114 QT_BEGIN_NAMESPACE
       
   115 namespace QTest {
       
   116     class QExternalProcess: public QProcess
       
   117     {
       
   118     protected:
       
   119 #ifdef Q_OS_UNIX
       
   120         void setupChildProcess()
       
   121         {
       
   122             // run in user code
       
   123             QProcess::setupChildProcess();
       
   124 
       
   125             if (processChannelMode() == ForwardedChannels) {
       
   126                 // reopen /dev/tty into stdin
       
   127                 int fd = ::open("/dev/tty", O_RDONLY);
       
   128                 if (fd == -1)
       
   129                     return;
       
   130                 ::dup2(fd, 0);
       
   131                 ::close(fd);
       
   132             }
       
   133         }
       
   134 #endif
       
   135     };
       
   136 
       
   137     class QExternalTestPrivate
       
   138     {
       
   139     public:
       
   140         QExternalTestPrivate()
       
   141             : qtModules(QExternalTest::QtCore | QExternalTest::QtGui | QExternalTest::QtTest),
       
   142               appType(QExternalTest::AutoApplication),
       
   143               debugMode(true),
       
   144               exitCode(-1)
       
   145         {
       
   146         }
       
   147         ~QExternalTestPrivate()
       
   148         {
       
   149             clear();
       
   150         }
       
   151 
       
   152         enum Target { Compile, Link, Run };
       
   153 
       
   154         QList<QByteArray> qmakeLines;
       
   155         QStringList extraProgramSources;
       
   156         QByteArray programHeader;
       
   157         QExternalTest::QtModules qtModules;
       
   158         QExternalTest::ApplicationType appType;
       
   159         bool debugMode;
       
   160 
       
   161         QString temporaryDir;
       
   162         QByteArray sourceCode;
       
   163         QByteArray std_out;
       
   164         QByteArray std_err;
       
   165         int exitCode;
       
   166         QExternalTest::Stage failedStage;
       
   167 
       
   168         void clear();
       
   169         bool tryCompile(const QByteArray &body);
       
   170         bool tryLink(const QByteArray &body);
       
   171         bool tryRun(const QByteArray &body);
       
   172 
       
   173     private:
       
   174         void removeTemporaryDirectory();
       
   175         bool createTemporaryDirectory();
       
   176         bool prepareSourceCode(const QByteArray &body);
       
   177         bool createProjectFile();
       
   178         bool runQmake();
       
   179         bool runMake(Target target);
       
   180         bool commonSetup(const QByteArray &body);
       
   181     };
       
   182 
       
   183     QExternalTest::QExternalTest()
       
   184         : d(new QExternalTestPrivate)
       
   185     {
       
   186     }
       
   187 
       
   188     QExternalTest::~QExternalTest()
       
   189     {
       
   190         delete d;
       
   191     }
       
   192 
       
   193     bool QExternalTest::isDebugMode() const
       
   194     {
       
   195         return d->debugMode;
       
   196     }
       
   197 
       
   198     void QExternalTest::setDebugMode(bool enable)
       
   199     {
       
   200         d->debugMode = enable;
       
   201     }
       
   202 
       
   203     QList<QByteArray> QExternalTest::qmakeSettings() const
       
   204     {
       
   205         return d->qmakeLines;
       
   206     }
       
   207 
       
   208     void QExternalTest::setQmakeSettings(const QList<QByteArray> &settings)
       
   209     {
       
   210         d->qmakeLines = settings;
       
   211     }
       
   212 
       
   213     QExternalTest::QtModules QExternalTest::qtModules() const
       
   214     {
       
   215         return d->qtModules;
       
   216     }
       
   217 
       
   218     void QExternalTest::setQtModules(QtModules modules)
       
   219     {
       
   220         d->qtModules = modules;
       
   221     }
       
   222 
       
   223     QExternalTest::ApplicationType QExternalTest::applicationType() const
       
   224     {
       
   225         return d->appType;
       
   226     }
       
   227 
       
   228     void QExternalTest::setApplicationType(ApplicationType type)
       
   229     {
       
   230         d->appType = type;
       
   231     }
       
   232 
       
   233     QStringList QExternalTest::extraProgramSources() const
       
   234     {
       
   235         return d->extraProgramSources;
       
   236     }
       
   237 
       
   238     void QExternalTest::setExtraProgramSources(const QStringList &extra)
       
   239     {
       
   240         d->extraProgramSources = extra;
       
   241     }
       
   242 
       
   243     QByteArray QExternalTest::programHeader() const
       
   244     {
       
   245         return d->programHeader;
       
   246     }
       
   247 
       
   248     void QExternalTest::setProgramHeader(const QByteArray &header)
       
   249     {
       
   250         d->programHeader = header;
       
   251     }
       
   252 
       
   253     bool QExternalTest::tryCompile(const QByteArray &body)
       
   254     {
       
   255         return d->tryCompile(body) && d->exitCode == 0;
       
   256     }
       
   257 
       
   258     bool QExternalTest::tryLink(const QByteArray &body)
       
   259     {
       
   260         return d->tryLink(body) && d->exitCode == 0;
       
   261     }
       
   262 
       
   263     bool QExternalTest::tryRun(const QByteArray &body)
       
   264     {
       
   265         return d->tryRun(body) && d->exitCode == 0;
       
   266     }
       
   267 
       
   268     bool QExternalTest::tryCompileFail(const QByteArray &body)
       
   269     {
       
   270         return d->tryCompile(body) && d->exitCode != 0;
       
   271     }
       
   272 
       
   273     bool QExternalTest::tryLinkFail(const QByteArray &body)
       
   274     {
       
   275         return d->tryLink(body) && d->exitCode != 0;
       
   276     }
       
   277 
       
   278     bool QExternalTest::tryRunFail(const QByteArray &body)
       
   279     {
       
   280         return d->tryRun(body) && d->exitCode != 0;
       
   281     }
       
   282 
       
   283     QExternalTest::Stage QExternalTest::failedStage() const
       
   284     {
       
   285         return d->failedStage;
       
   286     }
       
   287 
       
   288     int QExternalTest::exitCode() const
       
   289     {
       
   290         return d->exitCode;
       
   291     }
       
   292 
       
   293     QByteArray QExternalTest::fullProgramSource() const
       
   294     {
       
   295         return d->sourceCode;
       
   296     }
       
   297 
       
   298     QByteArray QExternalTest::standardOutput() const
       
   299     {
       
   300         return d->std_out;
       
   301     }
       
   302 
       
   303     QByteArray QExternalTest::standardError() const
       
   304     {
       
   305         return d->std_err;
       
   306     }
       
   307 
       
   308     QString QExternalTest::errorReport() const
       
   309     {
       
   310         const char *stage = 0;
       
   311         switch (d->failedStage) {
       
   312         case FileStage:
       
   313             stage = "creating files";
       
   314             break;
       
   315         case QmakeStage:
       
   316             stage = "executing qmake";
       
   317             break;
       
   318         case CompilationStage:
       
   319             stage = "during compilation";
       
   320             break;
       
   321         case LinkStage:
       
   322             stage = "during linking";
       
   323             break;
       
   324         case RunStage:
       
   325             stage = "executing program";
       
   326             break;
       
   327         }
       
   328 
       
   329         QString report = QString::fromLatin1(
       
   330             "External test failed %1 with exit code %4\n"
       
   331             "==== standard error: ====\n"
       
   332             "%2\n"
       
   333             "==== standard output: ====\n"
       
   334             "%3\n"
       
   335             "==== ====\n");
       
   336         return report.arg(QString::fromLatin1(stage),
       
   337                           QString::fromLocal8Bit(d->std_err),
       
   338                           QString::fromLocal8Bit(d->std_out))
       
   339             .arg(d->exitCode);
       
   340     }
       
   341 
       
   342     // actual execution code
       
   343     void QExternalTestPrivate::clear()
       
   344     {
       
   345         if (!temporaryDir.isEmpty())
       
   346             removeTemporaryDirectory();
       
   347 
       
   348         sourceCode.clear();
       
   349         std_out.clear();
       
   350         std_err.clear();
       
   351         exitCode = -1;
       
   352         failedStage = QExternalTest::FileStage;
       
   353     }
       
   354 
       
   355     void QExternalTestPrivate::removeTemporaryDirectory()
       
   356     {
       
   357         Q_ASSERT(!temporaryDir.isEmpty());
       
   358         removeRecursive(temporaryDir);
       
   359         temporaryDir.clear();
       
   360     }
       
   361 
       
   362     bool QExternalTestPrivate::prepareSourceCode(const QByteArray &body)
       
   363     {
       
   364         sourceCode.clear();
       
   365         sourceCode.reserve(8192);
       
   366 
       
   367         sourceCode += programHeader;
       
   368 
       
   369         // Add Qt header includes
       
   370         if (qtModules & QExternalTest::QtCore)
       
   371             sourceCode += "#include <QtCore/QtCore>\n";
       
   372         if (qtModules & QExternalTest::QtGui)
       
   373             sourceCode += "#include <QtGui/QtGui>\n";
       
   374         if (qtModules & QExternalTest::QtNetwork)
       
   375             sourceCode += "#include <QtNetwork/QtNetwork>\n";
       
   376         if (qtModules & QExternalTest::QtXml)
       
   377             sourceCode += "#include <QtXml/QtXml>\n";
       
   378         if (qtModules & QExternalTest::QtXmlPatterns)
       
   379             sourceCode += "#include <QtXmlPatterns/QtXmlPatterns>\n";
       
   380         if (qtModules & QExternalTest::QtOpenGL)
       
   381             sourceCode += "#include <QtOpenGL/QtOpenGL>\n";
       
   382         if (qtModules & QExternalTest::QtSql)
       
   383             sourceCode += "#include <QtSql/QtSql>\n";
       
   384         if (qtModules & QExternalTest::Qt3Support)
       
   385             sourceCode += "#include <Qt3Support/Qt3Support>\n";
       
   386         if (qtModules & QExternalTest::QtSvg)
       
   387             sourceCode += "#include <QtSvg/QtSvg>\n";
       
   388         if (qtModules & QExternalTest::QtScript)
       
   389             sourceCode += "#include <QtScript/QtScript>\n";
       
   390         if (qtModules & QExternalTest::QtTest)
       
   391             sourceCode += "#include <QtTest/QtTest>\n";
       
   392         if (qtModules & QExternalTest::QtDBus)
       
   393             sourceCode += "#include <QtDBus/QtDBus>\n";
       
   394         if (qtModules & QExternalTest::QtWebKit)
       
   395             sourceCode += "#include <QtWebKit/QtWebKit>\n";
       
   396         if (qtModules & QExternalTest::Phonon)
       
   397             sourceCode += "#include <Phonon/Phonon>\n";
       
   398         sourceCode +=
       
   399             "#include <stdlib.h>\n"
       
   400             "#include <stddef.h>\n";
       
   401 
       
   402         sourceCode +=
       
   403             "\n"
       
   404             "void q_external_test_user_code()\n"
       
   405             "{\n"
       
   406             "#include \"user_code.cpp\"\n"
       
   407             "}\n"
       
   408             "\n"
       
   409             "#ifdef Q_OS_WIN\n"
       
   410             "#include <windows.h>\n"
       
   411             "static void q_test_setup()\n"
       
   412             "{\n"
       
   413             "    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n"
       
   414             "}\n"
       
   415             "#else\n"
       
   416             "static void q_test_setup() { }\n"
       
   417             "#endif\n"
       
   418             "int main(int argc, char **argv)\n"
       
   419             "{\n";
       
   420 
       
   421         switch (appType) {
       
   422         applicationless:
       
   423         case QExternalTest::Applicationless:
       
   424             sourceCode +=
       
   425                 "    (void)argc; (void)argv;\n";
       
   426             break;
       
   427 
       
   428         coreapplication:
       
   429         case QExternalTest::QCoreApplication:
       
   430             sourceCode +=
       
   431                 "    QCoreApplication app(argc, argv);\n";
       
   432             break;
       
   433 
       
   434         case QExternalTest::QApplicationTty:
       
   435             sourceCode +=
       
   436                 "    QApplication app(argc, argv, QApplication::Tty);\n";
       
   437             break;
       
   438 
       
   439         guiapplication:
       
   440         case QExternalTest::QApplicationGuiClient:
       
   441             sourceCode +=
       
   442                 "    QApplication app(argc, argv, QApplication::GuiClient);\n";
       
   443             break;
       
   444 
       
   445         case QExternalTest::QApplicationGuiServer:
       
   446             sourceCode +=
       
   447                 "    QApplication app(argc, argv, QApplication::GuiServer);\n";
       
   448             break;
       
   449 
       
   450         case QExternalTest::AutoApplication:
       
   451             if (qtModules & QExternalTest::QtGui)
       
   452                 goto guiapplication;
       
   453             if (qtModules == 0)
       
   454                 goto applicationless;
       
   455             goto coreapplication;
       
   456         }
       
   457 
       
   458         sourceCode +=
       
   459             "    q_test_setup();\n"
       
   460             "    q_external_test_user_code();\n"
       
   461             "    return 0;\n"
       
   462             "}\n";
       
   463 
       
   464         QFile sourceFile(temporaryDir + QLatin1String("/project.cpp"));
       
   465         if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
       
   466             std_err = sourceFile.errorString().toLocal8Bit();
       
   467             return false;
       
   468         }
       
   469 
       
   470         sourceFile.write(sourceCode);
       
   471         sourceFile.close();
       
   472 
       
   473         sourceFile.setFileName(temporaryDir + QLatin1String("/user_code.cpp"));
       
   474         if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
       
   475             std_err = sourceFile.errorString().toLocal8Bit();
       
   476             return false;
       
   477         }
       
   478         sourceFile.write(body);
       
   479 
       
   480         return true;
       
   481     }
       
   482 
       
   483     bool QExternalTestPrivate::createTemporaryDirectory()
       
   484     {
       
   485         QDir temp = QDir::temp();
       
   486         QString subdir = QString::fromLatin1("qexternaltest-%1-%2-%3")
       
   487                         .arg(QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")))
       
   488                         .arg(quintptr(this), 0, 16)
       
   489                         .arg(qrand());
       
   490         if (!temp.mkdir(subdir))
       
   491             return false;
       
   492 
       
   493         if (!temp.cd(subdir))
       
   494             return false;
       
   495 
       
   496         temporaryDir = temp.absolutePath();
       
   497         return true;
       
   498     }
       
   499 
       
   500     bool QExternalTestPrivate::createProjectFile()
       
   501     {
       
   502         Q_ASSERT(!temporaryDir.isEmpty());
       
   503 
       
   504         QFile projectFile(temporaryDir + QLatin1String("/project.pro"));
       
   505         if (!projectFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
       
   506             std_err = projectFile.errorString().toLocal8Bit();
       
   507             return false;
       
   508         }
       
   509 
       
   510         projectFile.write(
       
   511             "TEMPLATE = app\n"
       
   512             "\n"
       
   513             "TARGET   = externaltest\n"
       
   514             "CONFIG   -= app_bundle\n"        // for the Mac
       
   515             "CONFIG   -= debug_and_release\n"
       
   516             "DESTDIR  = .\n"
       
   517             "OBJECTS_DIR = .\n"
       
   518             "UI_DIR   = .\n"
       
   519             "MOC_DIR  = .\n"
       
   520             "RCC_DIR  = .\n"
       
   521             "HEADERS  +=\n"
       
   522             "SOURCES  += project.cpp\n"
       
   523             "QT       -= core gui\n"
       
   524             "INCLUDEPATH += . ");
       
   525         projectFile.write(QFile::encodeName(QDir::currentPath()));
       
   526 
       
   527         if (debugMode)
       
   528             projectFile.write("\nCONFIG  += debug\n");
       
   529         else
       
   530             projectFile.write("\nCONFIG  += release\n");
       
   531 
       
   532         QByteArray extraSources = QFile::encodeName(extraProgramSources.join(" "));
       
   533         if (!extraSources.isEmpty()) {
       
   534             projectFile.write("SOURCES  += ");
       
   535             projectFile.write(extraSources);
       
   536             projectFile.putChar('\n');
       
   537         }
       
   538 
       
   539         // Add Qt modules
       
   540         if (qtModules & QExternalTest::QtCore)
       
   541             projectFile.write("QT += core\n");
       
   542         if (qtModules & QExternalTest::QtGui)
       
   543             projectFile.write("QT += gui\n");
       
   544         if (qtModules & QExternalTest::QtNetwork)
       
   545             projectFile.write("QT += network\n");
       
   546         if (qtModules & QExternalTest::QtXml)
       
   547             projectFile.write("QT += xml\n");
       
   548         if (qtModules & QExternalTest::QtXmlPatterns)
       
   549             projectFile.write("QT += xmlpatterns\n");
       
   550         if (qtModules & QExternalTest::QtOpenGL)
       
   551             projectFile.write("QT += opengl\n");
       
   552         if (qtModules & QExternalTest::QtSql)
       
   553             projectFile.write("QT += sql\n");
       
   554         if (qtModules & QExternalTest::Qt3Support)
       
   555             projectFile.write("QT += qt3support\n");
       
   556         if (qtModules & QExternalTest::QtSvg)
       
   557             projectFile.write("QT += svg\n");
       
   558         if (qtModules & QExternalTest::QtScript)
       
   559             projectFile.write("QT += script\n");
       
   560         if (qtModules & QExternalTest::QtTest)
       
   561             projectFile.write("QT += testlib\n");
       
   562         if (qtModules & QExternalTest::QtDBus)
       
   563             projectFile.write("QT += dbus\n");
       
   564         if (qtModules & QExternalTest::QtWebKit)
       
   565             projectFile.write("QT += webkit\n");
       
   566         if (qtModules & QExternalTest::Phonon)
       
   567             projectFile.write("QT += phonon\n");
       
   568 
       
   569         projectFile.write("\n### User-specified settings start ###\n");
       
   570         foreach (QByteArray line, qmakeLines) {
       
   571             projectFile.write(line);
       
   572             projectFile.write("\n");
       
   573         }
       
   574         projectFile.write("\n### User-specified settings end ###\n");
       
   575 
       
   576         // Use qmake to just compile:
       
   577         projectFile.write(
       
   578             "\n"
       
   579             "test_compile.depends        += $(OBJECTS)\n"
       
   580             "QMAKE_EXTRA_TARGETS += test_compile\n");
       
   581 
       
   582         // Use qmake to run the app too:
       
   583         projectFile.write(
       
   584             "\n"
       
   585             "unix:test_run.commands     = ./$(QMAKE_TARGET)\n"
       
   586             "else:test_run.commands     = $(QMAKE_TARGET)\n"
       
   587             "embedded:test_run.commands += -qws\n"
       
   588             "QMAKE_EXTRA_TARGETS += test_run\n");
       
   589 
       
   590         // Use qmake to debug:
       
   591         projectFile.write(
       
   592             "\n"
       
   593             "*-g++* {\n"
       
   594             "    unix:test_debug.commands      =  gdb --args ./$(QMAKE_TARGET)\n"
       
   595             "    else:test_debug.commands      = gdb --args $(QMAKE_TARGET)\n"
       
   596             "    embedded:test_debug.commands += -qws\n"
       
   597             "    QMAKE_EXTRA_TARGETS += test_debug\n"
       
   598             "}\n");
       
   599 
       
   600         // Also use qmake to run the app with valgrind:
       
   601         projectFile.write(
       
   602             "\n"
       
   603             "unix:test_valgrind.commands      = valgrind ./$(QMAKE_TARGET)\n"
       
   604             "else:test_valgrind.commands      = valgrind $(QMAKE_TARGET)\n"
       
   605             "embedded:test_valgrind.commands += -qws\n"
       
   606             "QMAKE_EXTRA_TARGETS    += test_valgrind\n");
       
   607 
       
   608         return true;
       
   609     }
       
   610 
       
   611     bool QExternalTestPrivate::runQmake()
       
   612     {
       
   613         Q_ASSERT(!temporaryDir.isEmpty());
       
   614         if (!createProjectFile())
       
   615             return false;
       
   616 
       
   617         failedStage = QExternalTest::QmakeStage;
       
   618         QProcess qmake;
       
   619         QStringList args;
       
   620         args << QLatin1String("-makefile")
       
   621              << QLatin1String("-spec")
       
   622              << makespec()
       
   623              << QLatin1String("project.pro");
       
   624         qmake.setWorkingDirectory(temporaryDir);
       
   625         qmake.start(QLatin1String("qmake"), args);
       
   626 
       
   627         std_out += "### --- stdout from qmake --- ###\n";
       
   628         std_err += "### --- stderr from qmake --- ###\n";
       
   629         bool ok = qmake.waitForStarted();
       
   630         if (!ok) {
       
   631             exitCode = 255;
       
   632             std_err += "qmake: ";
       
   633             std_err += qmake.errorString().toLocal8Bit();
       
   634         } else {
       
   635             ok = qmake.waitForFinished();
       
   636             exitCode = qmake.exitCode();
       
   637 
       
   638             std_out += qmake.readAllStandardOutput();
       
   639             std_err += qmake.readAllStandardError();
       
   640         }
       
   641 
       
   642         return ok && exitCode == 0;
       
   643     }
       
   644 
       
   645     bool QExternalTestPrivate::runMake(Target target)
       
   646     {
       
   647         Q_ASSERT(!temporaryDir.isEmpty());
       
   648 
       
   649         QExternalProcess make;
       
   650         make.setWorkingDirectory(temporaryDir);
       
   651 
       
   652         QStringList environment = QProcess::systemEnvironment();
       
   653         environment += QLatin1String("LC_ALL=C");
       
   654         make.setEnvironment(environment);
       
   655 
       
   656         QStringList args;
       
   657         QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels;
       
   658         if (target == Compile) {
       
   659             args << QLatin1String("test_compile");
       
   660         } else if (target == Run) {
       
   661             QByteArray run = qgetenv("QTEST_EXTERNAL_RUN");
       
   662             if (run == "valgrind")
       
   663                 args << QLatin1String("test_valgrind");
       
   664             else if (run == "debug")
       
   665                 args << QLatin1String("test_debug");
       
   666             else
       
   667                 args << QLatin1String("test_run");
       
   668             if (!run.isEmpty())
       
   669                 channelMode = QProcess::ForwardedChannels;
       
   670         }
       
   671 
       
   672         make.setProcessChannelMode(channelMode);
       
   673 
       
   674 #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW)
       
   675         make.start(QLatin1String("nmake.exe"), args);
       
   676         make.waitForStarted();
       
   677 #else
       
   678         static const char makes[] =
       
   679 # ifdef Q_CC_MINGW
       
   680             "mingw32-make.exe\0"
       
   681 # endif
       
   682             "gmake\0"
       
   683             "make\0";
       
   684         for (const char *p = makes; *p; p += strlen(p) + 1) {
       
   685             make.start(QLatin1String(p), args);
       
   686             if (make.waitForStarted())
       
   687                 break;
       
   688         }
       
   689 #endif
       
   690 
       
   691         if (make.state() != QProcess::Running) {
       
   692             exitCode = 255;
       
   693             std_err += "make: ";
       
   694             std_err += make.errorString().toLocal8Bit();
       
   695             return false;
       
   696         }
       
   697 
       
   698         make.closeWriteChannel();
       
   699         bool ok = make.waitForFinished(channelMode == QProcess::ForwardedChannels ? -1 : 60000);
       
   700         if (!ok)
       
   701             make.terminate();
       
   702         exitCode = make.exitCode();
       
   703         std_out += make.readAllStandardOutput();
       
   704         std_err += make.readAllStandardError();
       
   705 
       
   706         return ok;
       
   707     }
       
   708 
       
   709     bool QExternalTestPrivate::commonSetup(const QByteArray &body)
       
   710     {
       
   711         clear();
       
   712 
       
   713         if (!createTemporaryDirectory())
       
   714             return false;
       
   715         if (!createProjectFile())
       
   716             return false;
       
   717         if (!prepareSourceCode(body))
       
   718             return false;
       
   719         if (!runQmake())
       
   720             return false;
       
   721         return true;
       
   722     }
       
   723 
       
   724     bool QExternalTestPrivate::tryCompile(const QByteArray &body)
       
   725     {
       
   726         if (!commonSetup(body))
       
   727             return false;
       
   728 
       
   729         // compile
       
   730         failedStage = QExternalTest::CompilationStage;
       
   731         std_out += "\n### --- stdout from make (compilation) --- ###\n";
       
   732         std_err += "\n### --- stderr from make (compilation) --- ###\n";
       
   733         return runMake(Compile);
       
   734     }
       
   735 
       
   736     bool QExternalTestPrivate::tryLink(const QByteArray &body)
       
   737     {
       
   738         if (!tryCompile(body) || exitCode != 0)
       
   739             return false;
       
   740 
       
   741         // link
       
   742         failedStage = QExternalTest::LinkStage;
       
   743         std_out += "\n### --- stdout from make (linking) --- ###\n";
       
   744         std_err += "\n### --- stderr from make (linking) --- ###\n";
       
   745         return runMake(Link);
       
   746     }
       
   747 
       
   748     bool QExternalTestPrivate::tryRun(const QByteArray &body)
       
   749     {
       
   750         if (!tryLink(body) || exitCode != 0)
       
   751             return false;
       
   752 
       
   753         // run
       
   754         failedStage = QExternalTest::RunStage;
       
   755         std_out += "\n### --- stdout from process --- ###\n";
       
   756         std_err += "\n### --- stderr from process --- ###\n";
       
   757         return runMake(Run);
       
   758     }
       
   759 }
       
   760 QT_END_NAMESPACE