~bzoltan/kubuntu-packaging/decouple_cmake_plugin

« back to all changes in this revision

Viewing changes to share/qtcreator/qml/qmlobserver/qdeclarativetester.cpp

  • Committer: Timo Jyrinki
  • Date: 2013-12-02 09:16:15 UTC
  • mfrom: (1.1.29)
  • Revision ID: timo.jyrinki@canonical.com-20131202091615-xbj1os1f604ber1m
New upstream release candidate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
**
3
 
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
 
** Contact: http://www.qt-project.org/legal
5
 
**
6
 
** This file is part of Qt Creator.
7
 
**
8
 
** Commercial License Usage
9
 
** Licensees holding valid commercial Qt licenses may use this file in
10
 
** accordance with the commercial license agreement provided with the
11
 
** Software or, alternatively, in accordance with the terms contained in
12
 
** a written agreement between you and Digia.  For licensing terms and
13
 
** conditions see http://qt.digia.com/licensing.  For further information
14
 
** use the contact form at http://qt.digia.com/contact-us.
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, Digia gives you certain additional
25
 
** rights.  These rights are described in the Digia Qt LGPL Exception
26
 
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27
 
**
28
 
****************************************************************************/
29
 
 
30
 
#include <qdeclarativetester.h>
31
 
#include <qdeclarativeview.h>
32
 
#include <QDeclarativeComponent>
33
 
#include <QGraphicsObject>
34
 
#include <QApplication>
35
 
#include <QDebug>
36
 
#include <QFile>
37
 
#include <QDir>
38
 
#include <QCryptographicHash>
39
 
 
40
 
#ifndef NO_PRIVATE_HEADERS
41
 
#include <private/qabstractanimation_p.h>
42
 
#include <private/qdeclarativeitem_p.h>
43
 
#endif
44
 
 
45
 
QT_BEGIN_NAMESPACE
46
 
 
47
 
extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
48
 
 
49
 
QDeclarativeTester::QDeclarativeTester(const QString &script, QDeclarativeViewer::ScriptOptions opts,
50
 
                     QDeclarativeView *parent)
51
 
: QAbstractAnimation(parent), m_script(script), m_view(parent), filterEvents(true), options(opts),
52
 
  testscript(0), hasCompleted(false), hasFailed(false)
53
 
{
54
 
    parent->viewport()->installEventFilter(this);
55
 
    parent->installEventFilter(this);
56
 
#ifndef NO_PRIVATE_HEADERS
57
 
    QUnifiedTimer::instance()->setConsistentTiming(true);
58
 
#endif
59
 
 
60
 
    //Font antialiasing makes tests system-specific, so disable it
61
 
    QFont noAA = QApplication::font();
62
 
    noAA.setStyleStrategy(QFont::NoAntialias);
63
 
    QApplication::setFont(noAA);
64
 
 
65
 
    if (options & QDeclarativeViewer::Play)
66
 
        this->run();
67
 
    start();
68
 
}
69
 
 
70
 
QDeclarativeTester::~QDeclarativeTester()
71
 
{
72
 
    if (!hasFailed &&
73
 
        options & QDeclarativeViewer::Record &&
74
 
        options & QDeclarativeViewer::SaveOnExit)
75
 
        save();
76
 
}
77
 
 
78
 
int QDeclarativeTester::duration() const
79
 
{
80
 
    return -1;
81
 
}
82
 
 
83
 
void QDeclarativeTester::addMouseEvent(Destination dest, QMouseEvent *me)
84
 
{
85
 
    MouseEvent e(me);
86
 
    e.destination = dest;
87
 
    m_mouseEvents << e;
88
 
}
89
 
 
90
 
void QDeclarativeTester::addKeyEvent(Destination dest, QKeyEvent *ke)
91
 
{
92
 
    KeyEvent e(ke);
93
 
    e.destination = dest;
94
 
    m_keyEvents << e;
95
 
}
96
 
 
97
 
bool QDeclarativeTester::eventFilter(QObject *o, QEvent *e)
98
 
