| " << imageItems.at(i).itemName << " | N/A | N/A | N/A | ";
-            if (imageItems.at(i).status == ImageItem::IgnoreItem) {
-                out << "Blacklisted "
-                    << "Whitelist item";
-            } else {
-                out << "Test passed";
-            }
-            out << "\n";
-        }
-
-        writeFooter();
-        out.flush();
-        file.close();
-        path.clear();
-        headerWritten = false;
-    }
-}
-
-
-QString HTMLPage::generateCompared(const QString &baseline, const QString &rendered, bool fuzzy)
-{
-    QString res = rendered;
-    QFileInfo fi(res);
-    res.chop(fi.suffix().length() + 1);
-    res += QLS(fuzzy ? "_fuzzycompared.png" : "_compared.png");
-    QStringList args;
-    if (fuzzy)
-        args << QLS("-fuzz") << QLS("5%");
-    args << root+baseline << root+rendered << root+res;
-    QProcess::execute(QLS("compare"), args);
-    return res;
-}
-
-
-QString HTMLPage::generateThumbnail(const QString &image)
-{
-    QString res = image;
-    QFileInfo imgFI(root+image);
-    res.chop(imgFI.suffix().length() + 1);
-    res += QLS("_thumbnail.jpg");
-    QFileInfo resFI(root+res);
-    if (resFI.exists() && resFI.lastModified() > imgFI.lastModified())
-        return res;
-    QStringList args;
-    args << root+image << QLS("-resize") << QLS("240x240") << QLS("-quality") << QLS("50") << root+res;
-    QProcess::execute(QLS("convert"), args);
-    return res;
-}
-
-
-void HTMLPage::handleCGIQuery(const QString &query)
-{
-    QUrl cgiUrl(QLS("http://dummy/cgi-bin/dummy.cgi?") + query);
-    QTextStream s(stdout);
-    s << "Content-Type: text/html\r\n\r\n"
-      << "";
-
-    QString command(cgiUrl.queryItemValue("cmd"));
-
-    if (command == QLS("view")) {
-        s << BaselineHandler::view(cgiUrl.queryItemValue(QLS("baseline")),
-                                   cgiUrl.queryItemValue(QLS("rendered")),
-                                   cgiUrl.queryItemValue(QLS("compared")));
-    }
-    else if (command == QLS("updateSingleBaseline")) {
-        s << BaselineHandler::updateSingleBaseline(cgiUrl.queryItemValue(QLS("oldBaseline")),
-                                                   cgiUrl.queryItemValue(QLS("newBaseline")));
-    } else if (command == QLS("clearAllBaselines")) {
-        s << BaselineHandler::clearAllBaselines(cgiUrl.queryItemValue(QLS("context")));
-    } else if (command == QLS("blacklist")) {
-        // blacklist a test
-        s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")),
-                                            cgiUrl.queryItemValue(QLS("itemId")));
-    } else if (command == QLS("whitelist")) {
-        // whitelist a test
-        s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")),
-                                            cgiUrl.queryItemValue(QLS("itemId")), true);
-    } else {
-        s << "Unknown query: | 
" << query << "
";
-    }
-    s << "Back to report";
-    s << "";
-}
diff --git a/tests/arthur/baselineserver/src/htmlpage.h b/tests/arthur/baselineserver/src/htmlpage.h
deleted file mode 100644
index 5f1e051..0000000
--- a/tests/arthur/baselineserver/src/htmlpage.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef HTMLPAGE_H
-#define HTMLPAGE_H
-
-#include "baselineprotocol.h"
-#include 
-#include 
-
-class HTMLPage
-{
-public:
-    HTMLPage();
-    ~HTMLPage();
-
-    void start(const QString &storagePath, const QString &runId, const PlatformInfo pinfo, const QString &context, const ImageItemList &itemList);
-    void addItem(const QString &baseline, const QString &rendered, const ImageItem &item);
-    void end();
-    QString filePath();
-
-    static void handleCGIQuery(const QString &query);
-
-private:
-    void writeHeader(const ImageItem &item);
-    void writeFooter();
-    QString generateCompared(const QString &baseline, const QString &rendered, bool fuzzy = false);
-    QString generateThumbnail(const QString &image);
-
-    QString root;
-    QString path;
-    QString reportDir;
-    QFile file;
-    QTextStream out;
-    QString id;
-    PlatformInfo plat;
-    QString ctx;
-    ImageItemList imageItems;
-    bool headerWritten;
-};
-
-#endif // HTMLPAGE_H
diff --git a/tests/arthur/baselineserver/src/main.cpp b/tests/arthur/baselineserver/src/main.cpp
index a5ec4db..bf41f41 100644
--- a/tests/arthur/baselineserver/src/main.cpp
+++ b/tests/arthur/baselineserver/src/main.cpp
@@ -48,7 +48,7 @@ int main(int argc, char *argv[])
     QString queryString(qgetenv("QUERY_STRING"));
     if (!queryString.isEmpty()) {
         // run as CGI script
-        HTMLPage::handleCGIQuery(queryString);
+        Report::handleCGIQuery(queryString);
         return 0;
     }
 
