2015-05-08 21:10:43 +00:00
/****************************************************************************
* *
2016-01-19 11:23:05 +00:00
* * Copyright ( C ) 2016 Klaralvdalens Datakonsult AB , a KDAB Group company , info @ kdab . com , author Sergio Martins < sergio . martins @ kdab . com >
* * Contact : https : //www.qt.io/licensing/
2015-05-08 21:10:43 +00:00
* *
* * This file is part of the plugins of the Qt Toolkit .
* *
2016-01-19 11:23:05 +00:00
* * $ QT_BEGIN_LICENSE : GPL - EXCEPT $
2015-05-08 21:10:43 +00:00
* * 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
2016-01-19 11:23:05 +00:00
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
2015-05-08 21:10:43 +00:00
* *
2016-01-19 11:23:05 +00:00
* * 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.
2015-05-08 21:10:43 +00:00
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <QtTest/QtTest>
# include <QProcess>
# include <QString>
2019-08-16 11:11:53 +00:00
# include <util.h>
class TestQmllint : public QQmlDataTest
2015-05-08 21:10:43 +00:00
{
Q_OBJECT
private Q_SLOTS :
2019-08-16 11:11:53 +00:00
void initTestCase ( ) override ;
2019-09-19 08:42:51 +00:00
2019-06-14 12:21:25 +00:00
void testUnqualified ( ) ;
void testUnqualified_data ( ) ;
2019-09-19 08:42:51 +00:00
void cleanQmlCode_data ( ) ;
void cleanQmlCode ( ) ;
void dirtyQmlCode_data ( ) ;
void dirtyQmlCode ( ) ;
2019-11-14 15:31:48 +00:00
void testUnknownCausesFail ( ) ;
2019-08-16 09:31:51 +00:00
2020-04-29 08:47:19 +00:00
void directoryPassedAsQmlTypesFile ( ) ;
2020-10-06 10:29:00 +00:00
void oldQmltypes ( ) ;
2020-04-29 08:47:19 +00:00
2020-11-15 17:51:01 +00:00
void qmltypes_data ( ) ;
void qmltypes ( ) ;
2021-01-21 12:55:37 +00:00
void autoqmltypes ( ) ;
2021-02-22 15:12:57 +00:00
void resources ( ) ;
2021-01-21 12:55:37 +00:00
2021-03-02 08:51:21 +00:00
void requiredProperty ( ) ;
2015-05-08 21:10:43 +00:00
private :
2020-10-02 08:27:38 +00:00
QString runQmllint ( const QString & fileToLint ,
std : : function < void ( QProcess & ) > handleResult ,
const QStringList & extraArgs = QStringList ( ) ) ;
QString runQmllint ( const QString & fileToLint , bool shouldSucceed ,
const QStringList & extraArgs = QStringList ( ) ) ;
2019-08-21 09:43:42 +00:00
2015-05-08 21:10:43 +00:00
QString m_qmllintPath ;
} ;
void TestQmllint : : initTestCase ( )
{
2019-08-16 11:11:53 +00:00
QQmlDataTest : : initTestCase ( ) ;
2020-09-16 08:34:53 +00:00
m_qmllintPath = QLibraryInfo : : path ( QLibraryInfo : : BinariesPath ) + QLatin1String ( " /qmllint " ) ;
2015-05-08 21:10:43 +00:00
# ifdef Q_OS_WIN
m_qmllintPath + = QLatin1String ( " .exe " ) ;
# endif
if ( ! QFileInfo ( m_qmllintPath ) . exists ( ) ) {
QString message = QStringLiteral ( " qmllint executable not found (looked for %0) " ) . arg ( m_qmllintPath ) ;
QFAIL ( qPrintable ( message ) ) ;
}
}
2019-06-14 12:21:25 +00:00
void TestQmllint : : testUnqualified ( )
{
QFETCH ( QString , filename ) ;
QFETCH ( QString , warningMessage ) ;
QFETCH ( int , warningLine ) ;
QFETCH ( int , warningColumn ) ;
2019-08-21 09:43:42 +00:00
const QString output = runQmllint ( filename , false ) ;
2020-04-23 08:10:31 +00:00
QVERIFY ( output . contains ( QString : : asprintf ( " Warning: unqualified access at %s:%d:%d " , testFile ( filename ) . toUtf8 ( ) . constData ( ) , warningLine , warningColumn ) ) ) ;
2019-06-14 12:21:25 +00:00
QVERIFY ( output . contains ( warningMessage ) ) ;
}
void TestQmllint : : testUnqualified_data ( )
{
QTest : : addColumn < QString > ( " filename " ) ;
QTest : : addColumn < QString > ( " warningMessage " ) ;
QTest : : addColumn < int > ( " warningLine " ) ;
QTest : : addColumn < int > ( " warningColumn " ) ;
// check for false positive due to and warning about with statement
QTest : : newRow ( " WithStatement " ) < < QStringLiteral ( " WithStatement.qml " ) < < QStringLiteral ( " with statements are strongly discouraged " ) < < 10 < < 25 ;
// id from nowhere (as with setContextProperty)
QTest : : newRow ( " IdFromOuterSpaceDirect " ) < < QStringLiteral ( " IdFromOuterSpace.qml " ) < < " alien.x " < < 4 < < 8 ;
QTest : : newRow ( " IdFromOuterSpaceAccess " ) < < QStringLiteral ( " IdFromOuterSpace.qml " ) < < " console.log(alien) " < < 7 < < 21 ;
// access property of root object
QTest : : newRow ( " FromRootDirect " ) < < QStringLiteral ( " FromRoot.qml " ) < < QStringLiteral ( " x: root.unqualified " ) < < 9 < < 16 ; // new property
QTest : : newRow ( " FromRootAccess " ) < < QStringLiteral ( " FromRoot.qml " ) < < QStringLiteral ( " property int check: root.x " ) < < 13 < < 33 ; // builtin property
// access injected name from signal
2019-07-24 13:43:49 +00:00
QTest : : newRow ( " SignalHandler1 " ) < < QStringLiteral ( " SignalHandler.qml " ) < < QStringLiteral ( " onDoubleClicked: function(mouse) {... " ) < < 5 < < 21 ;
QTest : : newRow ( " SignalHandler2 " ) < < QStringLiteral ( " SignalHandler.qml " ) < < QStringLiteral ( " onPositionChanged: function(mouse) {... " ) < < 10 < < 21 ;
QTest : : newRow ( " SignalHandlerShort1 " ) < < QStringLiteral ( " SignalHandler.qml " ) < < QStringLiteral ( " onClicked: (mouse) => {... " ) < < 8 < < 29 ;
QTest : : newRow ( " SignalHandlerShort2 " ) < < QStringLiteral ( " SignalHandler.qml " ) < < QStringLiteral ( " onPressAndHold: (mouse) => {... " ) < < 12 < < 34 ;
2019-08-16 09:24:24 +00:00
// access catch identifier outside catch block
QTest : : newRow ( " CatchStatement " ) < < QStringLiteral ( " CatchStatement.qml " ) < < QStringLiteral ( " err " ) < < 6 < < 21 ;
2019-06-14 12:21:25 +00:00
2019-09-19 08:42:51 +00:00
QTest : : newRow ( " NonSpuriousParent " ) < < QStringLiteral ( " nonSpuriousParentWarning.qml " ) < < QStringLiteral ( " property int x: <id>.parent.x " ) < < 6 < < 25 ;
2020-05-06 11:21:21 +00:00
QTest : : newRow ( " crashConnections " )
< < QStringLiteral ( " crashConnections.qml " )
< < QStringLiteral ( " target: FirstRunDialog " ) < < 4 < < 13 ;
2019-07-23 14:10:24 +00:00
}
2019-11-14 15:31:48 +00:00
void TestQmllint : : testUnknownCausesFail ( )
2019-08-16 09:24:24 +00:00
{
2019-11-14 15:31:48 +00:00
const QString unknownNotFound = runQmllint ( " unknownElement.qml " , false ) ;
2019-09-19 08:42:51 +00:00
QVERIFY ( unknownNotFound . contains (
2020-09-28 10:40:33 +00:00
QStringLiteral ( " Warning: Unknown was not found. Did you add all import paths? " ) ) ) ;
2019-08-16 09:24:24 +00:00
}
2020-04-29 08:47:19 +00:00
void TestQmllint : : directoryPassedAsQmlTypesFile ( )
{
const QStringList iArg = QStringList ( ) < < QStringLiteral ( " -i " ) < < dataDirectory ( ) ;
const QString errorMessages = runQmllint ( " unknownElement.qml " , false , iArg ) ;
2020-10-06 10:52:42 +00:00
const QString expectedError = QStringLiteral ( " Warning: QML types file cannot be a directory: " ) + dataDirectory ( ) ;
2020-04-29 08:47:19 +00:00
QVERIFY2 ( errorMessages . contains ( expectedError ) , qPrintable ( QString : : fromLatin1 (
" Expected error to contain \" %1 \" , but it didn't: %2 " ) . arg ( expectedError , errorMessages ) ) ) ;
}
2020-10-06 10:29:00 +00:00
void TestQmllint : : oldQmltypes ( )
{
const QString errors = runQmllint ( " oldQmltypes.qml " , true ) ;
QVERIFY ( errors . contains ( QStringLiteral ( " Warning: typeinfo not declared in qmldir file " ) ) ) ;
2020-10-06 09:35:30 +00:00
QVERIFY ( ! errors . contains ( QStringLiteral ( " Warning: QQuickItem was not found. Did you add all import paths? " ) ) ) ;
QVERIFY ( errors . contains ( QStringLiteral ( " Warning: Found deprecated dependency specifications " ) ) ) ;
2020-10-16 07:11:40 +00:00
// Checking for both lines separately so that we don't have to mess with the line endings.b
QVERIFY ( errors . contains ( QStringLiteral ( " Meta object revision and export version differ, ignoring the revision. " ) ) ) ;
QVERIFY ( errors . contains ( QStringLiteral ( " Revision 0 corresponds to version 0.0; it should be 1.0. " ) ) ) ;
2020-10-06 10:29:00 +00:00
}
2020-11-15 17:51:01 +00:00
void TestQmllint : : qmltypes_data ( )
{
QTest : : addColumn < QString > ( " file " ) ;
2021-02-05 17:12:42 +00:00
const QString importsPath = QLibraryInfo : : path ( QLibraryInfo : : QmlImportsPath ) ;
2020-11-15 17:51:01 +00:00
QDirIterator it ( importsPath , { " *.qmltypes " } ,
QDir : : Files , QDirIterator : : Subdirectories ) ;
while ( it . hasNext ( ) )
QTest : : addRow ( " %s " , qPrintable ( it . next ( ) . mid ( importsPath . length ( ) ) ) ) < < it . filePath ( ) ;
}
void TestQmllint : : qmltypes ( )
{
QFETCH ( QString , file ) ;
runQmllint ( file , true ) ;
}
2021-01-21 12:55:37 +00:00
void TestQmllint : : autoqmltypes ( )
{
QProcess process ;
process . setWorkingDirectory ( testFile ( " autoqmltypes " ) ) ;
process . start ( m_qmllintPath , { QStringLiteral ( " test.qml " ) } ) ;
process . waitForFinished ( ) ;
QCOMPARE ( process . exitStatus ( ) , QProcess : : NormalExit ) ;
QCOMPARE ( process . exitCode ( ) , 0 ) ;
QVERIFY ( process . readAllStandardError ( ) . isEmpty ( ) ) ;
QVERIFY ( process . readAllStandardOutput ( ) . isEmpty ( ) ) ;
}
2021-02-22 15:12:57 +00:00
void TestQmllint : : resources ( )
{
runQmllint ( testFile ( " resource.qml " ) , true ,
{ QStringLiteral ( " --resource " ) , testFile ( " resource.qrc " ) } ) ;
runQmllint ( testFile ( " badResource.qml " ) , false ,
{ QStringLiteral ( " --resource " ) , testFile ( " resource.qrc " ) } ) ;
runQmllint ( testFile ( " resource.qml " ) , false , { } ) ;
runQmllint ( testFile ( " badResource.qml " ) , true , { } ) ;
}
2019-09-19 08:42:51 +00:00
void TestQmllint : : dirtyQmlCode_data ( )
2019-08-16 09:31:51 +00:00
{
2019-09-19 08:42:51 +00:00
QTest : : addColumn < QString > ( " filename " ) ;
QTest : : addColumn < QString > ( " warningMessage " ) ;
QTest : : addColumn < QString > ( " notContained " ) ;
QTest : : newRow ( " Invalid_syntax_QML " )
< < QStringLiteral ( " failure1.qml " )
2020-04-23 08:10:31 +00:00
< < QStringLiteral ( " %1:4 : Expected token `:' " )
2019-09-19 08:42:51 +00:00
< < QString ( ) ;
QTest : : newRow ( " Invalid_syntax_JS " )
< < QStringLiteral ( " failure1.js " )
2020-04-23 08:10:31 +00:00
< < QStringLiteral ( " %1:4 : Expected token `;' " )
2019-09-19 08:42:51 +00:00
< < QString ( ) ;
2019-11-11 17:18:04 +00:00
QTest : : newRow ( " AutomatchedSignalHandler " )
< < QStringLiteral ( " AutomatchedSignalHandler.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: unqualified access at %1:12:36 " )
2019-11-11 17:18:04 +00:00
< < QStringLiteral ( " no matching signal found " ) ;
2019-11-08 13:48:32 +00:00
QTest : : newRow ( " MemberNotFound " )
< < QStringLiteral ( " memberNotFound.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" foo \" not found on type \" QtObject \" at %1:6:31 " )
2019-11-08 13:48:32 +00:00
< < QString ( ) ;
QTest : : newRow ( " UnknownJavascriptMethd " )
< < QStringLiteral ( " unknownJavascriptMethod.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" foo2 \" not found on type \" Methods \" at %1:5:25 " )
2019-11-08 13:48:32 +00:00
< < QString ( ) ;
2019-11-11 16:35:09 +00:00
QTest : : newRow ( " badAlias " )
< < QStringLiteral ( " badAlias.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: unqualified access at %1:4:27 " )
2019-11-11 16:35:09 +00:00
< < QString ( ) ;
QTest : : newRow ( " badAliasProperty " )
< < QStringLiteral ( " badAliasProperty.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" nowhere \" not found on type \" QtObject \" at %1:5:32 " )
2019-11-11 16:35:09 +00:00
< < QString ( ) ;
2019-11-14 14:59:56 +00:00
QTest : : newRow ( " badParent " )
< < QStringLiteral ( " badParent.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" rrr \" not found on type \" Item \" at %1:5:34 " )
2019-11-14 14:59:56 +00:00
< < QString ( ) ;
QTest : : newRow ( " parentIsComponent " )
< < QStringLiteral ( " parentIsComponent.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" progress \" not found on type \" QQuickItem \" at %1:7:39 " )
2019-11-14 14:59:56 +00:00
< < QString ( ) ;
2019-11-15 15:59:46 +00:00
QTest : : newRow ( " badTypeAssertion " )
< < QStringLiteral ( " badTypeAssertion.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Property \" rrr \" not found on type \" Item \" at %1:5:39 " )
2019-11-15 15:59:46 +00:00
< < QString ( ) ;
2020-03-16 11:16:21 +00:00
QTest : : newRow ( " incompleteQmltypes " )
< < QStringLiteral ( " incompleteQmltypes.qml " )
2020-04-23 08:10:31 +00:00
< < QString ( " Warning: Type \" QPalette \" of base \" palette \" not found when accessing member \" weDontKnowIt \" at %1:5:34 " )
2020-03-16 11:16:21 +00:00
< < QString ( ) ;
2020-03-16 13:50:24 +00:00
QTest : : newRow ( " inheritanceCylce " )
< < QStringLiteral ( " Cycle1.qml " )
< < QString ( " Warning: Cycle2 is part of an inheritance cycle: Cycle2 -> Cycle3 -> Cycle1 -> Cycle2 " )
< < QString ( ) ;
2020-06-22 16:38:43 +00:00
QTest : : newRow ( " badQmldirImportAndDepend " )
< < QStringLiteral ( " qmldirImportAndDepend/bad.qml " )
2020-09-28 10:40:33 +00:00
< < QString ( " Warning: Item was not found. Did you add all import paths? " )
2020-06-22 16:38:43 +00:00
< < QString ( ) ;
2020-08-21 12:50:52 +00:00
QTest : : newRow ( " javascriptMethodsInModule " )
< < QStringLiteral ( " javascriptMethodsInModuleBad.qml " )
2020-09-24 08:06:26 +00:00
< < QString ( " Warning: Property \" unknownFunc \" not found on type \" Foo \" " )
< < QString ( ) ;
QTest : : newRow ( " badEnumFromQtQml " )
< < QStringLiteral ( " badEnumFromQtQml.qml " )
< < QString ( " Warning: Property \" Linear123 \" not found on type \" QQmlEasingEnums \" " )
< < QString ( ) ;
2020-10-02 15:31:10 +00:00
QTest : : newRow ( " anchors3 " )
< < QStringLiteral ( " anchors3.qml " )
< < QString ( )
< < QString ( ) ;
2020-10-02 08:27:38 +00:00
QTest : : newRow ( " nanchors1 " )
< < QStringLiteral ( " nanchors1.qml " )
< < QString ( )
< < QString ( ) ;
2020-10-02 09:17:29 +00:00
QTest : : newRow ( " nanchors2 " )
< < QStringLiteral ( " nanchors2.qml " )
2020-10-21 14:06:20 +00:00
< < QString ( " unknown grouped property scope nanchors. " )
2020-10-02 09:17:29 +00:00
< < QString ( ) ;
2020-10-02 08:27:38 +00:00
QTest : : newRow ( " nanchors3 " )
< < QStringLiteral ( " nanchors3.qml " )
2020-10-21 14:06:20 +00:00
< < QString ( " unknown grouped property scope nanchors. " )
2020-10-02 08:27:38 +00:00
< < QString ( ) ;
2020-10-21 12:11:10 +00:00
QTest : : newRow ( " badAliasObject " )
< < QStringLiteral ( " badAliasObject.qml " )
< < QString ( " Warning: Property \" wrongwrongwrong \" not found on type \" QtObject \" " )
< < QString ( ) ;
2021-01-26 09:17:05 +00:00
QTest : : newRow ( " badScript " )
< < QStringLiteral ( " badScript.qml " )
< < QString ( " Warning: Property \" stuff \" not found on type \" Empty \" " )
< < QString ( ) ;
2021-01-26 10:14:13 +00:00
QTest : : newRow ( " brokenNamespace " )
< < QStringLiteral ( " brokenNamespace.qml " )
< < QString ( " Warning: type not found in namespace at %1:4:17 " )
< < QString ( ) ;
2021-02-03 11:06:33 +00:00
// TODO: This fails but currently for the wrong reasons, make sure to add a warning message requirement
// once it does fail properly in order to avoid regressions.
QTest : : newRow ( " segFault (bad) " )
< < QStringLiteral ( " SegFault.bad.qml " )
< < QString ( )
< < QString ( ) ;
2021-02-11 12:17:29 +00:00
QTest : : newRow ( " VariableUsedBeforeDeclaration " )
< < QStringLiteral ( " useBeforeDeclaration.qml " )
< < QStringLiteral ( " Variable \" argq \" is used before its declaration at 5:9. "
" The declaration is at 6:13. " )
< < QString ( ) ;
2021-02-11 12:54:10 +00:00
QTest : : newRow ( " SignalParameterMismatch " )
< < QStringLiteral ( " namedSignalParameters.qml " )
< < QStringLiteral ( " Parameter 1 to signal handler for \" onSig \" is called \" argarg \" . "
" The signal has a parameter of the same name in position 2. " )
< < QStringLiteral ( " onSig2 " ) ;
QTest : : newRow ( " TooManySignalParameters " )
< < QStringLiteral ( " tooManySignalParameters.qml " )
< < QStringLiteral ( " Signal handler for \" onSig \" has more formal parameters "
" than the signal it handles. " )
< < QString ( ) ;
2021-02-12 13:35:48 +00:00
QTest : : newRow ( " OnAssignment " )
< < QStringLiteral ( " onAssignment.qml " )
< < QStringLiteral ( " Property \" loops \" not found on type \" bool \" " )
< < QString ( ) ;
2021-02-18 09:32:53 +00:00
QTest : : newRow ( " BadAttached " )
< < QStringLiteral ( " badAttached.qml " )
< < QStringLiteral ( " unknown attached property scope WrongAttached. " )
< < QString ( ) ;
2021-02-18 10:40:31 +00:00
QTest : : newRow ( " BadBinding " )
< < QStringLiteral ( " badBinding.qml " )
< < QStringLiteral ( " Binding assigned to \" doesNotExist \" , but no property "
" \" doesNotExist \" exists in the current element. " )
< < QString ( ) ;
QTest : : newRow ( " BadPropertyType " )
< < QStringLiteral ( " badPropertyType.qml " )
< < QStringLiteral ( " No type found for property \" bad \" . This may be due to a missing "
" import statement or incomplete qmltypes files. " )
< < QString ( ) ;
2021-02-24 15:42:51 +00:00
QTest : : newRow ( " Deprecation (Property, with reason) " )
< < QStringLiteral ( " deprecatedPropertyReason.qml " )
< < QStringLiteral ( " Property \" deprecated \" is deprecated (Reason: Test) " )
< < QString ( ) ;
QTest : : newRow ( " Deprecation (Property, no reason) " )
< < QStringLiteral ( " deprecatedProperty.qml " )
< < QStringLiteral ( " Property \" deprecated \" is deprecated " )
< < QString ( ) ;
QTest : : newRow ( " Deprecation (Type, with reason) " )
< < QStringLiteral ( " deprecatedTypeReason.qml " )
< < QStringLiteral ( " Type \" TypeDeprecatedReason \" is deprecated (Reason: Test) " )
< < QString ( ) ;
QTest : : newRow ( " Deprecation (Type, no reason) " )
< < QStringLiteral ( " deprecatedType.qml " )
< < QStringLiteral ( " Type \" TypeDeprecated \" is deprecated " )
< < QString ( ) ;
2019-08-16 09:31:51 +00:00
}
2019-09-19 08:42:51 +00:00
void TestQmllint : : dirtyQmlCode ( )
2019-08-16 15:03:30 +00:00
{
2019-09-19 08:42:51 +00:00
QFETCH ( QString , filename ) ;
QFETCH ( QString , warningMessage ) ;
QFETCH ( QString , notContained ) ;
2020-04-23 08:10:31 +00:00
if ( warningMessage . contains ( QLatin1String ( " %1 " ) ) )
warningMessage = warningMessage . arg ( testFile ( filename ) ) ;
2019-08-16 15:03:30 +00:00
2020-10-02 08:27:38 +00:00
const QString output = runQmllint ( filename , [ & ] ( QProcess & process ) {
QVERIFY ( process . waitForFinished ( ) ) ;
QCOMPARE ( process . exitStatus ( ) , QProcess : : NormalExit ) ;
2020-10-02 15:31:10 +00:00
QEXPECT_FAIL ( " anchors3 " , " We don't see that QQuickItem cannot be assigned to QQuickAnchorLine " , Abort ) ;
2020-10-21 14:06:20 +00:00
QEXPECT_FAIL ( " nanchors1 " , " Invalid grouped properties are not always detected " , Abort ) ;
2020-10-02 08:27:38 +00:00
QVERIFY ( process . exitCode ( ) ! = 0 ) ;
} ) ;
2019-09-19 08:42:51 +00:00
QVERIFY ( output . contains ( warningMessage ) ) ;
if ( ! notContained . isEmpty ( ) )
QVERIFY ( ! output . contains ( notContained ) ) ;
2019-08-16 14:44:06 +00:00
}
2019-09-19 08:42:51 +00:00
void TestQmllint : : cleanQmlCode_data ( )
2019-08-16 14:15:22 +00:00
{
2019-09-19 08:42:51 +00:00
QTest : : addColumn < QString > ( " filename " ) ;
QTest : : newRow ( " Simple_QML " ) < < QStringLiteral ( " Simple.qml " ) ;
QTest : : newRow ( " QML_importing_JS " ) < < QStringLiteral ( " importing_js.qml " ) ;
QTest : : newRow ( " JS_with_pragma_and_import " ) < < QStringLiteral ( " QTBUG-45916.js " ) ;
QTest : : newRow ( " uiQml " ) < < QStringLiteral ( " FormUser.qml " ) ;
QTest : : newRow ( " methodInScope " ) < < QStringLiteral ( " MethodInScope.qml " ) ;
QTest : : newRow ( " importWithPrefix " ) < < QStringLiteral ( " ImportWithPrefix.qml " ) ;
QTest : : newRow ( " catchIdentifier " ) < < QStringLiteral ( " catchIdentifierNoWarning.qml " ) ;
2019-09-13 09:34:08 +00:00
QTest : : newRow ( " qmldirAndQmltypes " ) < < QStringLiteral ( " qmldirAndQmltypes.qml " ) ;
2019-09-17 15:13:18 +00:00
QTest : : newRow ( " forLoop " ) < < QStringLiteral ( " forLoop.qml " ) ;
2019-10-15 08:39:40 +00:00
QTest : : newRow ( " esmodule " ) < < QStringLiteral ( " esmodule.mjs " ) ;
2019-11-08 17:43:31 +00:00
QTest : : newRow ( " methodsInJavascript " ) < < QStringLiteral ( " javascriptMethods.qml " ) ;
2019-11-11 16:35:09 +00:00
QTest : : newRow ( " goodAlias " ) < < QStringLiteral ( " goodAlias.qml " ) ;
2019-11-14 14:59:56 +00:00
QTest : : newRow ( " goodParent " ) < < QStringLiteral ( " goodParent.qml " ) ;
2019-11-15 15:59:46 +00:00
QTest : : newRow ( " goodTypeAssertion " ) < < QStringLiteral ( " goodTypeAssertion.qml " ) ;
2019-11-15 16:42:18 +00:00
QTest : : newRow ( " AttachedProps " ) < < QStringLiteral ( " AttachedProps.qml " ) ;
2020-03-16 10:20:47 +00:00
QTest : : newRow ( " unknownBuiltinFont " ) < < QStringLiteral ( " ButtonLoader.qml " ) ;
2020-03-16 11:15:10 +00:00
QTest : : newRow ( " confusingImport " ) < < QStringLiteral ( " Dialog.qml " ) ;
2020-03-16 14:07:04 +00:00
QTest : : newRow ( " qualifiedAttached " ) < < QStringLiteral ( " Drawer.qml " ) ;
2020-06-16 20:52:24 +00:00
QTest : : newRow ( " EnumAccess1 " ) < < QStringLiteral ( " EnumAccess1.qml " ) ;
QTest : : newRow ( " EnumAccess2 " ) < < QStringLiteral ( " EnumAccess2.qml " ) ;
2020-06-17 20:39:28 +00:00
QTest : : newRow ( " ListProperty " ) < < QStringLiteral ( " ListProperty.qml " ) ;
2020-06-18 18:52:58 +00:00
QTest : : newRow ( " AttachedType " ) < < QStringLiteral ( " AttachedType.qml " ) ;
2020-06-22 16:38:43 +00:00
QTest : : newRow ( " qmldirImportAndDepend " ) < < QStringLiteral ( " qmldirImportAndDepend/good.qml " ) ;
2020-06-23 14:06:58 +00:00
QTest : : newRow ( " ParentEnum " ) < < QStringLiteral ( " parentEnum.qml " ) ;
2020-08-18 19:22:10 +00:00
QTest : : newRow ( " Signals " ) < < QStringLiteral ( " Signal.qml " ) ;
2020-08-21 12:50:52 +00:00
QTest : : newRow ( " javascriptMethodsInModule " )
< < QStringLiteral ( " javascriptMethodsInModuleGood.qml " ) ;
2020-09-24 08:06:26 +00:00
QTest : : newRow ( " enumFromQtQml " ) < < QStringLiteral ( " enumFromQtQml.qml " ) ;
2020-10-02 08:27:38 +00:00
QTest : : newRow ( " anchors1 " ) < < QStringLiteral ( " anchors1.qml " ) ;
2020-10-02 09:17:29 +00:00
QTest : : newRow ( " anchors2 " ) < < QStringLiteral ( " anchors2.qml " ) ;
2020-10-06 13:45:05 +00:00
QTest : : newRow ( " optionalImport " ) < < QStringLiteral ( " optionalImport.qml " ) ;
2020-10-21 12:11:10 +00:00
QTest : : newRow ( " goodAliasObject " ) < < QStringLiteral ( " goodAliasObject.qml " ) ;
2020-11-20 12:13:23 +00:00
QTest : : newRow ( " jsmoduleimport " ) < < QStringLiteral ( " jsmoduleimport.qml " ) ;
2021-01-26 08:14:05 +00:00
QTest : : newRow ( " overridescript " ) < < QStringLiteral ( " overridescript.qml " ) ;
2021-02-01 14:03:19 +00:00
QTest : : newRow ( " multiExtension " ) < < QStringLiteral ( " multiExtension.qml " ) ;
2021-02-03 11:06:33 +00:00
QTest : : newRow ( " segFault " ) < < QStringLiteral ( " SegFault.qml " ) ;
2021-02-12 10:32:53 +00:00
QTest : : newRow ( " grouped scope failure " ) < < QStringLiteral ( " groupedScope.qml " ) ;
2021-02-16 10:00:04 +00:00
QTest : : newRow ( " layouts depends quick " ) < < QStringLiteral ( " layouts.qml " ) ;
2021-02-18 09:32:53 +00:00
QTest : : newRow ( " attached " ) < < QStringLiteral ( " attached.qml " ) ;
2021-02-18 10:40:31 +00:00
QTest : : newRow ( " enumProperty " ) < < QStringLiteral ( " enumProperty.qml " ) ;
2021-02-22 08:31:30 +00:00
QTest : : newRow ( " externalEnumProperty " ) < < QStringLiteral ( " externalEnumProperty.qml " ) ;
2021-02-22 09:40:32 +00:00
QTest : : newRow ( " shapes " ) < < QStringLiteral ( " shapes.qml " ) ;
2021-03-01 09:23:59 +00:00
QTest : : newRow ( " var " ) < < QStringLiteral ( " var.qml " ) ;
2019-08-16 14:15:22 +00:00
}
2019-09-19 08:42:51 +00:00
void TestQmllint : : cleanQmlCode ( )
2015-05-08 21:10:43 +00:00
{
QFETCH ( QString , filename ) ;
2019-09-19 08:42:51 +00:00
const QString warnings = runQmllint ( filename , true ) ;
2021-02-03 11:06:33 +00:00
QEXPECT_FAIL ( " segFault " , " This property exists and should not produce a warning " , Abort ) ;
2020-10-08 10:40:09 +00:00
QVERIFY2 ( warnings . isEmpty ( ) , qPrintable ( warnings ) ) ;
2015-05-08 21:10:43 +00:00
}
2020-10-02 08:27:38 +00:00
QString TestQmllint : : runQmllint ( const QString & fileToLint ,
std : : function < void ( QProcess & ) > handleResult ,
const QStringList & extraArgs )
2019-08-21 09:43:42 +00:00
{
2021-02-05 17:12:42 +00:00
auto qmlImportDir = QLibraryInfo : : path ( QLibraryInfo : : QmlImportsPath ) ;
2019-08-21 09:43:42 +00:00
QStringList args ;
2020-11-15 17:51:01 +00:00
args < < ( QFileInfo ( fileToLint ) . isAbsolute ( ) ? fileToLint : testFile ( fileToLint ) )
2019-09-19 08:42:51 +00:00
< < QStringLiteral ( " -I " ) < < qmlImportDir
2020-04-29 08:47:19 +00:00
< < QStringLiteral ( " -I " ) < < dataDirectory ( ) ;
args < < extraArgs ;
args < < QStringLiteral ( " --silent " ) ;
2019-09-19 08:42:51 +00:00
QString errors ;
auto verify = [ & ] ( bool isSilent ) {
QProcess process ;
process . start ( m_qmllintPath , args ) ;
2020-10-02 08:27:38 +00:00
handleResult ( process ) ;
2019-09-19 08:42:51 +00:00
errors = process . readAllStandardError ( ) ;
if ( isSilent )
QVERIFY ( errors . isEmpty ( ) ) ;
2020-11-17 19:37:14 +00:00
if ( QTest : : currentTestFailed ( ) ) {
qDebug ( ) < < " Command: " < < process . program ( ) < < args . join ( u ' ' ) ;
qDebug ( ) < < " Exit status: " < < process . exitStatus ( ) ;
qDebug ( ) < < " Exit code: " < < process . exitCode ( ) ;
qDebug ( ) < < " stderr: " < < errors ;
qDebug ( ) < < " stdout: " < < process . readAllStandardOutput ( ) ;
}
2019-09-19 08:42:51 +00:00
} ;
verify ( true ) ;
args . removeLast ( ) ;
verify ( false ) ;
return errors ;
2019-08-21 09:43:42 +00:00
}
2020-10-02 08:27:38 +00:00
QString TestQmllint : : runQmllint ( const QString & fileToLint , bool shouldSucceed , const QStringList & extraArgs )
{
return runQmllint ( fileToLint , [ & ] ( QProcess & process ) {
QVERIFY ( process . waitForFinished ( ) ) ;
QCOMPARE ( process . exitStatus ( ) , QProcess : : NormalExit ) ;
2021-02-03 11:06:33 +00:00
QEXPECT_FAIL ( " segFault " , " This property exists and should not produce a warning " , Abort ) ;
2020-10-02 08:27:38 +00:00
if ( shouldSucceed )
QCOMPARE ( process . exitCode ( ) , 0 ) ;
else
QVERIFY ( process . exitCode ( ) ! = 0 ) ;
} , extraArgs ) ;
}
2021-03-02 08:51:21 +00:00
void TestQmllint : : requiredProperty ( )
{
QVERIFY ( runQmllint ( " requiredProperty.qml " , true ) . isEmpty ( ) ) ;
const QString errors = runQmllint ( " requiredMissingProperty.qml " , true ) ;
QVERIFY ( errors . contains ( QStringLiteral ( " Property \" foo \" was marked as required but does not exist. " ) ) ) ;
}
2015-05-08 21:10:43 +00:00
QTEST_MAIN ( TestQmllint )
2019-08-16 11:11:53 +00:00
# include "tst_qmllint.moc"