{
99
 
    if (!filterEvents)
100
 
        return false;
101
 
 
102
 
    Destination destination;
103
 
    if (o == m_view) {
104
 
        destination = View;
105
 
    } else if (o == m_view->viewport()) {
106
 
        destination = ViewPort;
107
 
    } else {
108
 
        return false;
109
 
    }
110
 
 
111
 
    switch (e->type()) {
112
 
        case QEvent::KeyPress:
113
 
        case QEvent::KeyRelease:
114
 
            addKeyEvent(destination, (QKeyEvent *)e);
115
 
            return true;
116
 
        case QEvent::MouseButtonPress:
117
 
        case QEvent::MouseButtonRelease:
118
 
        case QEvent::MouseMove:
119
 
        case QEvent::MouseButtonDblClick:
120
 
            addMouseEvent(destination, (QMouseEvent *)e);
121
 
            return true;
122
 
        default:
123
 
            break;
124
 
    }
125
 
    return false;
126
 
}
127
 
 
128
 
void QDeclarativeTester::executefailure()
129
 
{
130
 
    hasFailed = true;
131
 
 
132
 
    if (options & QDeclarativeViewer::ExitOnFailure)
133
 
        exit(-1);
134
 
}
135
 
 
136
 
void QDeclarativeTester::imagefailure()
137
 
{
138
 
    hasFailed = true;
139
 
 
140
 
    if (options & QDeclarativeViewer::ExitOnFailure){
141
 
        testSkip();
142
 
        exit(hasFailed?-1:0);
143
 
    }
144
 
}
145
 
 
146
 
void QDeclarativeTester::testSkip()
147
 
{
148
 
    if (options & QDeclarativeViewer::TestSkipProperty){
149
 
        QString e = m_view->rootObject()->property("skip").toString();
150
 
        if (!e.isEmpty()) {
151
 
            if(hasFailed){
152
 
                qWarning() << "Test failed, but skipping it: " << e;
153
 
            }else{
154
 
                qWarning() << "Test skipped: " << e;
155
 
            }
156
 
            hasFailed = 0;
157
 
        }
158
 
    }
159
 
}
160
 
 
161
 
void QDeclarativeTester::complete()
162
 
{
163
 
    if ((options & QDeclarativeViewer::TestErrorProperty) && !hasFailed) {
164
 
        QString e = m_view->rootObject()->property("error").toString();
165
 
        if (!e.isEmpty()) {
166
 
            qWarning() << "Test failed:" << e;
167
 
            hasFailed = true;
168
 
        }
169
 
    }
170
 
 
171
 
 
172
 
    testSkip();
173
 
    if (options & QDeclarativeViewer::ExitOnComplete)
174
 
        QApplication::exit(hasFailed?-1:0);
175
 
 
176
 
    if (hasCompleted)
177
 
        return;
178
 
    hasCompleted = true;
179
 
 
180
 
    if (options & QDeclarativeViewer::Play)
181
 
        qWarning("Script playback complete");
182
 
}
183
 
 
184
 
void QDeclarativeTester::run()
185
 
{
186
 
    QDeclarativeComponent c(m_view->engine(), m_script + QLatin1String(".qml"));
187
 
 
188
 
    testscript = qobject_cast<QDeclarativeVisualTest *>(c.create());
189
 
    if (testscript) testscript->setParent(this);
190
 
    else { executefailure(); exit(-1); }
191
 
    testscriptidx = 0;
192
 
}
193
 
 
194
 
void QDeclarativeTester::save()
195
 
