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