diff --git a/tests/arthur/baselineserver/src/report.cpp b/tests/arthur/baselineserver/src/report.cpp
new file mode 100644
index 0000000..f5bb418
--- /dev/null
+++ b/tests/arthur/baselineserver/src/report.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "report.h"
+#include "baselineprotocol.h"
+#include "baselineserver.h"
+#include 
+#include 
+#include 
+
+Report::Report()
+    : written(false), numItems(0), numMismatches(0)
+{
+}
+
+Report::~Report()
+{
+    end();
+}
+
+QString Report::filePath()
+{
+    return path;
+}
+
+void Report::init(const BaselineHandler *h, const QString &r, const PlatformInfo &p)
+{
+    handler = h;
+    runId = r;
+    plat = p;
+    rootDir = BaselineServer::storagePath() + QLC('/');
+    reportDir = plat.value(PI_TestCase) + QLC('/') + (plat.value(PI_PulseGitBranch).isEmpty() ? QLS("reports/adhoc/") : QLS("reports/pulse/"));
+    QString dir = rootDir + reportDir;
+    QDir cwd;
+    if (!cwd.exists(dir))
+        cwd.mkpath(dir);
+    path = reportDir + QLS("Report_") + runId + QLS(".html");
+}
+
+void Report::addItems(const ImageItemList &items)
+{
+    if (items.isEmpty())
+        return;
+    numItems += items.size();
+    QString func = items.at(0).testFunction;
+    if (!testFunctions.contains(func))
+        testFunctions.append(func);
+    itemLists[func] += items;
+}
+
+void Report::addMismatch(const ImageItem &item)
+{
+    if (!testFunctions.contains(item.testFunction)) {
+        qWarning() << "Report::addMismatch: unknown testfunction" << item.testFunction;
+        return;
+    }
+    bool found = false;
+    ImageItemList &list = itemLists[item.testFunction];
+    for (ImageItemList::iterator it = list.begin(); it != list.end(); ++it) {
+        if (it->itemName == item.itemName && it->itemChecksum == item.itemChecksum) {
+            it->status = ImageItem::Mismatch;
+            found = true;
+            break;
+        }
+    }
+    if (found)
+        numMismatches++;
+    else
+        qWarning() << "Report::addMismatch: unknown item" << item.itemName << "in testfunction" << item.testFunction;
+}
+
+void Report::end()
+{
+    if (written || !numMismatches)
+        return;
+    write();
+    written = true;
+}
+
+
+void Report::write()
+{
+    QFile file(rootDir + path);
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+        qWarning() << "Failed to open report file" << file.fileName();
+        return;
+    }
+    out.setDevice(&file);
+
+    writeHeader();
+    foreach(const QString &func, testFunctions) {
+        writeFunctionResults(itemLists.value(func));
+    }
+    writeFooter();
+    file.close();
+}
+
+
+void Report::writeHeader()
+{
+    QString title = plat.value(PI_TestCase) + QLS(" Qt Baseline Test Report");
+    out << "" << title << "\n"
+        << "" << title << "
\n"
+        << "Run Id: " << runId << "
\n"
+        << "Summary: " << numMismatches << " of " << numItems << " items reported mismatching
\n\n";
+    out << "Platform Info:
\n"
+        << "\n";
+    foreach (QString key, plat.keys())
+        out << "| " << key << " | " << plat.value(key) << " | 
\n";
+    out << "
\n\n";
+}
+
+
+void Report::writeFunctionResults(const ImageItemList &list)
+{
+    QString testFunction = list.at(0).testFunction;
+    QString pageUrl = BaselineServer::baseUrl() + path;
+    QString ctx = handler->pathForItem(list.at(0), true, false).section(QLC('/'), 0, -2);
+
+    out << "\n 
Test function: " << testFunction << "
\n";
+    out << "Clear all baselines (They will be recreated by the next run)
\n\n";
+
+    out << "\n"
+           "\n"
+           "| Item\n"
+           " | Baseline\n"
+           " | Rendered\n"
+           " | Comparison (diffs are RED)\n"
+           " | Info/Action\n"
+           " | 
\n\n";
+
+    foreach (const ImageItem &item, list) {
+        out << "\n";
+        out << "| " << item.itemName << "\n";
+        QString baseline = handler->pathForItem(item, true, false) + QLS(FileFormat);
+        if (item.status == ImageItem::Mismatch) {
+            QString rendered = handler->pathForItem(item, false, false) + QLS(FileFormat);
+            writeItem(baseline, rendered, item, ctx);
+        }
+        else {
+            out << " | view\n"
+                << " | n/a\n"
+                << " | ";
+            switch (item.status) {
+            case ImageItem::BaselineNotFound:
+                out << "Baseline not found/regenerated";
+                break;
+            case ImageItem::IgnoreItem:
+                out << "Blacklisted "
+                    << "Whitelist this item";
+                break;
+            case ImageItem::Ok:
+                out << "No mismatch reported";
+                break;
+            default:
+                out << "?";
+                break;
+            }
+            out << "\n";
+        }
+        out << " | 
\n\n";
+    }
+
+    out << "
\n";
+}
+
+void Report::writeItem(const QString &baseline, const QString &rendered, const ImageItem &item, const QString &ctx)
+{
+    QString compared = generateCompared(baseline, rendered);
+    QString pageUrl = BaselineServer::baseUrl() + path;
+
+    QStringList images = QStringList() << baseline << rendered << compared;
+    foreach (const QString& img, images)
+        out << "\n";
+
+    out << " | \n"
+        << " \n";
+}
+
+void Report::writeFooter()
+{
+    out << "\n\n";
+}
+
+
+QString Report::generateCompared(const QString &baseline, const QString &rendered, bool fuzzy)
+{
+    QString res = rendered;
+    QFileInfo fi(res);
+    res.chop(fi.suffix().length() + 1);
+    res += QLS(fuzzy ? "_fuzzycompared.png" : "_compared.png");
+    QStringList args;
+    if (fuzzy)
+        args << QLS("-fuzz") << QLS("5%");
+    args << rootDir+baseline << rootDir+rendered << rootDir+res;
+    QProcess::execute(QLS("compare"), args);
+    return res;
+}
+
+
+QString Report::generateThumbnail(const QString &image)
+{
+    QString res = image;
+    QFileInfo imgFI(rootDir+image);
+    res.chop(imgFI.suffix().length() + 1);
+    res += QLS("_thumbnail.jpg");
+    QFileInfo resFI(rootDir+res);
+    if (resFI.exists() && resFI.lastModified() > imgFI.lastModified())
+        return res;
+    QStringList args;
+    args << rootDir+image << QLS("-resize") << QLS("240x240>") << QLS("-quality") << QLS("50") << rootDir+res;
+    QProcess::execute(QLS("convert"), args);
+    return res;
+}
+
+
+void Report::handleCGIQuery(const QString &query)
+{
+    QUrl cgiUrl(QLS("http://dummy/cgi-bin/dummy.cgi?") + query);
+    QTextStream s(stdout);
+    s << "Content-Type: text/html\r\n\r\n"
+      << "";
+
+    QString command(cgiUrl.queryItemValue("cmd"));
+
+    if (command == QLS("view")) {
+        s << BaselineHandler::view(cgiUrl.queryItemValue(QLS("baseline")),
+                                   cgiUrl.queryItemValue(QLS("rendered")),
+                                   cgiUrl.queryItemValue(QLS("compared")));
+    }
+    else if (command == QLS("updateSingleBaseline")) {
+        s << BaselineHandler::updateSingleBaseline(cgiUrl.queryItemValue(QLS("oldBaseline")),
+                                                   cgiUrl.queryItemValue(QLS("newBaseline")));
+    } else if (command == QLS("clearAllBaselines")) {
+        s << BaselineHandler::clearAllBaselines(cgiUrl.queryItemValue(QLS("context")));
+    } else if (command == QLS("blacklist")) {
+        // blacklist a test
+        s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")),
+                                            cgiUrl.queryItemValue(QLS("itemId")));
+    } else if (command == QLS("whitelist")) {
+        // whitelist a test
+        s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")),
+                                            cgiUrl.queryItemValue(QLS("itemId")), true);
+    } else {
+        s << "Unknown query:Mismatch reported\n"
+        << " Replace baseline with rendered\n"
+        << " Blacklist this item\n"
+        << " Inspect\n"
+        << " | 
" << query << "
";
+    }
+    s << "Back to report";
+    s << "";
+}
diff --git a/tests/arthur/baselineserver/src/report.h b/tests/arthur/baselineserver/src/report.h
new file mode 100644
index 0000000..0df613a
--- /dev/null
+++ b/tests/arthur/baselineserver/src/report.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef REPORT_H
+#define REPORT_H
+
+#include "baselineprotocol.h"
+#include 
+#include 
+#include 
+#include 
+
+class BaselineHandler;
+
+class Report
+{
+public:
+    Report();
+    ~Report();
+
+    void init(const BaselineHandler *h, const QString &r, const PlatformInfo &p);
+    void addItems(const ImageItemList& items);
+    void addMismatch(const ImageItem& item);
+    void end();
+
+    QString filePath();
+
+    static void handleCGIQuery(const QString &query);
+
+private:
+    void write();
+    void writeFunctionResults(const ImageItemList &list);
+    void writeItem(const QString &baseline, const QString &rendered, const ImageItem &item, const QString &ctx);
+    void writeHeader();
+    void writeFooter();
+    QString generateCompared(const QString &baseline, const QString &rendered, bool fuzzy = false);
+    QString generateThumbnail(const QString &image);
+
+    const BaselineHandler *handler;
+    QString runId;
+    PlatformInfo plat;
+    QString rootDir;
+    QString reportDir;
+    QString path;
+    QStringList testFunctions;
+    QMap itemLists;
+    bool written;
+    int numItems;
+    int numMismatches;
+    QTextStream out;
+};
+
+#endif // REPORT_H
diff --git a/tests/arthur/common/baselineprotocol.cpp b/tests/arthur/common/baselineprotocol.cpp
index c7e9e72..e4445bd 100644
--- a/tests/arthur/common/baselineprotocol.cpp
+++ b/tests/arthur/common/baselineprotocol.cpp
@@ -48,6 +48,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifndef QMAKESPEC
 #define QMAKESPEC "Unknown"