{
196
 
    QString filename = m_script + QLatin1String(".qml");
197
 
    QFileInfo filenameInfo(filename);
198
 
    QDir saveDir = filenameInfo.absoluteDir();
199
 
    saveDir.mkpath(".");
200
 
 
201
 
    QFile file(filename);
202
 
    file.open(QIODevice::WriteOnly);
203
 
    QTextStream ts(&file);
204
 
 
205
 
    ts << "import Qt.VisualTest 4.7\n\n";
206
 
    ts << "VisualTest {\n";
207
 
 
208
 
    int imgCount = 0;
209
 
    QList<KeyEvent> keyevents = m_savedKeyEvents;
210
 
    QList<MouseEvent> mouseevents = m_savedMouseEvents;
211
 
    for (int ii = 0; ii < m_savedFrameEvents.count(); ++ii) {
212
 
        const FrameEvent &fe = m_savedFrameEvents.at(ii);
213
 
        ts << "    Frame {\n";
214
 
        ts << "        msec: " << fe.msec << "\n";
215
 
        if (!fe.hash.isEmpty()) {
216
 
            ts << "        hash: \"" << fe.hash.toHex() << "\"\n";
217
 
        } else if (!fe.image.isNull()) {
218
 
            QString filename = filenameInfo.baseName() + QLatin1Char('.')
219
 
                               + QString::number(imgCount) + ".png";
220
 
            fe.image.save(m_script + QLatin1Char('.') + QString::number(imgCount) + ".png");
221
 
            imgCount++;
222
 
            ts << "        image: \"" << filename << "\"\n";
223
 
        }
224
 
        ts << "    }\n";
225
 
 
226
 
        while (!mouseevents.isEmpty() &&
227
 
               mouseevents.first().msec == fe.msec) {
228
 
            MouseEvent me = mouseevents.takeFirst();
229
 
 
230
 
            ts << "    Mouse {\n";
231
 
            ts << "        type: " << me.type << "\n";
232
 
            ts << "        button: " << me.button << "\n";
233
 
            ts << "        buttons: " << me.buttons << "\n";
234
 
            ts << "        x: " << me.pos.x() << "; y: " << me.pos.y() << "\n";
235
 
            ts << "        modifiers: " << me.modifiers << "\n";
236
 
            if (me.destination == ViewPort)
237
 
                ts << "        sendToViewport: true\n";
238
 
            ts << "    }\n";
239
 
        }
240
 
 
241
 
        while (!keyevents.isEmpty() &&
242
 
               keyevents.first().msec == fe.msec) {
243
 
            KeyEvent ke = keyevents.takeFirst();
244
 
 
245
 
            ts << "    Key {\n";
246
 
            ts << "        type: " << ke.type << "\n";
247
 
            ts << "        key: " << ke.key << "\n";
248
 
            ts << "        modifiers: " << ke.modifiers << "\n";
249
 
            ts << "        text: \"" << ke.text.toUtf8().toHex() << "\"\n";
250
 
            ts << "        autorep: " << (ke.autorep?"true":"false") << "\n";
251
 
            ts << "        count: " << ke.count << "\n";
252
 
            if (ke.destination == ViewPort)
253
 
                ts << "        sendToViewport: true\n";
254
 
            ts << "    }\n";
255
 
        }
256
 
    }
257
 
 
258
 
    ts << "}\n";
259
 
    file.close();
260
 
}
261
 
 
262
 
void QDeclarativeTester::updateCurrentTime(int msec)
263
 
