tests/auto/guiapplauncher/tst_guiapplauncher.cpp
changeset 3 41300fa6a67c
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
       
     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 #include "windowmanager.h"
       
    43 
       
    44 #include <QtCore/QDir>
       
    45 #include <QtCore/QString>
       
    46 #include <QtTest/QtTest>
       
    47 #include <QtCore/QProcess>
       
    48 #include <QtCore/QByteArray>
       
    49 #include <QtCore/QLibraryInfo>
       
    50 #include <QtCore/QVariant>
       
    51 #include <QtCore/QDateTime>
       
    52 #include <QtCore/QMap>
       
    53 
       
    54 // AppLaunch: Launch gui applications, keep them running a while
       
    55 // (grabbing their top level from the window manager) and send
       
    56 // them a Close event via window manager. Verify that they do not
       
    57 // not crash nor produces unexpected error output.
       
    58 // Note: Do not play with the machine while it is running as otherwise
       
    59 // the top-level find algorithm might get confused (especially on Windows).
       
    60 // Environment variables are checked to turned off some tests
       
    61 // It is currently implemented for X11 and Windows, pending an
       
    62 // implementation of the WindowManager class and deployment on
       
    63 // the other platforms.
       
    64 
       
    65 enum  { defaultUpTimeMS = 3000, defaultTopLevelWindowTimeoutMS = 30000,
       
    66         defaultTerminationTimeoutMS = 35000 };
       
    67 
       
    68 // List the examples to test (Gui examples only).
       
    69 struct Example {
       
    70     const char *name;
       
    71     const char *directory;
       
    72     const char *binary;
       
    73     unsigned priority; // 0-highest
       
    74     int upTimeMS;
       
    75 };
       
    76 
       
    77 const struct Example examples[] = {
       
    78     {"animation/animatedtiles Example", "animation/animatedtiles", "animatedtiles", 0, -1},
       
    79     {"animation/appchooser Example", "animation/appchooser", "appchooser", 10, -1},
       
    80     {"animation/easing Example", "animation/easing", "easing", 10, -1},
       
    81     {"animation/moveblocks Example", "animation/moveblocks", "moveblocks", 10, -1},
       
    82     {"animation/states Example", "animation/states", "states", 10, -1},
       
    83     {"animation/stickman Example", "animation/stickman", "stickman", 10, -1},
       
    84     {"designer/calculatorbuilder Example", "designer/calculatorbuilder", "calculatorbuilder", 10, -1},
       
    85     {"dialogs/standarddialogs Example", "dialogs/standarddialogs", "standarddialogs", 10, -1},
       
    86     {"draganddrop/dropsite Example", "draganddrop/dropsite", "dropsite", 10, -1},
       
    87     {"draganddrop/fridgemagnets Example", "draganddrop/fridgemagnets", "fridgemagnets", 10, -1},
       
    88     {"draganddrop/puzzle Example", "draganddrop/puzzle", "puzzle", 10, -1},
       
    89     {"effects/blurpicker Example", "effects/blurpicker", "blurpicker", 10, -1},
       
    90     {"effects/customshader Example", "effects/customshader", "customshader", 10, -1},
       
    91     {"effects/fademessage Example", "effects/fademessage", "fademessage", 10, -1},
       
    92     {"effects/lighting Example", "effects/lighting", "lighting", 10, -1},
       
    93     {"graphicsview/anchorlayout Example", "graphicsview/anchorlayout", "anchorlayout", 10, -1},
       
    94     {"graphicsview/basicgraphicslayouts Example", "graphicsview/basicgraphicslayouts", "basicgraphicslayouts", 0, -1},
       
    95     {"graphicsview/collidingmice Example", "graphicsview/collidingmice", "collidingmice", 10, -1},
       
    96     {"graphicsview/diagramscene Example", "graphicsview/diagramscene", "diagramscene", 10, -1},
       
    97     {"graphicsview/dragdroprobot Example", "graphicsview/dragdroprobot", "dragdroprobot", 10, -1},
       
    98     {"graphicsview/elasticnodes Example", "graphicsview/elasticnodes", "elasticnodes", 10, -1},
       
    99     {"graphicsview/flowlayout Example", "graphicsview/flowlayout", "flowlayout", 10, -1},
       
   100     {"graphicsview/padnavigator Example", "graphicsview/padnavigator", "padnavigator", 0, -1},
       
   101     {"graphicsview/portedasteroids Example", "graphicsview/portedasteroids", "portedasteroids", 10, -1},
       
   102     {"graphicsview/portedcanvas Example", "graphicsview/portedcanvas", "portedcanvas", 10, -1},
       
   103     {"graphicsview/weatheranchorlayout Example", "graphicsview/weatheranchorlayout", "weatheranchorlayout", 10, -1},
       
   104     {"itemviews/addressbook Example", "itemviews/addressbook", "addressbook", 0, -1},
       
   105     {"itemviews/basicsortfiltermodel Example", "itemviews/basicsortfiltermodel", "basicsortfiltermodel", 10, -1},
       
   106     {"itemviews/chart Example", "itemviews/chart", "chart", 0, -1},
       
   107     {"itemviews/coloreditorfactory Example", "itemviews/coloreditorfactory", "coloreditorfactory", 10, -1},
       
   108     {"itemviews/combowidgetmapper Example", "itemviews/combowidgetmapper", "combowidgetmapper", 6, -1},
       
   109     {"itemviews/customsortfiltermodel Example", "itemviews/customsortfiltermodel", "customsortfiltermodel", 6, -1},
       
   110     {"itemviews/dirview Example", "itemviews/dirview", "dirview", 0, -1},
       
   111     {"itemviews/editabletreemodel Example", "itemviews/editabletreemodel", "editabletreemodel", 0, -1},
       
   112     {"itemviews/fetchmore Example", "itemviews/fetchmore", "fetchmore", 10, -1},
       
   113     {"itemviews/frozencolumn Example", "itemviews/frozencolumn", "frozencolumn", 10, -1},
       
   114     {"itemviews/pixelator Example", "itemviews/pixelator", "pixelator", 10, -1},
       
   115     {"itemviews/puzzle Example", "itemviews/puzzle", "puzzle", 10, -1},
       
   116     {"itemviews/simpledommodel Example", "itemviews/simpledommodel", "simpledommodel", 10, -1},
       
   117     {"itemviews/simpletreemodel Example", "itemviews/simpletreemodel", "simpletreemodel", 10, -1},
       
   118     {"itemviews/simplewidgetmapper Example", "itemviews/simplewidgetmapper", "simplewidgetmapper", 10, -1},
       
   119     {"itemviews/spinboxdelegate Example", "itemviews/spinboxdelegate", "spinboxdelegate", 0, -1},
       
   120     {"itemviews/stardelegate Example", "itemviews/stardelegate", "stardelegate", 10, -1},
       
   121     {"layouts/basiclayouts Example", "layouts/basiclayouts", "basiclayouts", 0, -1},
       
   122     {"layouts/borderlayout Example", "layouts/borderlayout", "borderlayout", 10, -1},
       
   123     {"layouts/dynamiclayouts Example", "layouts/dynamiclayouts", "dynamiclayouts", 10, -1},
       
   124     {"layouts/flowlayout Example", "layouts/flowlayout", "flowlayout", 10, -1},
       
   125     {"mainwindows/application Example", "mainwindows/application", "application", 6, -1},
       
   126     {"mainwindows/dockwidgets Example", "mainwindows/dockwidgets", "dockwidgets", 0, -1},
       
   127     {"mainwindows/mdi Example", "mainwindows/mdi", "mdi", 0, -1},
       
   128     {"mainwindows/menus Example", "mainwindows/menus", "menus", 10, -1},
       
   129     {"mainwindows/recentfiles Example", "mainwindows/recentfiles", "recentfiles", 10, -1},
       
   130     {"mainwindows/sdi Example", "mainwindows/sdi", "sdi", 10, -1},
       
   131     {"multitouch/dials Example", "multitouch/dials", "dials", 10, -1},
       
   132     {"multitouch/fingerpaint Example", "multitouch/fingerpaint", "fingerpaint", 10, -1},
       
   133     {"multitouch/knobs Example", "multitouch/knobs", "knobs", 10, -1},
       
   134     {"multitouch/pinchzoom Example", "multitouch/pinchzoom", "pinchzoom", 10, -1},
       
   135     {"opengl/2dpainting Example", "opengl/2dpainting", "2dpainting", 10, -1},
       
   136     {"opengl/grabber Example", "opengl/grabber", "grabber", 10, -1},
       
   137     {"opengl/hellogl Example", "opengl/hellogl", "hellogl", 10, -1},
       
   138     {"opengl/overpainting Example", "opengl/overpainting", "overpainting", 10, -1},
       
   139     {"opengl/samplebuffers Example", "opengl/samplebuffers", "samplebuffers", 10, -1},
       
   140     {"opengl/textures Example", "opengl/textures", "textures", 10, -1},
       
   141     {"painting/basicdrawing Example", "painting/basicdrawing", "basicdrawing", 10, -1},
       
   142     {"painting/concentriccircles Example", "painting/concentriccircles", "concentriccircles", 0, -1},
       
   143     {"painting/fontsampler Example", "painting/fontsampler", "fontsampler", 0, -1},
       
   144     {"painting/imagecomposition Example", "painting/imagecomposition", "imagecomposition", 10, -1},
       
   145     {"painting/painterpaths Example", "painting/painterpaths", "painterpaths", 10, -1},
       
   146     {"painting/svggenerator Example", "painting/svggenerator", "svggenerator", 10, -1},
       
   147     {"painting/svgviewer Example", "painting/svgviewer", "svgviewer", 0, -1},
       
   148     {"painting/transformations Example", "painting/transformations", "transformations", 0, -1},
       
   149     {"qtconcurrent/imagescaling Example", "qtconcurrent/imagescaling", "imagescaling", 10, -1},
       
   150     {"richtext/calendar Example", "richtext/calendar", "calendar", 0, -1},
       
   151     {"richtext/orderform Example", "richtext/orderform", "orderform", 10, -1},
       
   152     {"richtext/syntaxhighlighter Example", "richtext/syntaxhighlighter", "syntaxhighlighter", 0, -1},
       
   153     {"richtext/textobject Example", "richtext/textobject", "textobject", 10, -1},
       
   154     {"script/calculator Example", "script/calculator", "calculator", 6, -1},
       
   155     {"script/qstetrix Example", "script/qstetrix", "qstetrix", 0, -1},
       
   156     {"statemachine/eventtransitions Example", "statemachine/eventtransitions", "eventtransitions", 10, -1},
       
   157     {"statemachine/rogue Example", "statemachine/rogue", "rogue", 10, -1},
       
   158     {"statemachine/trafficlight Example", "statemachine/trafficlight", "trafficlight", 0, -1},
       
   159     {"statemachine/twowaybutton Example", "statemachine/twowaybutton", "twowaybutton", 10, -1},
       
   160     {"tutorials/addressbook/part7 Example", "tutorials/addressbook/part7", "part7", 0, -1},
       
   161     {"webkit/fancybrowser Example", "webkit/fancybrowser", "fancybrowser", 0, 7000},
       
   162     {"widgets/analogclock Example", "widgets/analogclock", "analogclock", 6, -1},
       
   163     {"widgets/calculator Example", "widgets/calculator", "calculator", 6, -1},
       
   164     {"widgets/calendarwidget Example", "widgets/calendarwidget", "calendarwidget", 10, -1},
       
   165     {"widgets/charactermap Example", "widgets/charactermap", "charactermap", 10, -1},
       
   166     {"widgets/codeeditor Example", "widgets/codeeditor", "codeeditor", 0, -1},
       
   167     {"widgets/digitalclock Example", "widgets/digitalclock", "digitalclock", 10, -1},
       
   168     {"widgets/groupbox Example", "widgets/groupbox", "groupbox", 10, -1},
       
   169     {"widgets/icons Example", "widgets/icons", "icons", 10, -1},
       
   170     {"widgets/imageviewer Example", "widgets/imageviewer", "imageviewer", 10, -1},
       
   171     {"widgets/lineedits Example", "widgets/lineedits", "lineedits", 10, -1},
       
   172     {"widgets/scribble Example", "widgets/scribble", "scribble", 10, -1},
       
   173     {"widgets/sliders Example", "widgets/sliders", "sliders", 10, -1},
       
   174     {"widgets/spinboxes Example", "widgets/spinboxes", "spinboxes", 10, -1},
       
   175     {"widgets/styles Example", "widgets/styles", "styles", 0, -1},
       
   176     {"widgets/stylesheet Example", "widgets/stylesheet", "stylesheet", 0, -1},
       
   177     {"widgets/tablet Example", "widgets/tablet", "tablet", 10, -1},
       
   178     {"widgets/tetrix Example", "widgets/tetrix", "tetrix", 0, -1},
       
   179     {"widgets/tooltips Example", "widgets/tooltips", "tooltips", 10, -1},
       
   180     {"widgets/validators Example", "widgets/validators", "validators", 10, -1},
       
   181     {"widgets/wiggly Example", "widgets/wiggly", "wiggly", 10, -1}
       
   182 };
       
   183 
       
   184 const struct Example demos[] = {
       
   185     {"Affine Demo", "affine", "affine", 0, -1},
       
   186     {"Books Demo", "books", "books", 0, -1},
       
   187     {"Browser Demo", "browser", "browser", 0, 0000},
       
   188     {"Chip Demo", "chip", "chip", 0, -1},
       
   189     {"Composition Demo", "composition", "composition", 0, -1},
       
   190     {"Deform Demo", "deform", "deform", 0, -1},
       
   191     {"Embeddeddialogs Demo", "embeddeddialogs", "embeddeddialogs", 0, -1},
       
   192     {"Gradients Demo", "gradients", "gradients", 0, -1},
       
   193     {"Interview Demo", "interview", "interview", 0, -1},
       
   194     {"Mainwindow Demo", "mainwindow", "mainwindow", 0, -1},
       
   195     {"PathStroke Demo", "pathstroke", "pathstroke", 0, -1},
       
   196     {"Spreadsheet Demo", "spreadsheet", "spreadsheet", 0, -1},
       
   197     {"Sub-Attac Demo", "sub-attaq", "sub-attaq", 0, -1},
       
   198     {"TextEdit Demo", "textedit", "textedit", 0, -1},
       
   199     {"Undo Demo", "undo", "undo", 0, -1}
       
   200 };
       
   201 
       
   202 // Data struct used in tests, specifying paths and timeouts
       
   203 struct AppLaunchData {
       
   204     AppLaunchData();
       
   205     void clear();
       
   206 
       
   207     QString binary;
       
   208     QStringList args;    
       
   209     QString workingDirectory;
       
   210     int upTimeMS;
       
   211     int topLevelWindowTimeoutMS;
       
   212     int terminationTimeoutMS;
       
   213     bool splashScreen;
       
   214 };
       
   215 
       
   216 AppLaunchData::AppLaunchData() :
       
   217     upTimeMS(defaultUpTimeMS),
       
   218     topLevelWindowTimeoutMS(defaultTopLevelWindowTimeoutMS),
       
   219     terminationTimeoutMS(defaultTerminationTimeoutMS),
       
   220     splashScreen(false)
       
   221 {
       
   222 }
       
   223 
       
   224 void AppLaunchData::clear()
       
   225 {
       
   226     binary.clear();
       
   227     args.clear();
       
   228     workingDirectory.clear();
       
   229     upTimeMS = defaultUpTimeMS;
       
   230     topLevelWindowTimeoutMS = defaultTopLevelWindowTimeoutMS;
       
   231     terminationTimeoutMS = defaultTerminationTimeoutMS;
       
   232     splashScreen = false;
       
   233 }
       
   234 
       
   235 Q_DECLARE_METATYPE(AppLaunchData)
       
   236 
       
   237 
       
   238 class tst_GuiAppLauncher : public QObject
       
   239 {
       
   240     Q_OBJECT
       
   241 
       
   242 public:
       
   243     // Test name (static const char title!) + data
       
   244     typedef QPair<const char*, AppLaunchData> TestDataEntry;
       
   245     typedef QList<TestDataEntry> TestDataEntries;
       
   246 
       
   247     enum { TestTools = 0x1, TestDemo = 0x2, TestExamples = 0x4,
       
   248            TestAll = TestTools|TestDemo|TestExamples };
       
   249 
       
   250     tst_GuiAppLauncher();
       
   251 
       
   252 private Q_SLOTS:
       
   253     void initTestCase();
       
   254 
       
   255     void run();
       
   256     void run_data();
       
   257 
       
   258     void cleanupTestCase();
       
   259 
       
   260 private:
       
   261     QString workingDir() const;
       
   262 
       
   263 private:
       
   264     bool runApp(const AppLaunchData &data, QString *errorMessage) const;
       
   265     TestDataEntries testData() const;
       
   266 
       
   267     const unsigned m_testMask;
       
   268     const unsigned m_examplePriority;
       
   269     const QString m_dir;
       
   270     const QSharedPointer<WindowManager> m_wm;
       
   271 };
       
   272 
       
   273 // Test mask from enviroment as test lib does not allow options.
       
   274 static inline unsigned testMask()
       
   275 {
       
   276     unsigned testMask = tst_GuiAppLauncher::TestAll;
       
   277     if (!qgetenv("QT_TEST_NOTOOLS").isEmpty())
       
   278         testMask &= ~ tst_GuiAppLauncher::TestTools;
       
   279     if (!qgetenv("QT_TEST_NOEXAMPLES").isEmpty())
       
   280         testMask &= ~tst_GuiAppLauncher::TestExamples;
       
   281     if (!qgetenv("QT_TEST_NODEMOS").isEmpty())
       
   282         testMask &= ~tst_GuiAppLauncher::TestDemo;
       
   283     return testMask;
       
   284 }
       
   285 
       
   286 static inline unsigned testExamplePriority()
       
   287 {
       
   288     const QByteArray priorityD = qgetenv("QT_TEST_EXAMPLE_PRIORITY");
       
   289     if (!priorityD.isEmpty()) {
       
   290         bool ok;
       
   291         const unsigned rc = priorityD.toUInt(&ok);
       
   292         if (ok)
       
   293             return rc;
       
   294     }
       
   295     return 5;
       
   296 }
       
   297 
       
   298 tst_GuiAppLauncher::tst_GuiAppLauncher() :
       
   299     m_testMask(testMask()),
       
   300     m_examplePriority(testExamplePriority()),
       
   301     m_dir(QLatin1String(SRCDIR)),
       
   302     m_wm(WindowManager::create())
       
   303 {
       
   304 }
       
   305 
       
   306 void tst_GuiAppLauncher::initTestCase()
       
   307 {   
       
   308     QString message = QString::fromLatin1("### App Launcher test on %1 in %2 (%3)").
       
   309                       arg(QDateTime::currentDateTime().toString(), QDir::currentPath()).
       
   310                       arg(QLibraryInfo::buildKey());
       
   311     qDebug("%s", qPrintable(message));
       
   312     qWarning("### PLEASE LEAVE THE MACHINE UNATTENDED WHILE THIS TEST IS RUNNING\n");
       
   313 
       
   314     // Does a window manager exist on the platform?
       
   315     if (!m_wm->openDisplay(&message)) {
       
   316         QSKIP(message.toLatin1().constData(), SkipAll);
       
   317     }
       
   318 
       
   319     // Paranoia: Do we have our test file?
       
   320     const QDir workDir(m_dir);
       
   321     if (!workDir.exists()) {
       
   322         message = QString::fromLatin1("Invalid working directory %1").arg(m_dir);
       
   323         QFAIL(message.toLocal8Bit().constData());
       
   324     }
       
   325 }
       
   326 
       
   327 void tst_GuiAppLauncher::run()
       
   328 {
       
   329     QString errorMessage;
       
   330     QFETCH(AppLaunchData, data);
       
   331     const bool rc = runApp(data, &errorMessage);
       
   332     if (!rc) // Wait for windows to disappear after kill
       
   333         WindowManager::sleepMS(500);
       
   334     QVERIFY2(rc, qPrintable(errorMessage));
       
   335 }
       
   336 
       
   337 // Cross platform galore!
       
   338 static inline QString guiBinary(QString in)
       
   339 {
       
   340 #ifdef Q_OS_MAC
       
   341     return in + QLatin1String(".app/Contents/MacOS/") + in;
       
   342 #endif
       
   343     in[0] = in.at(0).toLower();
       
   344 #ifdef Q_OS_WIN
       
   345     in += QLatin1String(".exe");
       
   346 #endif
       
   347     return in;
       
   348 }
       
   349 
       
   350 void tst_GuiAppLauncher::run_data()
       
   351 {
       
   352     QTest::addColumn<AppLaunchData>("data");
       
   353     foreach(const TestDataEntry &data, testData())
       
   354         QTest::newRow(data.first) << data.second;
       
   355 }
       
   356 
       
   357 // Read out the examples array structures and convert to test data.
       
   358 static tst_GuiAppLauncher::TestDataEntries exampleData(unsigned priority,
       
   359                                                        const QString &path,
       
   360                                                        bool debug,
       
   361                                                        const Example *exArray,
       
   362                                                        unsigned n)
       
   363 {
       
   364     Q_UNUSED(debug)
       
   365     tst_GuiAppLauncher::TestDataEntries rc;
       
   366     const QChar slash = QLatin1Char('/');
       
   367     AppLaunchData data;
       
   368     for (unsigned e = 0; e < n; e++) {
       
   369         const Example &example = exArray[e];
       
   370         if (example.priority <= priority) {
       
   371             data.clear();
       
   372             const QString examplePath = path + slash + QLatin1String(example.directory);
       
   373             data.binary = examplePath + slash;
       
   374 #ifdef Q_OS_WIN
       
   375             data.binary += debug? QLatin1String("debug/") : QLatin1String("release/");
       
   376 #endif
       
   377             data.binary += guiBinary(QLatin1String(example.binary));
       
   378             data.workingDirectory = examplePath;
       
   379             if (example.upTimeMS > 0)
       
   380                 data.upTimeMS = example.upTimeMS;
       
   381             rc.append(tst_GuiAppLauncher::TestDataEntry(example.name, data));
       
   382         }
       
   383     }
       
   384     return rc;
       
   385 }
       
   386 
       
   387 tst_GuiAppLauncher::TestDataEntries tst_GuiAppLauncher::testData() const
       
   388 {
       
   389     TestDataEntries rc;
       
   390     const QChar slash = QLatin1Char('/');
       
   391     const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + slash;
       
   392     const bool debug = QLibraryInfo::buildKey().contains(QLatin1String("debug"));
       
   393     Q_UNUSED(debug)
       
   394 
       
   395     AppLaunchData data;
       
   396 
       
   397     if (m_testMask & TestTools) {
       
   398         data.binary = binPath + guiBinary(QLatin1String("Designer"));
       
   399         data.args.append(m_dir + QLatin1String("test.ui"));
       
   400         rc.append(TestDataEntry("Qt Designer", data));
       
   401 
       
   402         data.clear();
       
   403         data.binary = binPath + guiBinary(QLatin1String("Linguist"));
       
   404         data.splashScreen = true;
       
   405         data.upTimeMS = 5000; // Slow loading
       
   406         data.args.append(m_dir + QLatin1String("test.ts"));
       
   407         rc.append(TestDataEntry("Qt Linguist", data));
       
   408     }
       
   409 
       
   410     if (m_testMask & TestDemo) {
       
   411         data.clear();
       
   412         data.upTimeMS = 5000; // Startup animation
       
   413         data.binary = binPath + guiBinary(QLatin1String("qtdemo"));
       
   414         rc.append(TestDataEntry("Qt Demo", data));
       
   415 
       
   416         const QString demosPath = QLibraryInfo::location(QLibraryInfo::DemosPath);
       
   417         if (!demosPath.isEmpty())
       
   418             rc += exampleData(m_examplePriority, demosPath, debug, demos, sizeof(demos)/sizeof(Example));
       
   419     }
       
   420 
       
   421     if (m_testMask & TestExamples) {
       
   422         const QString examplesPath = QLibraryInfo::location(QLibraryInfo::ExamplesPath);
       
   423         if (!examplesPath.isEmpty())
       
   424             rc += exampleData(m_examplePriority, examplesPath, debug, examples, sizeof(examples)/sizeof(Example));
       
   425     }
       
   426     qDebug("Running %d tests...", rc.size());
       
   427     return rc;
       
   428 }
       
   429 
       
   430 static inline void ensureTerminated(QProcess *p)
       
   431 {
       
   432     if (p->state() != QProcess::Running)
       
   433         return;
       
   434     p->terminate();
       
   435     if (p->waitForFinished(300))
       
   436         return;
       
   437     p->kill();
       
   438     if (!p->waitForFinished(500))
       
   439         qWarning("Unable to terminate process");
       
   440 }
       
   441 
       
   442 static const QStringList &stderrWhiteList()
       
   443 {
       
   444     static QStringList rc;
       
   445     if (rc.empty()) {
       
   446         rc << QLatin1String("QPainter::begin: Paint device returned engine == 0, type: 2")
       
   447            << QLatin1String("QPainter::setRenderHint: Painter must be active to set rendering hints")
       
   448            << QLatin1String("QPainter::setPen: Painter not active")
       
   449            << QLatin1String("QPainter::setBrush: Painter not active")
       
   450            << QLatin1String("QPainter::end: Painter not active, aborted");
       
   451     }
       
   452     return rc;
       
   453 }
       
   454 
       
   455 bool tst_GuiAppLauncher::runApp(const AppLaunchData &data, QString *errorMessage) const
       
   456 {
       
   457     qDebug("Launching: %s\n", qPrintable(data.binary));
       
   458     QProcess process;
       
   459     process.setProcessChannelMode(QProcess::MergedChannels);
       
   460     if (!data.workingDirectory.isEmpty())
       
   461         process.setWorkingDirectory(data.workingDirectory);
       
   462     process.start(data.binary, data.args);
       
   463     process.closeWriteChannel();
       
   464     if (!process.waitForStarted()) {
       
   465         *errorMessage = QString::fromLatin1("Unable to execute %1: %2").arg(data.binary, process.errorString());
       
   466         return false;
       
   467     }
       
   468     // Get window id.
       
   469     const QString winId = m_wm->waitForTopLevelWindow(data.splashScreen ? 2 : 1, process.pid(), data.topLevelWindowTimeoutMS, errorMessage);
       
   470     if (winId.isEmpty()) {
       
   471         ensureTerminated(&process);
       
   472         return false;
       
   473     }
       
   474     qDebug("Window: %s\n", qPrintable(winId));
       
   475     // Wait a bit, then send close
       
   476     WindowManager::sleepMS(data.upTimeMS);
       
   477     if (m_wm->sendCloseEvent(winId, process.pid(), errorMessage)) {
       
   478         qDebug("Sent close to window: %s\n", qPrintable(winId));
       
   479     } else {        
       
   480         ensureTerminated(&process);
       
   481         return false;
       
   482     }
       
   483     // Terminate
       
   484     if (!process.waitForFinished(data.terminationTimeoutMS)) {
       
   485         *errorMessage = QString::fromLatin1("%1: Timeout %2ms").arg(data.binary).arg(data.terminationTimeoutMS);
       
   486         ensureTerminated(&process);
       
   487         return false;
       
   488     }
       
   489     if (process.exitStatus() != QProcess::NormalExit) {
       
   490         *errorMessage = QString::fromLatin1("%1: Startup crash").arg(data.binary);
       
   491         return false;
       
   492     }
       
   493 
       
   494     const int exitCode = process.exitCode();
       
   495     // check stderr
       
   496     const QStringList stderrOutput = QString::fromLocal8Bit(process.readAllStandardOutput()).split(QLatin1Char('\n'));
       
   497     foreach(const QString &stderrLine, stderrOutput) {
       
   498         // Skip expected QPainter warnings from oxygen.
       
   499         if (stderrWhiteList().contains(stderrLine)) {
       
   500             qWarning("%s: stderr: %s\n", qPrintable(data.binary), qPrintable(stderrLine));
       
   501         } else {
       
   502             if (!stderrLine.isEmpty()) { // Split oddity gives empty messages
       
   503                 *errorMessage = QString::fromLatin1("%1: Unexpected output (ex=%2): '%3'").arg(data.binary).arg(exitCode).arg(stderrLine);
       
   504                 return false;
       
   505             }
       
   506         }
       
   507     }
       
   508 
       
   509     if (exitCode != 0) {
       
   510         *errorMessage = QString::fromLatin1("%1: Exit code %2").arg(data.binary).arg(exitCode);
       
   511         return false;
       
   512     }
       
   513     return true;
       
   514 }
       
   515 
       
   516 void tst_GuiAppLauncher::cleanupTestCase()
       
   517 {
       
   518 }
       
   519 
       
   520 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
       
   521 QTEST_NOOP_MAIN
       
   522 #else
       
   523 QTEST_APPLESS_MAIN(tst_GuiAppLauncher)
       
   524 #endif
       
   525 
       
   526 #include "tst_guiapplauncher.moc"