@@ -264,6 +265,10 @@ QDataStream & operator>> (QDataStream &stream, ImageItem &ii)
     return stream;
 }
 
+BaselineProtocol::BaselineProtocol()
+{
+}
+
 BaselineProtocol::~BaselineProtocol()
 {
     socket.close();
diff --git a/tests/arthur/common/baselineprotocol.h b/tests/arthur/common/baselineprotocol.h
index 1f4d593..2315bc3 100644
--- a/tests/arthur/common/baselineprotocol.h
+++ b/tests/arthur/common/baselineprotocol.h
@@ -38,6 +38,7 @@
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
+
 #ifndef BASELINEPROTOCOL_H
 #define BASELINEPROTOCOL_H
 
@@ -46,6 +47,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define QLS QLatin1String
 #define QLC QLatin1Char
@@ -87,7 +89,8 @@ public:
     enum ItemStatus {
         Ok = 0,
         BaselineNotFound = 1,
-        IgnoreItem = 2
+        IgnoreItem = 2,
+        Mismatch = 3
     };
 
     QString testFunction;
@@ -107,12 +110,15 @@ Q_DECLARE_METATYPE(ImageItem);
 
 typedef QVector ImageItemList;
 
+
 class BaselineProtocol
 {
 public:
-    BaselineProtocol() {}
+    BaselineProtocol();
     ~BaselineProtocol();
 
+    static BaselineProtocol *instance(QObject *parent = 0);
+
     // ****************************************************
     // Important constants here
     // ****************************************************
@@ -136,6 +142,8 @@ public:
     };
 
     // For client:
+
+    // For advanced client:
     bool connect(const QString &testCase, bool *dryrun = 0);
     bool requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList);
     bool submitNewBaseline(const ImageItem &item, QByteArray *serverMsg);
