6#include <QtTest/qtestsystem.h>
7#include <QtTest/private/qtestcrashhandler_p.h>
10#include <QtQml/qqmlengine.h>
11#include <QtQml/qqmlcontext.h>
12#include <QtQuick/private/qquickitem_p.h>
13#include <QtQuick/private/qquickwindow_p.h>
14#include <QtQuick/qquickitem.h>
15#include <QtQuick/qquickview.h>
16#include <QtQuick/qquickwindow.h>
17#include <QtQml/qjsvalue.h>
18#include <QtQml/qjsengine.h>
19#include <QtQml/qqmlpropertymap.h>
20#include <QtQuick/private/qquickitem_p.h>
21#include <QtQuick/qquickitem.h>
23#include <QtCore/qurl.h>
24#include <QtCore/qfileinfo.h>
25#include <QtCore/qdir.h>
26#include <QtCore/qdiriterator.h>
27#include <QtCore/qfile.h>
28#include <QtCore/qdebug.h>
29#include <QtCore/qeventloop.h>
30#include <QtCore/qtextstream.h>
31#include <QtCore/qtimer.h>
32#include <QtGui/qtextdocument.h>
34#include <QtGui/QGuiApplication>
35#include <QtGui/private/qguiapplication_p.h>
36#include <QtGui/qpa/qplatformintegration.h>
37#include <QtCore/QTranslator>
38#include <QtTest/QSignalSpy>
39#include <QtQml/QQmlFileSelector>
41#include <private/qqmlcomponent_p.h>
42#include <private/qv4resolvedtypereference_p.h>
109#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
110#if QT_DEPRECATED_SINCE(6, 4)
174 return s.mid(1,
s.size() - 2);
185 results.setTestCaseName(fi.baseName());
192 << errors.size() <<
" error(s):\n";
195 if (e.url().isLocalFile()) {
198 str << e.url().toString();
201 str <<
':' << e.line() <<
',' << e.column();
202 str <<
": " << e.description() <<
'\n';
208 str <<
"View: " <<
view->metaObject()->className() <<
", ";
209 str <<
"Import paths:\n";
210 const auto importPaths =
engine->importPathList();
211 for (
const QString &
i : importPaths)
214 str <<
" Plugin paths:\n";
215 for (
const QString &
p : pluginPaths)
220 results.fail(errors.at(0).description(),
221 errors.at(0).url(), errors.at(0).line());
223 results.finishTestDataCleanup();
240 qWarning(
"qWaitForSignal: invalid arguments");
244 qWarning(
"qWaitForSignal: not a valid signal, use the SIGNAL macro");
248 int sig =
obj->metaObject()->indexOfSignal(
signal + 1);
253 qWarning(
"qWaitForSignal: no such signal %s::%s",
obj->metaObject()->className(),
260 static int slot = receiver.metaObject()->indexOfSlot(
"slotFun()");
262 qWarning(
"qWaitForSignal: failed to connect to signal %s::%s",
270template <
typename... Args>
278 const QMetaObject *setupMetaObject = setupObject->metaObject();
279 const int methodIndex = setupMetaObject->
indexOfMethod(member);
280 if (methodIndex != -1) {
282 method.invoke(setupObject, std::forward<Args>(
args)...);
303 QQmlRefPointer<QV4::ExecutableCompilationUnit> rootCompilationUnit
305 TestCaseEnumerationResult
result = enumerateTestCases(
306 rootCompilationUnit->baseCompilationUnit().data());
307 m_testCases =
result.testCases +
result.finalizedPartialTestCases();
308 m_errors +=
result.errors;
313 QList<QQmlError>
errors()
const {
return m_errors; }
317 QList<QQmlError> m_errors;
320 struct TestCaseEnumerationResult
323 QList<QQmlError> errors;
326 bool isTestCase =
false;
333 for (
const QString &function : testFunctions)
338 TestCaseEnumerationResult &operator<<(
const TestCaseEnumerationResult &
other)
340 testCases +=
other.testCases +
other.finalizedPartialTestCases();
341 errors +=
other.errors;
346 TestCaseEnumerationResult enumerateTestCases(
347 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
352 const Import *
import = compilationUnit->importAt(i);
353 if (compilationUnit->stringAt(import->uriIndex) !=
QLatin1String(
"QtTest"))
357 QString typeQualifier = compilationUnit->stringAt(import->qualifierIndex);
359 testCaseTypeName = typeQualifier %
QLatin1Char(
'.') % testCaseTypeName;
361 testCaseType = compilationUnit->typeNameCache->query(
363 if (testCaseType.isValid())
367 TestCaseEnumerationResult
result;
370 object = compilationUnit->objectAt(0);
374 if (
const auto superTypeUnit = compilationUnit->resolvedType(
object->inheritedTypeNameIndex)
375 ->compilationUnit()) {
377 if (testCaseType.isValid() && superTypeUnit->url() == testCaseType.sourceUrl())
379 else if (superTypeUnit->url() != compilationUnit->url()) {
380 result = enumerateTestCases(superTypeUnit);
385 for (
auto binding =
object->bindingsBegin(); binding !=
object->bindingsEnd(); ++binding) {
386 if (compilationUnit->stringAt(binding->propertyNameIndex) ==
QLatin1String(
"name")) {
388 result.testCaseName = compilationUnit->stringAt(binding->stringIndex);
391 error.setUrl(compilationUnit->url());
392 error.setLine(binding->location.line());
393 error.setColumn(binding->location.column());
394 error.setDescription(
QStringLiteral(
"the 'name' property of a TestCase must be a literal string"));
402 auto functionsEnd = compilationUnit->objectFunctionsEnd(
object);
403 for (
auto function = compilationUnit->objectFunctionsBegin(
object); function != functionsEnd; ++
function) {
404 QString functionName = compilationUnit->stringAt(function->nameIndex);
411 result.testFunctions << functionName;
416 for (
auto binding =
object->bindingsBegin(); binding !=
object->bindingsEnd(); ++binding) {
419 result << enumerateTestCases(compilationUnit,
child);
434 QScopedPointer<QCoreApplication>
app;
453 QScopedArrayPointer<char *> testArgV(
new char *[argc + 1]);
454 testArgV[0] = argv[0];
456 while (
index < argc) {
457 if (strcmp(argv[
index],
"-import") == 0 && (
index + 1) < argc) {
460 }
else if (strcmp(argv[
index],
"-plugins") == 0 && (
index + 1) < argc) {
463 }
else if (strcmp(argv[
index],
"-input") == 0 && (
index + 1) < argc) {
466 }
else if (strcmp(argv[
index],
"-opengl") == 0) {
468 }
else if (strcmp(argv[
index],
"-translation") == 0 && (
index + 1) < argc) {
471 }
else if (strcmp(argv[
index],
"-file-selector") == 0 && (
index + 1) < argc) {
475 testArgV[testArgC++] = argv[
index++];
478 testArgV[testArgC] = 0;
487#if QT_CONFIG(translation)
489 if (!translationFile.isEmpty()) {
490 if (translator.load(translationFile)) {
499 if (testPath.isEmpty() && sourceDir) {
505#if defined(Q_OS_ANDROID) || defined(Q_OS_INTEGRITY)
506 if (testPath.isEmpty())
510 if (testPath.isEmpty()) {
523 if (testPathInfo.isFile()) {
530 const QString filePath = testPathInfo.dir()
535 files.append(filePath);
541 if (
files.isEmpty()) {
542 qWarning(
"The file '%s' does not contain any tests files",
550 qWarning(
"'%s' does not have the suffix '.qml' or '.qmltests'.",
qPrintable(testPath));
553 }
else if (testPathInfo.isDir()) {
559 while (
iter.hasNext())
562 if (
files.isEmpty()) {
563 qWarning(
"The directory '%s' does not contain any test files matching '%s'",
568 qWarning(
"'%s' does not exist under '%s'.",
573 std::optional<QTest::CrashHandler::FatalSignalHandler> handler;
578 qputenv(
"QT_QTESTLIB_RUNNING",
"1");
581 const bool filteringTestFunctions = !commandLineTestFunctions.isEmpty();
593 for (
const QString &
path : std::as_const(pluginPaths))
596 if (!fileSelectors.isEmpty()) {
598 qmlFileSelector->setExtraSelectors(fileSelectors);
609 if (!testCaseCollector.errors().isEmpty()) {
616 for (
const QString &function : availableTestFunctions)
621 const QSet<QString> availableTestSet(availableTestFunctions.cbegin(), availableTestFunctions.cend());
622 if (filteringTestFunctions && !availableTestSet.intersects(commandLineTestFunctions))
624 commandLineTestFunctions.subtract(availableTestSet);
634 &eventLoop,
SLOT(quit()));
655 if (
view.size().isEmpty()) {
656 view.resize(200, 200);
664 view.requestActivate();
670 if (
view.isExposed()) {
678 <<
"If the test case was expecting windowShown, it will hang.";
692 if (!commandLineTestFunctions.isEmpty()) {
693 qWarning() <<
"Could not find the following test functions:";
694 for (
const QString &functionName : std::as_const(commandLineTestFunctions))
696 return commandLineTestFunctions.size();
705#include "moc_quicktest_p.cpp"
706#include "quicktest.moc"
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static bool installTranslator(QTranslator *messageFile)
Adds the translation file translationFile to the list of translation files to be used for translation...
The QDirIterator class provides an iterator for directory entrylists.
bool cdUp()
Changes directory by moving one directory up from the QDir's current directory.
QString dirName() const
Returns the name of the directory; this is not the same as the path, e.g.
static QDir current()
Returns the application's current directory.
QString absolutePath() const
Returns the absolute path (a path that starts with "/" or with a drive specification),...
static QString toNativeSeparators(const QString &pathName)
static QString currentPath()
Returns the absolute path of the application's current directory.
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
void close() override
Calls QFileDevice::flush() and closes the file.
QString absoluteFilePath() const
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QPlatformIntegration * platformIntegration()
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
QString objectName
the name of this object
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
\inmodule QtCore\reentrant
static QQmlComponentPrivate * get(QQmlComponent *c)
The QQmlComponent class encapsulates a QML component definition.
void setContextProperty(const QString &, QObject *)
Set the value of the name property on this context.
The QQmlEngine class provides an environment for instantiating QML components.
The QQmlError class encapsulates a QML error.
A class for applying a QFileSelector to QML file loading.
static QQmlTypeLoader * get(Engine *engine)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
The QQuickView class provides a window for displaying a Qt Quick user interface.
QList< QQmlError > errors() const
Return the list of errors that occurred during the last compile or create operation.
Status status
The component's current \l{QQuickView::Status} {status}.
QQmlEngine * engine() const
Returns a pointer to the QQmlEngine used for instantiating QML Components.
QQmlContext * rootContext() const
This function returns the root of the context hierarchy.
void setSource(const QUrl &)
Sets the source to the url, loads the QML component and instantiates it.
static QQuickWindowPrivate * get(QQuickWindow *c)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString trimmed() const &
QString & prepend(QChar c)
static QTestRootObject * instance()
bool singleShot
whether the timer is a single-shot timer
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
void show()
Shows the window.
void setTitle(const QString &)
static void setCurrentAppname(const char *appname)
static void setProgramName(const char *name)
static void parseArgs(int argc, char *argv[])
QList< QString > TestCaseList
QList< QQmlError > errors() const
TestCaseList testCases() const
TestCaseCollector(const QFileInfo &fileInfo, QQmlEngine *engine)
Q_QMLTEST_EXPORT bool qWaitForPolish(const QQuickItem *item, int timeout=defaultTimeout)
Q_QMLTEST_EXPORT bool qIsPolishScheduled(const QQuickItem *item)
Combined button and popup list for selecting options.
bool qWaitFor(Functor predicate, QDeadlineTimer deadline=QDeadlineTimer(std::chrono::seconds{5}))
Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout=5000)
Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout=5000)
Q_TESTLIB_EXPORT QStringList testFunctions
Q_TESTLIB_EXPORT bool printAvailableFunctions
Q_CORE_EXPORT void qWait(int ms)
This is an overloaded member function, provided for convenience. It differs from the above function o...
@ WindowMinMaxButtonsHint
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
#define Q_ARG(Type, data)
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
GLuint GLsizei const GLchar * message
GLsizei const GLchar *const * path
static qreal component(const QPointF &point, unsigned int i)
static QString absolutePath(const QString &path)
#define qUtf8Printable(string)
#define qPrintable(string)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
bool qputenv(const char *varName, QByteArrayView raw)
bool qWaitForSignal(QObject *obj, const char *signal, int timeout)
static QString stripQuotes(const QString &s)
int quick_test_main(int argc, char **argv, const char *name, const char *sourceDir)
static void handleCompileErrors(const QFileInfo &fi, const QList< QQmlError > &errors, QQmlEngine *engine, QQuickView *view=nullptr)
void maybeInvokeSetupMethod(QObject *setupObject, const char *member, Args &&... args)
int quick_test_main_with_setup(int argc, char **argv, const char *name, const char *sourceDir, QObject *setup)
const QStringList filters({"Image files (*.png *.xpm *.jpg)", "Text files (*.txt)", "Any files (*)" })
[6]
QApplication app(argc, argv)
[0]
\inmodule QtCore \reentrant