diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 0000000000000000000000000000000000000000..bc6a6dffbe0bb8c23472d56df0ccae3cda07cf2b
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,8 @@
+TEMPLATE=subdirs
+qtHaveModule(quick) {
+    SUBDIRS += quick
+}
+qtHaveModule(qml) {
+    SUBDIRS += qml
+}
+
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
new file mode 100644
index 0000000000000000000000000000000000000000..63775a12a66f67ce18095c5a7864a320ccad1195
--- /dev/null
+++ b/tests/auto/qml/qml.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+QT_FOR_CONFIG += qml-private
+
+qtConfig(qml-devtools):
+    SUBDIRS += qmlmin
+
+qtConfig(private_tests): \
+    SUBDIRS += qqmlparser
+
diff --git a/tests/auto/qml/qmlmin/qmlmin.pro b/tests/auto/qml/qmlmin/qmlmin.pro
new file mode 100644
index 0000000000000000000000000000000000000000..18dba551dca13ea9e50bcfce1ab791a66d69b881
--- /dev/null
+++ b/tests/auto/qml/qmlmin/qmlmin.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_qmlmin
+QT += qml testlib gui-private
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmlmin.cpp
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+# Boot2qt is cross compiled but it has sources available
+!boot2qt {
+   cross_compile: DEFINES += QTEST_CROSS_COMPILED
+}
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa13ea72bdbf737cf6009feb9c9ceed3d2249aed
--- /dev/null
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QLibraryInfo>
+#include <QDir>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
+#include <QDebug>
+#include <QQmlError>
+#include <cstdlib>
+
+class tst_qmlmin : public QObject
+{
+    Q_OBJECT
+public:
+    tst_qmlmin();
+
+private slots:
+    void initTestCase();
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+    void qmlMinify_data();
+    void qmlMinify();
+#endif
+
+private:
+    QString qmlminPath;
+    QStringList excludedDirs;
+    QStringList invalidFiles;
+
+    QStringList findFiles(const QDir &);
+    bool isInvalidFile(const QFileInfo &fileName) const;
+};
+
+tst_qmlmin::tst_qmlmin()
+{
+}
+
+void tst_qmlmin::initTestCase()
+{
+    qmlminPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlmin");
+#ifdef Q_OS_WIN
+    qmlminPath += QLatin1String(".exe");
+#endif
+    if (!QFileInfo(qmlminPath).exists()) {
+        QString message = QString::fromLatin1("qmlmin executable not found (looked for %0)")
+                .arg(qmlminPath);
+        QFAIL(qPrintable(message));
+    }
+
+    // Add directories you want excluded here
+    // excludedDirs << "exclude/this/dir";
+
+    // Add invalid files (i.e. files with syntax errors)
+    // invalidFiles << "exclude/this/file.txt";
+}
+
+QStringList tst_qmlmin::findFiles(const QDir &d)
+{
+    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+        QString s = excludedDirs.at(ii);
+        if (d.absolutePath().endsWith(s))
+            return QStringList();
+    }
+
+    QStringList rv;
+
+    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml") << QLatin1String("*.js"),
+                                    QDir::Files);
+    foreach (const QString &file, files) {
+        rv << d.absoluteFilePath(file);
+    }
+
+    QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
+                                   QDir::NoSymLinks);
+    foreach (const QString &dir, dirs) {
+        QDir sub = d;
+        sub.cd(dir);
+        rv << findFiles(sub);
+    }
+
+    return rv;
+}
+
+bool tst_qmlmin::isInvalidFile(const QFileInfo &fileName) const
+{
+    foreach (const QString &invalidFile, invalidFiles) {
+        if (fileName.absoluteFilePath().endsWith(invalidFile))
+            return true;
+    }
+    return false;
+}
+
+/*
+This test runs all the examples in the Qt QML UI source tree and ensures
+that they start and exit cleanly.
+
+Examples are any .qml files under the examples/ directory that start
+with a lower case letter.
+*/
+
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+void tst_qmlmin::qmlMinify_data()
+{
+    QTest::addColumn<QString>("file");
+
+    QString examples = QLatin1String(SRCDIR) + "/../../../../examples/";
+    QString tests = QLatin1String(SRCDIR) + "/../../../../tests/";
+
+    QStringList files;
+    files << findFiles(QDir(examples));
+    files << findFiles(QDir(tests));
+
+    foreach (const QString &file, files)
+        QTest::newRow(qPrintable(file)) << file;
+}
+#endif
+
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+void tst_qmlmin::qmlMinify()
+{
+    QFETCH(QString, file);
+
+    QProcess qmlminify;
+
+    // Restrict line width to 100 characters
+    qmlminify.start(qmlminPath, QStringList() << QLatin1String("--verify-only") << QLatin1String("-w100") << file);
+    qmlminify.waitForFinished();
+
+    QCOMPARE(qmlminify.error(), QProcess::UnknownError);
+    QCOMPARE(qmlminify.exitStatus(), QProcess::NormalExit);
+
+    if (isInvalidFile(file))
+        QCOMPARE(qmlminify.exitCode(), EXIT_FAILURE); // cannot minify files with syntax errors
+    else
+        QCOMPARE(qmlminify.exitCode(), 0);
+}
+#endif
+
+QTEST_MAIN(tst_qmlmin)
+
+#include "tst_qmlmin.moc"
diff --git a/tests/auto/qml/qqmlparser/qqmlparser.pro b/tests/auto/qml/qqmlparser/qqmlparser.pro
new file mode 100644
index 0000000000000000000000000000000000000000..fa85b93c400e84c207d55aaa469120aadd10757e
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/qqmlparser.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qqmlparser
+QT += qml-private testlib
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qqmlparser.cpp
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+cross_compile: DEFINES += QTEST_CROSS_COMPILED
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e30481e3b84c2d7d44f44e9e07d0cae5dd1a986b
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -0,0 +1,272 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsast_p.h>
+
+#include <qtest.h>
+#include <QDir>
+#include <QDebug>
+#include <cstdlib>
+
+class tst_qqmlparser : public QObject
+{
+    Q_OBJECT
+public:
+    tst_qqmlparser();
+
+private slots:
+    void initTestCase();
+#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+    void qmlParser_data();
+    void qmlParser();
+#endif
+    void invalidEscapeSequence();
+    void stringLiteral();
+    void noSubstitutionTemplateLiteral();
+    void templateLiteral();
+
+private:
+    QStringList excludedDirs;
+
+    QStringList findFiles(const QDir &);
+};
+
+namespace check {
+
+using namespace QQmlJS;
+
+class Check: public AST::Visitor
+{
+    QList<AST::Node *> nodeStack;
+
+public:
+    void operator()(AST::Node *node)
+    {
+        AST::Node::accept(node, this);
+    }
+
+    void checkNode(AST::Node *node)
+    {
+        if (! nodeStack.isEmpty()) {
+            AST::Node *parent = nodeStack.last();
+            const quint32 parentBegin = parent->firstSourceLocation().begin();
+            const quint32 parentEnd = parent->lastSourceLocation().end();
+
+            if (node->firstSourceLocation().begin() < parentBegin)
+                qDebug() << "first source loc failed: node:" << node->kind << "at" << node->firstSourceLocation().startLine << "/" << node->firstSourceLocation().startColumn
+                         << "parent" << parent->kind << "at" << parent->firstSourceLocation().startLine << "/" << parent->firstSourceLocation().startColumn;
+            if (node->lastSourceLocation().end() > parentEnd)
+                qDebug() << "first source loc failed: node:" << node->kind << "at" << node->lastSourceLocation().startLine << "/" << node->lastSourceLocation().startColumn
+                         << "parent" << parent->kind << "at" << parent->lastSourceLocation().startLine << "/" << parent->lastSourceLocation().startColumn;
+
+            QVERIFY(node->firstSourceLocation().begin() >= parentBegin);
+            QVERIFY(node->lastSourceLocation().end() <= parentEnd);
+        }
+    }
+
+    virtual bool preVisit(AST::Node *node)
+    {
+        checkNode(node);
+        nodeStack.append(node);
+        return true;
+    }
+
+    virtual void postVisit(AST::Node *)
+    {
+        nodeStack.removeLast();
+    }
+};
+
+}
+
+tst_qqmlparser::tst_qqmlparser()
+{
+}
+
+void tst_qqmlparser::initTestCase()
+{
+    // Add directories you want excluded here:
+    // excludedDirs << "exclude/this/dir";
+}
+
+QStringList tst_qqmlparser::findFiles(const QDir &d)
+{
+    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+        QString s = excludedDirs.at(ii);
+        if (d.absolutePath().endsWith(s))
+            return QStringList();
+    }
+
+    QStringList rv;
+
+    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml") << QLatin1String("*.js"),
+                                    QDir::Files);
+    foreach (const QString &file, files) {
+        rv << d.absoluteFilePath(file);
+    }
+
+    QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
+                                   QDir::NoSymLinks);
+    foreach (const QString &dir, dirs) {
+        QDir sub = d;
+        sub.cd(dir);
+        rv << findFiles(sub);
+    }
+
+    return rv;
+}
+
+/*
+This test checks all the qml and js files in the QtQml UI source tree
+and ensures that the subnode's source locations are inside parent node's source locations
+*/
+
+#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+void tst_qqmlparser::qmlParser_data()
+{
+    QTest::addColumn<QString>("file");
+
+    QString examples = QLatin1String(SRCDIR) + "/../../../../examples/";
+    QString tests = QLatin1String(SRCDIR) + "/../../../../tests/";
+
+    QStringList files;
+    files << findFiles(QDir(examples));
+    files << findFiles(QDir(tests));
+
+    foreach (const QString &file, files)
+        QTest::newRow(qPrintable(file)) << file;
+}
+#endif
+
+#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+void tst_qqmlparser::qmlParser()
+{
+    QFETCH(QString, file);
+
+    using namespace QQmlJS;
+
+    QString code;
+
+    QFile f(file);
+    if (f.open(QFile::ReadOnly))
+        code = QString::fromUtf8(f.readAll());
+
+    const bool qmlMode = file.endsWith(QLatin1String(".qml"));
+
+    Engine engine;
+    Lexer lexer(&engine);
+    lexer.setCode(code, 1, qmlMode);
+    Parser parser(&engine);
+    bool ok = qmlMode ? parser.parse() : parser.parseProgram();
+
+    if (ok) {
+        check::Check chk;
+        chk(parser.rootNode());
+    }
+}
+#endif
+
+void tst_qqmlparser::invalidEscapeSequence()
+{
+    using namespace QQmlJS;
+
+    Engine engine;
+    Lexer lexer(&engine);
+    lexer.setCode(QLatin1String("\"\\"), 1);
+    Parser parser(&engine);
+    parser.parse();
+}
+
+void tst_qqmlparser::stringLiteral()
+{
+    using namespace QQmlJS;
+
+    Engine engine;
+    Lexer lexer(&engine);
+    QLatin1String code("'hello string'");
+    lexer.setCode(code , 1);
+    Parser parser(&engine);
+    QVERIFY(parser.parseExpression());
+    AST::ExpressionNode *expression = parser.expression();
+    QVERIFY(expression);
+    auto *literal = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expression);
+    QVERIFY(literal);
+    QCOMPARE(literal->value, "hello string");
+    QCOMPARE(literal->firstSourceLocation().begin(), 0);
+    QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::noSubstitutionTemplateLiteral()
+{
+    using namespace QQmlJS;
+
+    Engine engine;
+    Lexer lexer(&engine);
+    QLatin1String code("`hello template`");
+    lexer.setCode(code, 1);
+    Parser parser(&engine);
+    QVERIFY(parser.parseExpression());
+    AST::ExpressionNode *expression = parser.expression();
+    QVERIFY(expression);
+
+    auto *literal = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+    QVERIFY(literal);
+
+    QCOMPARE(literal->value, "hello template");
+    QCOMPARE(literal->firstSourceLocation().begin(), 0);
+    QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::templateLiteral()
+{
+    using namespace QQmlJS;
+
+    Engine engine;
+    Lexer lexer(&engine);
+    QLatin1String code("`one plus one equals ${1+1}!`");
+    lexer.setCode(code, 1);
+    Parser parser(&engine);
+    QVERIFY(parser.parseExpression());
+    AST::ExpressionNode *expression = parser.expression();
+    QVERIFY(expression);
+
+    auto *templateLiteral = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+    QVERIFY(templateLiteral);
+
+    QCOMPARE(templateLiteral->firstSourceLocation().begin(), 0);
+    auto *e = templateLiteral->expression;
+    QVERIFY(e);
+}
+
+QTEST_MAIN(tst_qqmlparser)
+
+#include "tst_qqmlparser.moc"
diff --git a/tests/auto/quick/examples/data/dummytest.qml b/tests/auto/quick/examples/data/dummytest.qml
new file mode 100644
index 0000000000000000000000000000000000000000..b20e907f27cbe14b99a0cf6bd8180aa3afae4589
--- /dev/null
+++ b/tests/auto/quick/examples/data/dummytest.qml
@@ -0,0 +1,6 @@
+import Qt.VisualTest 4.6
+
+VisualTest {
+    Frame { msec: 0 }
+    Frame { msec: 10 }
+}
diff --git a/tests/auto/quick/examples/examples.pro b/tests/auto/quick/examples/examples.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4e7ed1908a8bd9c12724132607a6aa8800bea45d
--- /dev/null
+++ b/tests/auto/quick/examples/examples.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+testcase.timeout = 400 # this test is slow
+TARGET = tst_examples
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_examples.cpp
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+#temporary
+QT += core-private gui-private qml-private quick-private  testlib
+!qtHaveModule(xmlpatterns): DEFINES += QT_NO_XMLPATTERNS
+
diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02dc70429bd615b36fcb7c1701852b2ebec953c0
--- /dev/null
+++ b/tests/auto/quick/examples/tst_examples.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QLibraryInfo>
+#include <QDir>
+#include <QDebug>
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QQuickView>
+#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QQmlError>
+
+static QtMessageHandler testlibMsgHandler = nullptr;
+void msgHandlerFilter(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg)
+{
+    if (type == QtCriticalMsg || type == QtFatalMsg)
+        (*testlibMsgHandler)(type, ctxt, msg);
+}
+
+class tst_examples : public QObject
+{
+    Q_OBJECT
+public:
+    tst_examples();
+    ~tst_examples();
+
+private slots:
+    void init();
+    void cleanup();
+
+    void sgexamples_data();
+    void sgexamples();
+
+    void namingConvention();
+private:
+    QStringList excludedDirs;
+    QStringList excludedFiles;
+
+    void namingConvention(const QDir &);
+    QStringList findQmlFiles(const QDir &);
+
+    QQmlEngine engine;
+};
+
+tst_examples::tst_examples()
+{
+    // Add files to exclude here
+    excludedFiles << "snippets/qml/listmodel/listmodel.qml"; //Just a ListModel, no root QQuickItem
+    excludedFiles << "examples/quick/demos/photosurface/photosurface.qml"; // root item is Window rather than Item
+
+    // Add directories you want excluded here
+    excludedDirs << "shared"; //Not an example
+    excludedDirs << "snippets/qml/path"; //No root QQuickItem
+    excludedDirs << "examples/qml/qmlextensionplugins"; //Requires special import search path
+    excludedDirs << "examples/quick/tutorials/gettingStartedQml"; //C++ example, but no cpp files in root dir
+
+    // These snippets are not expected to run on their own.
+    excludedDirs << "snippets/qml/visualdatamodel_rootindex";
+    excludedDirs << "snippets/qml/qtbinding";
+    excludedDirs << "snippets/qml/imports";
+    excludedFiles << "snippets/qml/image-ext.qml";
+    excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources
+    excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources
+
+#ifdef QT_NO_XMLPATTERNS
+    excludedDirs << "demos/twitter";
+    excludedDirs << "demos/flickr";
+    excludedDirs << "demos/photoviewer";
+    excludedFiles << "snippets/qml/xmlrole.qml";
+    excludedFiles << "particles/itemparticle/particleview.qml";
+    excludedFiles << "views/visualdatamodel/slideshow.qml";
+#endif
+
+#if !QT_CONFIG(opengl)
+    //No support for Particles
+    excludedFiles << "examples/qml/dynamicscene/dynamicscene.qml";
+    excludedFiles << "examples/quick/animation/basics/color-animation.qml";
+    excludedFiles << "examples/quick/particles/affectors/content/age.qml";
+    excludedFiles << "examples/quick/touchinteraction/multipointtouch/bearwhack.qml";
+    excludedFiles << "examples/quick/touchinteraction/multipointtouch/multiflame.qml";
+    excludedDirs << "examples/quick/particles";
+    // No Support for ShaderEffect
+    excludedFiles << "src/quick/doc/snippets/qml/animators.qml";
+#endif
+
+}
+
+tst_examples::~tst_examples()
+{
+}
+
+void tst_examples::init()
+{
+    if (!qstrcmp(QTest::currentTestFunction(), "sgsnippets"))
+        testlibMsgHandler = qInstallMessageHandler(msgHandlerFilter);
+}
+
+void tst_examples::cleanup()
+{
+    if (!qstrcmp(QTest::currentTestFunction(), "sgsnippets"))
+        qInstallMessageHandler(testlibMsgHandler);
+}
+
+/*
+This tests that the examples follow the naming convention required
+to have them tested by the examples() test.
+*/
+void tst_examples::namingConvention(const QDir &d)
+{
+    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+        QString s = excludedDirs.at(ii);
+        if (d.absolutePath().endsWith(s))
+            return;
+    }
+
+    QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
+                                    QDir::Files);
+
+    bool seenQml = !files.isEmpty();
+    bool seenLowercase = false;
+
+    foreach (const QString &file, files) {
+        if (file.at(0).isLower())
+            seenLowercase = true;
+    }
+
+    if (!seenQml) {
+        QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
+                QDir::NoSymLinks);
+        foreach (const QString &dir, dirs) {
+            QDir sub = d;
+            sub.cd(dir);
+            namingConvention(sub);
+        }
+    } else if (!seenLowercase) {
+        // QTBUG-28271 don't fail, but rather warn only
+        qWarning() << QString(
+            "Directory %1 violates naming convention; expected at least one qml file "
+            "starting with lower case, got: %2"
+        ).arg(d.absolutePath()).arg(files.join(","));
+
+//        QFAIL(qPrintable(QString(
+//            "Directory %1 violates naming convention; expected at least one qml file "
+//            "starting with lower case, got: %2"
+//        ).arg(d.absolutePath()).arg(files.join(","))));
+    }
+}
+
+void tst_examples::namingConvention()
+{
+    QStringList examplesLocations;
+    examplesLocations << QLibraryInfo::location(QLibraryInfo::ExamplesPath) + QLatin1String("/qml");
+    examplesLocations << QLibraryInfo::location(QLibraryInfo::ExamplesPath) + QLatin1String("/quick");
+
+    foreach (const QString &examples, examplesLocations) {
+        QDir d(examples);
+        if (d.exists())
+            namingConvention(d);
+    }
+}
+
+QStringList tst_examples::findQmlFiles(const QDir &d)
+{
+    for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+        QString s = excludedDirs.at(ii);
+        if (d.absolutePath().endsWith(s))
+            return QStringList();
+    }
+
+    QStringList rv;
+
+    QStringList cppfiles = d.entryList(QStringList() << QLatin1String("*.cpp"), QDir::Files);
+    if (cppfiles.isEmpty()) {
+        QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
+                                        QDir::Files);
+        foreach (const QString &file, files) {
+            if (file.at(0).isLower()) {
+                bool superContinue = false;
+                for (int ii = 0; ii < excludedFiles.count(); ++ii) {
+                    QString e = excludedFiles.at(ii);
+                    if (d.absoluteFilePath(file).endsWith(e)) {
+                        superContinue = true;
+                        break;
+                    }
+                }
+                if (superContinue)
+                    continue;
+                rv << d.absoluteFilePath(file);
+            }
+        }
+    }
+
+
+    QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
+                                   QDir::NoSymLinks);
+    foreach (const QString &dir, dirs) {
+        QDir sub = d;
+        sub.cd(dir);
+        rv << findQmlFiles(sub);
+    }
+
+    return rv;
+}
+
+/*
+This test runs all the examples in the QtQml UI source tree and ensures
+that they start and exit cleanly.
+
+Examples are any .qml files under the examples/ directory that start
+with a lower case letter.
+*/
+void tst_examples::sgexamples_data()
+{
+    QTest::addColumn<QString>("file");
+
+    QString examples = QLatin1String(SRCDIR) + "/../../../../examples/";
+
+    QStringList files;
+    files << findQmlFiles(QDir(examples));
+
+    foreach (const QString &file, files)
+        QTest::newRow(qPrintable(file)) << file;
+}
+
+void tst_examples::sgexamples()
+{
+    QFETCH(QString, file);
+    QQuickWindow window;
+    window.setPersistentOpenGLContext(true);
+    window.setPersistentSceneGraph(true);
+
+    QQmlComponent component(&engine, QUrl::fromLocalFile(file));
+    if (component.status() == QQmlComponent::Error)
+        qWarning() << component.errors();
+    QCOMPARE(component.status(), QQmlComponent::Ready);
+
+    QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+    QQuickItem *root = qobject_cast<QQuickItem *>(object.data());
+    if (!root)
+        component.completeCreate();
+    QVERIFY(root);
+
+    window.resize(240, 320);
+    window.show();
+    QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+    root->setParentItem(window.contentItem());
+    component.completeCreate();
+
+    qApp->processEvents();
+}
+
+QTEST_MAIN(tst_examples)
+
+#include "tst_examples.moc"
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b2542cf2fec3fc7d6fd40f8968db7ed7e976b4f4
--- /dev/null
+++ b/tests/auto/quick/quick.pro
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+
+!cross_compile: PRIVATETESTS += examples
+
+qtConfig(private_tests) {
+    SUBDIRS += $$PRIVATETESTS
+}
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 0000000000000000000000000000000000000000..85e4f3a53daada4148da2e36b80b9d03be0607aa
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS +=  auto