{
264
 
#ifndef NO_PRIVATE_HEADERS
265
 
    QDeclarativeItemPrivate::setConsistentTime(msec);
266
 
#endif
267
 
    if (!testscript && msec > 16 && options & QDeclarativeViewer::Snapshot)
268
 
        return;
269
 
 
270
 
    QImage img(m_view->width(), m_view->height(), QImage::Format_RGB32);
271
 
 
272
 
    if (options & QDeclarativeViewer::TestImages) {
273
 
        img.fill(qRgb(255,255,255));
274
 
 
275
 
#ifdef Q_OS_MAC
276
 
        bool oldSmooth = qt_applefontsmoothing_enabled;
277
 
        qt_applefontsmoothing_enabled = false;
278
 
#endif
279
 
        QPainter p(&img);
280
 
#ifdef Q_OS_MAC
281
 
        qt_applefontsmoothing_enabled = oldSmooth;
282
 
#endif
283
 
 
284
 
        m_view->render(&p);
285
 
    }
286
 
 
287
 
    bool snapshot = msec == 16 && (options & QDeclarativeViewer::Snapshot
288
 
                                   || (testscript && testscript->count() == 2));
289
 
 
290
 
    FrameEvent fe;
291
 
    fe.msec = msec;
292
 
    if (msec == 0 || !(options & QDeclarativeViewer::TestImages)) {
293
 
        // Skip first frame, skip if not doing images
294
 
    } else if (0 == ((m_savedFrameEvents.count()-1) % 60) || snapshot) {
295
 
        fe.image = img;
296
 
    } else {
297
 
        QCryptographicHash hash(QCryptographicHash::Md5);
298
 
        hash.addData((const char *)img.bits(), img.bytesPerLine() * img.height());
299
 
        fe.hash = hash.result();
300
 
    }
301
 
    m_savedFrameEvents.append(fe);
302
 
 
303
 
    // Deliver mouse events
304
 
    filterEvents = false;
305
 
 
306
 
    if (!testscript) {
307
 
        for (int ii = 0; ii < m_mouseEvents.count(); ++ii) {
308
 
            MouseEvent &me = m_mouseEvents[ii];
309
 
            me.msec = msec;
310
 
            QMouseEvent event(me.type, me.pos, me.button, me.buttons, me.modifiers);
311
 
 
312
 
            if (me.destination == View) {
313
 
                QCoreApplication::sendEvent(m_view, &event);
314
 
            } else {
315
 
                QCoreApplication::sendEvent(m_view->viewport(), &event);
316
 
            }
317
 
        }
318
 
 
319
 
        for (int ii = 0; ii < m_keyEvents.count(); ++ii) {
320
 
            KeyEvent &ke = m_keyEvents[ii];
321
 
            ke.msec = msec;
322
 
            QKeyEvent event(ke.type, ke.key, ke.modifiers, ke.text, ke.autorep, ke.count);
323
 
 
324
 
            if (ke.destination == View) {
325
 
                QCoreApplication::sendEvent(m_view, &event);
326
 
            } else {
327
 
                QCoreApplication::sendEvent(m_view->viewport(), &event);
328
 
            }
329
 
        }
330
 
        m_savedMouseEvents.append(m_mouseEvents);
331
 
        m_savedKeyEvents.append(m_keyEvents);
332
 
    }
333
 
 
334
 
    m_mouseEvents.clear();
335
 
    m_keyEvents.clear();
336
 
 
337
 
    // Advance test script
338
 
    while (testscript && testscript->count() > testscriptidx) {
339
 
 
340
 
        QObject *event = testscript->event(testscriptidx);
341
 
 
342
 
        if (QDeclarativeVisualTestFrame *frame = qobject_cast<QDeclarativeVisualTestFrame *>(event)) {
343
 
            if (frame->msec() < msec) {
344
 
                if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record)) {
345
 
                    qWarning() << "QDeclarativeTester(" << m_script << "): Extra frame.  Seen:"
346
 
                               << msec << "Expected:" << frame->msec();
347
 
                    imagefailure();
348
 
                }
349
 
            } else if (frame->msec() == msec) {
350
 
                if (!frame->hash().isEmpty() && frame->hash().toUtf8() != fe.hash.toHex()) {
351
 
                    if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record)) {
352
 
                        qWarning() << "QDeclarativeTester(" << m_script << "): Mismatched frame hash at" << msec
353
 
                                   << ".  Seen:" << fe.hash.toHex()
354
 
                                   << "Expected:" << frame->hash().toUtf8();
355
 
                        imagefailure();
356
 
                    }
357
 
                }
358
 
            } else if (frame->msec() > msec) {
359
 
                break;
360
 
            }