diff --git a/tests/arthur/common/qbaselinetest.cpp b/tests/arthur/common/qbaselinetest.cpp
new file mode 100644
index 0000000..e95b510
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbaselinetest.h"
+#include "baselineprotocol.h"
+
+namespace QBaselineTest {
+
+bool connected = false;
+bool triedConnecting = false;
+BaselineProtocol proto;
+
+
+bool checkImage(const QImage& img, const char *name, quint16 checksum, QByteArray *msg, bool *error)
+{
+    QByteArray itemName;
+    bool hasName = qstrlen(name);
+    const char *tag = QTest::currentDataTag();
+    if (qstrlen(tag)) {
+        itemName = tag;
+        if (hasName)
+            itemName.append('_').append(name);
+    } else {
+        itemName = hasName ? name : "default_name";
+    }
+
+    *msg = "Baseline check of image '" + itemName + "': ";
+
+    if (!triedConnecting) {
+        triedConnecting = true;
+        if (!proto.connect(QTest::testObject()->metaObject()->className())) {
+            *msg += "Failed to connect to baseline server: " + proto.errorMessage().toLatin1();
+            *error = true;
+            return true;
+        }
+        connected = true;
+    }
+    if (!connected) {
+        *msg = "Not connected to baseline server.";
+        *error = true;
+        return true;
+    }
+
+    ImageItem item;
+    item.itemName = QLatin1String(itemName);
+    item.itemChecksum = checksum;
+    item.testFunction = QLatin1String(QTest::currentTestFunction());
+    ImageItemList list;
+    list.append(item);
+    if (!proto.requestBaselineChecksums(QLatin1String(QTest::currentTestFunction()), &list) || list.isEmpty()) {
+        *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1();
+        *error = true;
+        return true;
+    }
+    item.image = img;
+    item.imageChecksums.prepend(ImageItem::computeChecksum(img));
+    QByteArray srvMsg;
+    switch (list.at(0).status) {
+    case ImageItem::IgnoreItem :
+        qDebug() << msg->constData() << "Ignored, blacklisted on server.";
+        return true;
+        break;
+    case ImageItem::BaselineNotFound:
+        if (proto.submitNewBaseline(item, &srvMsg))
+            qDebug() << msg->constData() << "Baseline not found on server. New baseline uploaded.";
+        else
+            qDebug() << msg->constData() << "Baseline not found on server. Uploading of new baseline failed:" << srvMsg;
+        return true;
+        break;
+    case ImageItem::Ok:
+        break;
+    default:
+        qWarning() << "Unexpected reply from baseline server.";
+        return true;
+        break;
+    }
+    *error = false;
+    // The actual comparison of the given image with the baseline:
+    if (list.at(0).imageChecksums.contains(item.imageChecksums.at(0)))
+        return true;
+    proto.submitMismatch(item, &srvMsg);
+    *msg += "Mismatch. See report:\n   " + srvMsg;
+    return false;
+}
+
+}
diff --git a/tests/arthur/common/qbaselinetest.h b/tests/arthur/common/qbaselinetest.h
new file mode 100644
index 0000000..3445c72
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BASELINETEST_H
+#define BASELINETEST_H
+
+#include 
+
+namespace QBaselineTest {
+bool checkImage(const QImage& img, const char *name, quint16 checksum, QByteArray *msg, bool *error);
+}
+
+#define QBASELINE_CHECK_SUM(image, name, checksum)\
+do {\
+    QByteArray _msg;\
+    bool _err = false;\
+    if (!QBaselineTest::checkImage((image), (name), (checksum), &_msg, &_err)) {\
+        QFAIL(_msg.constData());\
+    } else if (_err) {\
+        QSKIP(_msg.constData(), SkipSingle);\
+    }\
+} while (0)
+
+#define QBASELINE_CHECK(image, name) QBASELINE_CHECK_SUM(image, name, 0)
+
+#endif // BASELINETEST_H
diff --git a/tests/arthur/common/qbaselinetest.pri b/tests/arthur/common/qbaselinetest.pri
new file mode 100644
index 0000000..5420c6e
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.pri
@@ -0,0 +1,13 @@
+QT *= testlib
+
+SOURCES += \
+        $$PWD/qbaselinetest.cpp
+
+HEADERS += \
+        $$PWD/qbaselinetest.h
+
+win32|symbian*:MKSPEC=$$replace(QMAKESPEC, \\\\, /)
+else:MKSPEC=$$QMAKESPEC
+DEFINES += QMAKESPEC=\\\"$$MKSPEC\\\"
+
+include($$PWD/baselineprotocol.pri)
diff --git a/tests/auto/baselineexample/baselineexample.pro b/tests/auto/baselineexample/baselineexample.pro
new file mode 100644
index 0000000..30feecc
--- /dev/null
+++ b/tests/auto/baselineexample/baselineexample.pro
@@ -0,0 +1,18 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2010-12-09T14:55:13
+#
+#-------------------------------------------------
+
+QT       += testlib
+
+TARGET = tst_baselineexample
+CONFIG   += console
+CONFIG   -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += tst_baselineexample.cpp
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include($$QT_SOURCE_TREE/tests/arthur/common/qbaselinetest.pri)
diff --git a/tests/auto/baselineexample/tst_baselineexample.cpp b/tests/auto/baselineexample/tst_baselineexample.cpp
new file mode 100644
index 0000000..28cbec5
--- /dev/null
+++ b/tests/auto/baselineexample/tst_baselineexample.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include 
+#include 
+
+class tst_BaselineExample : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_BaselineExample();
+
+private Q_SLOTS:
+    void testBasicUsage();
+    void testMultipleImages();
+    void testDataDriven_data();
+    void testDataDriven();
+    void testDataDrivenMultiple_data();
+    void testDataDrivenMultiple();
+    void testChecksum_data();
+    void testChecksum();
+};
+
+
+tst_BaselineExample::tst_BaselineExample()
+{
+}
+
+
+void tst_BaselineExample::testBasicUsage()
+{
+    // Generate an image:
+    QPushButton b("Press me!");
+    b.resize(100, 50);
+    b.show();
+    QTest::qWaitForWindowShown(&b);
+    QImage img1 = QPixmap::grabWidget(&b).toImage();
+    QVERIFY(!img1.isNull());
+
+    // Compare it to baseline on server:
+    QBASELINE_CHECK(img1, "button");
+}
+
+
+void tst_BaselineExample::testMultipleImages()
+{
+    QPushButton b("Press me!");
+    b.resize(100, 50);
+    b.show();
+    QTest::qWaitForWindowShown(&b);
+    QBASELINE_CHECK(QPixmap::grabWidget(&b).toImage(), "text1");
+
+    b.setText("Kick me!");
+    QTest::qWait(50);
+    QBASELINE_CHECK(QPixmap::grabWidget(&b).toImage(), "text2");
+}
+
+
+void tst_BaselineExample::testDataDriven_data()
+{
+    QTest::addColumn("label");
+    QTest::newRow("short") << "Ok!";
+    QTest::newRow("long") << "A really long button text that just does not seem to end";
+    QTest::newRow("empty") << "";
+}
+
+
+void tst_BaselineExample::testDataDriven()
+{
+    QFETCH(QString, label);
+    QPushButton b(label);
+    b.resize(100, 50);
+    b.show();
+    QTest::qWaitForWindowShown(&b);
+    QBASELINE_CHECK(QPixmap::grabWidget(&b).toImage(), 0);
+}
+
+
+void tst_BaselineExample::testDataDrivenMultiple_data()
+{
+    testDataDriven_data();
+}
+
+
+void tst_BaselineExample::testDataDrivenMultiple()
+{
+    QFETCH(QString, label);
+    QPushButton b(label);
+    b.resize(100, 50);
+    b.show();
+    QTest::qWaitForWindowShown(&b);
+    QBASELINE_CHECK(QPixmap::grabWidget(&b).toImage(), "normal");
+
+    b.setText(label.prepend('&'));
+    QTest::qWait(50);
+    QBASELINE_CHECK(QPixmap::grabWidget(&b).toImage(), "shortcut");
+}
+
+
+void tst_BaselineExample::testChecksum_data()
+{
+    testDataDriven_data();
+}
+
+
+void tst_BaselineExample::testChecksum()
+{
+    QFETCH(QString, label);
+    QPushButton b(label);
+    b.resize(100, 50);
+    b.show();
+    QTest::qWaitForWindowShown(&b);
+    QBASELINE_CHECK_SUM(QPixmap::grabWidget(&b).toImage(), 0, quint16(qHash(label)));
+}
+
+
+QTEST_MAIN(tst_BaselineExample);
+
+#include "tst_baselineexample.moc"
diff --git a/tests/auto/lancelot/lancelot.pro b/tests/auto/lancelot/lancelot.pro
index 4535b83..6d6edf8 100644
--- a/tests/auto/lancelot/lancelot.pro
+++ b/tests/auto/lancelot/lancelot.pro
@@ -7,9 +7,6 @@ SOURCES += tst_lancelot.cpp \
 HEADERS += $$QT_SOURCE_TREE/tests/arthur/common/paintcommands.h
 RESOURCES += $$QT_SOURCE_TREE/tests/arthur/common/images.qrc
 
-include($$QT_SOURCE_TREE/tests/arthur/common/baselineprotocol.pri)
-win32|symbian*:MKSPEC=$$replace(QMAKESPEC, \\\\, /)
-else:MKSPEC=$$QMAKESPEC
-DEFINES += QMAKESPEC=\\\"$$MKSPEC\\\"
+include($$QT_SOURCE_TREE/tests/arthur/common/qbaselinetest.pri)
 
 !symbian:!wince*:DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/auto/lancelot/tst_lancelot.cpp b/tests/auto/lancelot/tst_lancelot.cpp
index d1b093f..4bde927 100644
--- a/tests/auto/lancelot/tst_lancelot.cpp
+++ b/tests/auto/lancelot/tst_lancelot.cpp
@@ -252,7 +252,7 @@ void tst_Lancelot::runTestSuite(GraphicsEngine engine, QImage::Format format)
             if (dryRunMode)
                 qDebug() << "Dryrun mode, ignoring detected mismatch." << serverMsg;
             else
-                QFAIL("Rendered image differs from baseline.\n" + serverMsg);
+                QFAIL("Rendered image differs from baseline. Report:\n   " + serverMsg);
     }
 }
 
-- 
cgit v0.12