361
 
 
362
 
            if (options & QDeclarativeViewer::TestImages && !(options & QDeclarativeViewer::Record) && !frame->image().isEmpty()) {
363
 
                QImage goodImage(frame->image().toLocalFile());
364
 
                if (frame->msec() == 16 && goodImage.size() != img.size()){
365
 
                    //Also an image mismatch, but this warning is more informative. Only checked at start though.
366
 
                    qWarning() << "QDeclarativeTester(" << m_script << "): Size mismatch. This test must be run at " << goodImage.size();
367
 
                    imagefailure();
368
 
                }
369
 
                if (goodImage != img) {
370
 
                    QString reject(frame->image().toLocalFile() + ".reject.png");
371
 
                    qWarning() << "QDeclarativeTester(" << m_script << "): Image mismatch.  Reject saved to:"
372
 
                               << reject;
373
 
                    img.save(reject);
374
 
                    bool doDiff = (goodImage.size() == img.size());
375
 
                    if (doDiff) {
376
 
                        QImage diffimg(m_view->width(), m_view->height(), QImage::Format_RGB32);
377
 
                        diffimg.fill(qRgb(255,255,255));
378
 
                        QPainter p(&diffimg);
379
 
                        int diffCount = 0;
380
 
                        for (int x = 0; x < img.width(); ++x) {
381
 
                            for (int y = 0; y < img.height(); ++y) {
382
 
                                if (goodImage.pixel(x,y) != img.pixel(x,y)) {
383
 
                                    ++diffCount;
384
 
                                    p.drawPoint(x,y);
385
 
                                }
386
 
                            }
387
 
                        }
388
 
                        QString diff(frame->image().toLocalFile() + ".diff.png");
389
 
                        diffimg.save(diff);
390
 
                        qWarning().nospace() << "                    Diff (" << diffCount << " pixels differed) saved to: " << diff;
391
 
                    }
392
 
                    imagefailure();
393
 
                }
394
 
            }
395
 
        } else if (QDeclarativeVisualTestMouse *mouse = qobject_cast<QDeclarativeVisualTestMouse *>(event)) {
396
 
            QPoint pos(mouse->x(), mouse->y());
397
 
            QPoint globalPos = m_view->mapToGlobal(QPoint(0, 0)) + pos;
398
 
            QMouseEvent event((QEvent::Type)mouse->type(), pos, globalPos, (Qt::MouseButton)mouse->button(), (Qt::MouseButtons)mouse->buttons(), (Qt::KeyboardModifiers)mouse->modifiers());
399
 
 
400
 
            MouseEvent me(&event);
401
 
            me.msec = msec;
402
 
            if (!mouse->sendToViewport()) {
403
 
                QCoreApplication::sendEvent(m_view, &event);
404
 
                me.destination = View;
405
 
            } else {
406
 
                QCoreApplication::sendEvent(m_view->viewport(), &event);
407
 
                me.destination = ViewPort;
408
 
            }
409
 
            m_savedMouseEvents.append(me);
410
 
        } else if (QDeclarativeVisualTestKey *key = qobject_cast<QDeclarativeVisualTestKey *>(event)) {
411
 
 
412
 
            QKeyEvent event((QEvent::Type)key->type(), key->key(), (Qt::KeyboardModifiers)key->modifiers(), QString::fromUtf8(QByteArray::fromHex(key->text().toUtf8())), key->autorep(), key->count());
413
 
 
414
 
            KeyEvent ke(&event);
415
 
            ke.msec = msec;
416
 
            if (!key->sendToViewport()) {
417
 
                QCoreApplication::sendEvent(m_view, &event);
418
 
                ke.destination = View;
419
 
            } else {
420
 
                QCoreApplication::sendEvent(m_view->viewport(), &event);
421
 
                ke.destination = ViewPort;
422
 
            }
423
 
            m_savedKeyEvents.append(ke);
424
 
        }
425
 
        testscriptidx++;
426
 
    }
427
 
 
428
 
    filterEvents = true;
429
 
 
430
 
    if (testscript && testscript->count() <= testscriptidx) {
431
 
        //if (msec == 16) //for a snapshot, leave it up long enough to see
432
 
        //    (void)::sleep(1);
433
 
        complete();
434
 
    }
435
 
}
436
 
 
437
 
void QDeclarativeTester::registerTypes()
438
 
{
439
 
    qmlRegisterType<QDeclarativeVisualTest>("Qt.VisualTest", 4,7, "VisualTest");
440
 
    qmlRegisterType<QDeclarativeVisualTestFrame>("Qt.VisualTest", 4,7, "Frame");
441
 
    qmlRegisterType<QDeclarativeVisualTestMouse>("Qt.VisualTest", 4,7, "Mouse");
442
 
    qmlRegisterType<QDeclarativeVisualTestKey>("Qt.VisualTest", 4,7, "Key");
443
 
}
444
 
 
445
 
QT_END_NAMESPACE