aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml')
-rw-r--r--tests/auto/qml/bindingdependencyapi/dummy_imports.qml8
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/quit.js4
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/quitInJS.qml41
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp52
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp46
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp1
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations2
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp2
-rw-r--r--tests/auto/qml/parserstress/dummy_imports.qml8
-rw-r--r--tests/auto/qml/parserstress/tst_parserstress.cpp3
-rw-r--r--tests/auto/qml/qjsengine/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp301
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp111
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.h1
-rw-r--r--tests/auto/qml/qml.pro5
-rw-r--r--tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml7
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro3
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp11
-rw-r--r--tests/auto/qml/qmldiskcache/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp64
-rw-r--r--tests/auto/qml/qmllint/data/CatchStatement.qml8
-rw-r--r--tests/auto/qml/qmllint/data/FromRoot.qml17
-rw-r--r--tests/auto/qml/qmllint/data/IdFromOuterSpace.qml9
-rw-r--r--tests/auto/qml/qmllint/data/SignalHandler.qml13
-rw-r--r--tests/auto/qml/qmllint/data/WithStatement.qml13
-rw-r--r--tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml7
-rw-r--r--tests/auto/qml/qmllint/data/nonSpuriousParentWarning.qml8
-rw-r--r--tests/auto/qml/qmllint/data/spuriousParentWarning.qml7
-rw-r--r--tests/auto/qml/qmllint/main.cpp85
-rw-r--r--tests/auto/qml/qmllint/qmllint.pro13
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp174
-rw-r--r--tests/auto/qml/qmlmin/tst_qmlmin.cpp5
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/Derived.qml6
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro2
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes10
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir1
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp24
-rw-r--r--tests/auto/qml/qqmlbinding/data/MyComponent.qml2
-rw-r--r--tests/auto/qml/qqmlbinding/data/bindToQMLComponent.qml12
-rw-r--r--tests/auto/qml/qqmlbinding/data/nanPropertyToInt.qml14
-rw-r--r--tests/auto/qml/qqmlbinding/data/noUnexpectedStringConversion.qml30
-rw-r--r--tests/auto/qml/qqmlbinding/data/restoreBinding2.qml55
-rw-r--r--tests/auto/qml/qqmlbinding/data/restoreBinding3.qml56
-rw-r--r--tests/auto/qml/qqmlbinding/data/restoreBinding4.qml59
-rw-r--r--tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp156
-rw-r--r--tests/auto/qml/qqmlchangeset/qqmlchangeset.pro2
-rw-r--r--tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml9
-rw-r--r--tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml21
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp111
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-targetchange.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml (renamed from tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml (renamed from tests/auto/qml/qqmlconnections/data/disabled-at-start.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml (renamed from tests/auto/qml/qqmlconnections/data/override-proxy-type.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml (renamed from tests/auto/qml/qqmlconnections/data/rewriteError-global.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml (renamed from tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml (renamed from tests/auto/qml/qqmlconnections/data/singletontype-target.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml (renamed from tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml (renamed from tests/auto/qml/qqmlconnections/data/test-connection.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/bindings/trimming.qml (renamed from tests/auto/qml/qqmlconnections/data/trimming.qml)0
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml15
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml25
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml17
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml9
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml11
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml14
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml13
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml8
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml22
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml9
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/test-connection.qml14
-rw-r--r--tests/auto/qml/qqmlconnections/data/functions/trimming.qml13
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp72
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp26
-rw-r--r--tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp2
-rw-r--r--tests/auto/qml/qqmldirparser/qqmldirparser.pro2
-rw-r--r--tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/generatorFunction.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regularExpression.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml1
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h26
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp177
-rw-r--r--tests/auto/qml/qqmlengine/qqmlengine.pro2
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp86
-rw-r--r--tests/auto/qml/qqmlerror/tst_qqmlerror.cpp2
-rw-r--r--tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp7
-rw-r--r--tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp26
-rw-r--r--tests/auto/qml/qqmlimport/qqmlimport.pro5
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp5
-rw-r--r--tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro2
-rw-r--r--tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.17.qml31
-rw-r--r--tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt0
-rw-r--r--tests/auto/qml/qqmllanguage/data/bareQmlImport.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.2.qmlbin404 -> 404 bytes
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/fuzzed.3.qmlbin0 -> 4777 bytes
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml19
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/qqmllanguage.pro2
-rw-r--r--tests/auto/qml/qqmllanguage/qqmllanguage.qrc5
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp9
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h31
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp306
-rw-r--r--tests/auto/qml/qqmllistcompositor/qqmllistcompositor.pro2
-rw-r--r--tests/auto/qml/qqmllistmodel/qqmllistmodel.pro2
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp63
-rw-r--r--tests/auto/qml/qqmllistmodelworkerscript/qqmllistmodelworkerscript.pro2
-rw-r--r--tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp4
-rw-r--r--tests/auto/qml/qqmllocale/data/localeAsCppProperty.qml6
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp22
-rw-r--r--tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp11
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/data/multiSingleton.qml6
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml16
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton2.qml6
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/internal/InternalType.qml6
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/moduleWithQmlSingleton.pro18
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/plugin.cpp50
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro3
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp17
-rw-r--r--tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp3
-rw-r--r--tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro2
-rw-r--r--tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp4
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js6
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js6
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js4
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js3
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js5
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml9
-rw-r--r--tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js2
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml4
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml5
-rw-r--r--tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml6
-rw-r--r--tests/auto/qml/qqmlparser/qqmlparser.pro4
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp143
-rw-r--r--tests/auto/qml/qqmlproperty/data/interfaceBinding.qml27
-rw-r--r--tests/auto/qml/qqmlproperty/data/nullPropertyBinding.qml22
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp113
-rw-r--r--tests/auto/qml/qqmlpropertycache/data/SpecialObject1.qml5
-rw-r--r--tests/auto/qml/qqmlpropertycache/data/SpecialObject2.qml5
-rw-r--r--tests/auto/qml/qqmlpropertycache/data/noDuckType.qml7
-rw-r--r--tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp12
-rw-r--r--tests/auto/qml/qqmlpropertymap/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro2
-rw-r--r--tests/auto/qml/qqmlsqldatabase/dummy_imports.qml8
-rw-r--r--tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp2
-rw-r--r--tests/auto/qml/qqmltablemodel/data/TestModel.qml50
-rw-r--r--tests/auto/qml/qqmltablemodel/data/TestUtils.js45
-rw-r--r--tests/auto/qml/qqmltablemodel/data/common.qml149
-rw-r--r--tests/auto/qml/qqmltablemodel/data/complex.qml68
-rw-r--r--tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml55
-rw-r--r--tests/auto/qml/qqmltablemodel/data/empty.qml82
-rw-r--r--tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml47
-rw-r--r--tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml86
-rw-r--r--tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml84
-rw-r--r--tests/auto/qml/qqmltablemodel/qqmltablemodel.pro10
-rw-r--r--tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp980
-rw-r--r--tests/auto/qml/qqmltimer/dummy_imports.qml9
-rw-r--r--tests/auto/qml/qqmltranslation/data/mylibrary.js5
-rw-r--r--tests/auto/qml/qqmltranslation/data/nested_js_translation.js3
-rw-r--r--tests/auto/qml/qqmltranslation/data/preferjs.qml8
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp30
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Com/Orga/BaseStyle.qml5
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/Handler.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Com/Orga/Style.qml6
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Com/Orga/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml5
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml3
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp33
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/color_read.qml3
-rw-r--r--tests/auto/qml/qqmlvaluetypes/testtypes.h3
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp34
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp51
-rw-r--r--tests/auto/qml/qquickworkerscript/qquickworkerscript.pro2
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp46
-rw-r--r--tests/auto/qml/qv4assembler/tst_qv4assembler.cpp14
-rw-r--r--tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp25
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp2
-rw-r--r--tests/auto/qml/v4traced/tst_v4traced.cpp325
-rw-r--r--tests/auto/qml/v4traced/v4traced.pro5
206 files changed, 4857 insertions, 856 deletions
diff --git a/tests/auto/qml/bindingdependencyapi/dummy_imports.qml b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml
new file mode 100644
index 0000000000..b9a196e188
--- /dev/null
+++ b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/quit.js b/tests/auto/qml/debugger/qqmldebugjs/data/quit.js
new file mode 100644
index 0000000000..1a45fd5538
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/quit.js
@@ -0,0 +1,4 @@
+function quit() {
+ console.log("hit");
+ Qt.quit();
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/quitInJS.qml b/tests/auto/qml/debugger/qqmldebugjs/data/quitInJS.qml
new file mode 100644
index 0000000000..6e4183100b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/quitInJS.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import "quit.js" as Quit;
+
+//DO NOT CHANGE
+
+Item {
+ Timer {
+ running: true
+ triggeredOnStart: true
+ onTriggered: Quit.quit();
+ }
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
index 1ac28c473b..5b6c43bc0c 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -38,7 +38,6 @@
#include <QtTest/qtest.h>
#include <QtTest/qtestsystem.h>
#include <QtCore/qprocess.h>
-#include <QtCore/qtimer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qmutex.h>
@@ -59,6 +58,8 @@ const char *ONCOMPLETED_QMLFILE = "oncompleted.qml";
const char *CREATECOMPONENT_QMLFILE = "createComponent.qml";
const char *CONDITION_QMLFILE = "condition.qml";
const char *QUIT_QMLFILE = "quit.qml";
+const char *QUITINJS_QMLFILE = "quitInJS.qml";
+const char *QUIT_JSFILE = "quit.js";
const char *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml";
const char *STEPACTION_QMLFILE = "stepAction.qml";
const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml";
@@ -110,8 +111,10 @@ private slots:
void setBreakpointInScriptOnOptimizedBinding();
void setBreakpointInScriptWithCondition_data() { targetData(); }
void setBreakpointInScriptWithCondition();
- void setBreakpointInScriptThatQuits_data() { targetData(); }
+ void setBreakpointInScriptThatQuits_data() { targetData(); };
void setBreakpointInScriptThatQuits();
+ void setBreakpointInJavaScript_data();
+ void setBreakpointInJavaScript();
void setBreakpointWhenAttaching();
void clearBreakpoint_data() { targetData(); }
@@ -162,8 +165,6 @@ private:
void targetData();
bool waitForClientSignal(const char *signal, int timeout = 30000);
void checkVersionParameters();
-
- QTime t;
};
@@ -171,7 +172,6 @@ private:
void tst_QQmlDebugJS::initTestCase()
{
QQmlDebugTest::initTestCase();
- t.start();
}
QQmlDebugTest::ConnectResult tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile,
@@ -454,6 +454,48 @@ void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
}
+void tst_QQmlDebugJS::setBreakpointInJavaScript_data()
+{
+ QTest::addColumn<bool>("qmlscene");
+ QTest::addColumn<bool>("seedCache");
+ QTest::newRow("custom / immediate") << false << false;
+ QTest::newRow("qmlscene / immediate") << true << false;
+ QTest::newRow("custom / seeded") << false << true;
+ QTest::newRow("qmlscene / seeded") << true << true;
+}
+
+void tst_QQmlDebugJS::setBreakpointInJavaScript()
+{
+ QFETCH(bool, qmlscene);
+ QFETCH(bool, seedCache);
+
+ if (seedCache) { // Make sure there is a qmlc file that the engine should _not_ laod.
+ QProcess process;
+ process.start(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene",
+ { testFile(QUITINJS_QMLFILE) });
+ QTRY_COMPARE(process.state(), QProcess::NotRunning);
+ }
+
+ QCOMPARE(init(qmlscene, QUITINJS_QMLFILE), ConnectSuccess);
+
+ const int sourceLine = 2;
+
+ m_client->setBreakpoint(QLatin1String(QUIT_JSFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(QUIT_JSFILE));
+
+ m_client->continueDebugging(QV4DebugClient::Continue);
+
+ QVERIFY(m_process->waitForFinished());
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+}
+
void tst_QQmlDebugJS::setBreakpointWhenAttaching()
{
int sourceLine = 35;
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index 99c90c142f..0ebf43eb6f 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -524,7 +524,7 @@ void tst_QQmlEngineDebugService::watch_property()
QCOMPARE(spy.count(), 1);
QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name.toUtf8());
- QCOMPARE(spy.at(0).at(1).value<QVariant>(), qVariantFromValue(origWidth*2));
+ QCOMPARE(spy.at(0).at(1).value<QVariant>(), QVariant::fromValue(origWidth*2));
}
void tst_QQmlEngineDebugService::watch_object()
@@ -772,11 +772,11 @@ void tst_QQmlEngineDebugService::queryObject()
}
// test specific property values
- QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500));
- QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600));
- QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue")));
+ QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500));
+ QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600));
+ QCOMPARE(findProperty(rect.properties, "color").value, QVariant::fromValue(QColor("blue")));
- QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
+ QCOMPARE(findProperty(text.properties, "color").value, QVariant::fromValue(QColor("blue")));
} else {
foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
@@ -851,11 +851,11 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
}
// test specific property values
- QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500));
- QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600));
- QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue")));
+ QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500));
+ QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600));
+ QCOMPARE(findProperty(rect.properties, "color").value, QVariant::fromValue(QColor("blue")));
- QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
+ QCOMPARE(findProperty(text.properties, "color").value, QVariant::fromValue(QColor("blue")));
} else {
foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
@@ -1004,15 +1004,15 @@ void tst_QQmlEngineDebugService::queryExpressionResult_data()
QTest::addColumn<QString>("expr");
QTest::addColumn<QVariant>("result");
- QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60);
- QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500);
- QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>"));
- QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>"));
- QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QVariantList() << QVariant(QString("<unnamed object>")));
+ QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60);
+ QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500);
+ QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>"));
+ QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>"));
+ QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>")));
QVariantMap map;
map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
- QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map);
- QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05);
+ QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map);
+ QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05);
}
void tst_QQmlEngineDebugService::queryExpressionResultInRootContext()
@@ -1052,15 +1052,15 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
QTest::addColumn<QString>("expr");
QTest::addColumn<QVariant>("result");
- QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60);
- QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500);
- QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>"));
- QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>"));
- QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QVariantList() << QVariant(QString("<unnamed object>")));
+ QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60);
+ QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500);
+ QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>"));
+ QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>"));
+ QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>")));
QVariantMap map;
map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
- QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map);
- QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05);
+ QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map);
+ QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05);
}
void tst_QQmlEngineDebugService::setBindingForObject()
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 497c721f50..84f5eebd10 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -36,7 +36,6 @@
#include <QQmlComponent>
#include <private/qv4engine_p.h>
#include <private/qv4debugging_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4string_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index a5246c8792..4c04afe886 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -211,7 +211,6 @@ built-ins/Promise/prototype/then/ctor-throws.js fails
built-ins/Promise/race/ctx-ctor.js fails
built-ins/Proxy/ownKeys/return-duplicate-entries-throws.js fails
built-ins/Proxy/ownKeys/return-duplicate-symbol-entries-throws.js fails
-built-ins/RegExp/S15.10.2.12_A2_T1.js fails
built-ins/RegExp/prototype/Symbol.match/builtin-success-u-return-val-groups.js fails
built-ins/RegExp/prototype/Symbol.split/species-ctor.js fails
built-ins/RegExp/prototype/exec/S15.10.6.2_A5_T3.js fails
@@ -219,7 +218,6 @@ built-ins/RegExp/prototype/exec/failure-lastindex-access.js fails
built-ins/RegExp/prototype/exec/success-lastindex-access.js fails
built-ins/RegExp/prototype/source/value-line-terminator.js fails
built-ins/RegExp/prototype/test/S15.10.6.3_A1_T22.js fails
-built-ins/RegExp/u180e.js fails
built-ins/RegExp/unicode_restricted_brackets.js fails
built-ins/RegExp/unicode_restricted_character_class_escape.js fails
built-ins/RegExp/unicode_restricted_identity_escape.js fails
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
index 2f41e57324..9fe2de5368 100644
--- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -509,7 +509,7 @@ static bool executeTest(const QByteArray &data, bool runAsModule = false, const
QVector<QUrl> modulesToLoad = { rootModuleUrl };
while (!modulesToLoad.isEmpty()) {
QUrl url = modulesToLoad.takeFirst();
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> module;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> module;
QFile f(url.toLocalFile());
if (f.open(QIODevice::ReadOnly)) {
diff --git a/tests/auto/qml/parserstress/dummy_imports.qml b/tests/auto/qml/parserstress/dummy_imports.qml
new file mode 100644
index 0000000000..b9a196e188
--- /dev/null
+++ b/tests/auto/qml/parserstress/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/parserstress/tst_parserstress.cpp b/tests/auto/qml/parserstress/tst_parserstress.cpp
index e32fcabaf3..11851de76e 100644
--- a/tests/auto/qml/parserstress/tst_parserstress.cpp
+++ b/tests/auto/qml/parserstress/tst_parserstress.cpp
@@ -130,8 +130,7 @@ void tst_parserstress::ecmascript()
QCOMPARE(component.errors().at(1).line(), 142);
} else {
-
- QVERIFY(!component.isError());
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
}
}
diff --git a/tests/auto/qml/qjsengine/dummy_imports.qml b/tests/auto/qml/qjsengine/dummy_imports.qml
new file mode 100644
index 0000000000..8d86f3583b
--- /dev/null
+++ b/tests/auto/qml/qjsengine/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQml 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index cd7796827d..f1ff396d4f 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -66,6 +66,10 @@ private slots:
void newArray();
void newArray_HooliganTask218092();
void newArray_HooliganTask233836();
+ void toScriptValue_data();
+ void toScriptValue();
+ void toScriptValuenotroundtripped_data();
+ void toScriptValuenotroundtripped();
void newVariant();
void newVariant_valueOfToString();
void newVariant_valueOfEnum();
@@ -94,6 +98,7 @@ private slots:
void valueConversion_basic2();
void valueConversion_dateTime();
void valueConversion_regExp();
+ void valueConversion_RegularExpression();
void castWithMultipleInheritance();
void collectGarbage();
void gcWithNestedDataStructure();
@@ -135,6 +140,8 @@ private slots:
void qRegExpInport_data();
void qRegExpInport();
+ void qRegularExpressionImport_data();
+ void qRegularExpressionImport();
void dateRoundtripJSQtJS();
void dateRoundtripQtJSQt();
void dateConversionJSQt();
@@ -194,7 +201,9 @@ private slots:
void engineForObject();
void intConversion_QTBUG43309();
+#ifdef QT_DEPRECATED
void toFixed();
+#endif
void argumentEvaluationOrder();
@@ -239,6 +248,9 @@ private slots:
void aggressiveGc();
void noAccumulatorInTemplateLiteral();
+ void interrupt_data();
+ void interrupt();
+
void triggerBackwardJumpWithDestructuring();
public:
@@ -484,17 +496,97 @@ void tst_QJSEngine::newArray_HooliganTask233836()
}
}
+void tst_QJSEngine::toScriptValue_data()
+{
+ QTest::addColumn<QVariant>("input");
+
+ QTest::newRow("UnknownType") << QVariant(int(QMetaType::UnknownType), nullptr);
+ QTest::newRow("Nullptr") << QVariant(int(QMetaType::Nullptr), nullptr);
+ QTest::newRow("true") << QVariant(true);
+ QTest::newRow("false") << QVariant(false);
+ QTest::newRow("int") << QVariant(int(42));
+ QTest::newRow("uint") << QVariant(uint(42));
+ QTest::newRow("longlong") << QVariant(qlonglong(4242));
+ QTest::newRow("ulonglong") << QVariant(qulonglong(4242));
+ QTest::newRow("double") << QVariant(double(42.42));
+ QTest::newRow("float") << QVariant(float(42.42));
+ QTest::newRow("qstring") << QVariant(QString::fromLatin1("hello"));
+ QTest::newRow("qbytearray") << QVariant(QByteArray("hello"));
+ QTest::newRow("short") << QVariant(short('r'));
+ QTest::newRow("ushort") << QVariant(short('b'));
+ QTest::newRow("char") << QVariant(char('r'));
+ QTest::newRow("uchar") << QVariant(uchar('b'));
+ QTest::newRow("qchar") << QVariant(QString::fromUtf8("å").at(0));
+ QTest::newRow("qdate") << QVariant(QDate(1925, 5, 8));
+ QTest::newRow("qtime") << QVariant(QTime(4, 5, 6));
+ QTest::newRow("qregularexpression") << QVariant(QRegularExpression(".*"));
+ QTest::newRow("qpointf") << QVariant(QPointF(42, 24));
+ QTest::newRow("qvariantlist") << QVariant(QVariantList() << 42.24 << 5 << "hello");
+ QTest::newRow("qvariantlist_point") << QVariant(QVariantList() << 42.24 << QPointF(42.24, 24.42) << QPointF(24.42, 42.24));
+ QVariantMap vm; vm.insert("test", 55); vm.insert("abc", 42.42);;
+ QTest::newRow("qvariantmap") << QVariant(vm);
+ vm.clear(); vm.insert("point1", QPointF(42.24, 24.42)); vm.insert("point2", QPointF(42.24, 24.42));
+ QTest::newRow("qvariantmap_point") << QVariant(vm);
+ QTest::newRow("qvariant") << QVariant(QVariant(42));
+ QTest::newRow("QList<int>") << QVariant::fromValue(QList<int>() << 1 << 2 << 3 << 4);
+ QTest::newRow("QVector<int>") << QVariant::fromValue(QVector<int>() << 1 << 2 << 3 << 4);
+ QTest::newRow("QList<QString>") << QVariant::fromValue(QVector<QString>() << "1" << "2" << "3" << "4");
+ QTest::newRow("QStringList") << QVariant::fromValue(QStringList() << "1" << "2" << "3" << "4");
+ QTest::newRow("QMap<QString, QString>") << QVariant::fromValue(QMap<QString, QString>{{ "1", "2" }, { "3", "4" }});
+ QTest::newRow("QHash<QString, QString>") << QVariant::fromValue(QHash<QString, QString>{{ "1", "2" }, { "3", "4" }});
+ QTest::newRow("QMap<QString, QPointF>") << QVariant::fromValue(QMap<QString, QPointF>{{ "1", { 42.24, 24.42 } }, { "3", { 24.42, 42.24 } }});
+ QTest::newRow("QHash<QString, QPointF>") << QVariant::fromValue(QHash<QString, QPointF>{{ "1", { 42.24, 24.42 } }, { "3", { 24.42, 42.24 } }});
+}
+
+void tst_QJSEngine::toScriptValue()
+{
+ QFETCH(QVariant, input);
+
+ QJSEngine engine;
+ QJSValue outputJS = engine.toScriptValue(input);
+ QVariant output = engine.fromScriptValue<QVariant>(outputJS);
+
+ QCOMPARE(input, output);
+}
+
+void tst_QJSEngine::toScriptValuenotroundtripped_data()
+{
+ QTest::addColumn<QVariant>("input");
+ QTest::addColumn<QVariant>("output");
+
+ QTest::newRow("QList<QObject*>") << QVariant::fromValue(QList<QObject*>() << this) << QVariant(QVariantList() << QVariant::fromValue(this));
+ QTest::newRow("QObjectList") << QVariant::fromValue(QObjectList() << this) << QVariant(QVariantList() << QVariant::fromValue(this));
+ QTest::newRow("QList<QPoint>") << QVariant::fromValue(QList<QPointF>() << QPointF(42.24, 24.42) << QPointF(42.24, 24.42)) << QVariant(QVariantList() << QPointF(42.24, 24.42) << QPointF(42.24, 24.42));
+ QTest::newRow("QVector<QPoint>") << QVariant::fromValue(QVector<QPointF>() << QPointF(42.24, 24.42) << QPointF(42.24, 24.42)) << QVariant(QVariantList() << QPointF(42.24, 24.42) << QPointF(42.24, 24.42));
+ QTest::newRow("VoidStar") << QVariant(int(QMetaType::VoidStar), nullptr) << QVariant(int(QMetaType::Nullptr), nullptr);
+ QTest::newRow("qregex") << QVariant(QRegExp(".*", Qt::CaseSensitive, QRegExp::RegExp2)) << QVariant(QRegularExpression(".*"));
+}
+
+// This is almost the same as toScriptValue, but the inputs don't roundtrip to
+// exactly the same value.
+void tst_QJSEngine::toScriptValuenotroundtripped()
+{
+ QFETCH(QVariant, input);
+ QFETCH(QVariant, output);
+
+ QJSEngine engine;
+ QJSValue outputJS = engine.toScriptValue(input);
+ QVariant actualOutput = engine.fromScriptValue<QVariant>(outputJS);
+
+ QCOMPARE(actualOutput, output);
+}
+
void tst_QJSEngine::newVariant()
{
QJSEngine eng;
{
QJSValue opaque = eng.toScriptValue(QVariant(QPoint(1, 2)));
QVERIFY(!opaque.isUndefined());
- QCOMPARE(opaque.isVariant(), true);
+ QCOMPARE(opaque.isVariant(), false);
QVERIFY(!opaque.isCallable());
QCOMPARE(opaque.isObject(), true);
QVERIFY(!opaque.prototype().isUndefined());
- QCOMPARE(opaque.prototype().isVariant(), true);
+ QCOMPARE(opaque.prototype().isVariant(), false);
QVERIFY(opaque.property("valueOf").callWithInstance(opaque).equals(opaque));
}
}
@@ -508,7 +600,7 @@ void tst_QJSEngine::newVariant_valueOfToString()
QJSValue value = object.property("valueOf").callWithInstance(object);
QVERIFY(value.isObject());
QVERIFY(value.strictlyEquals(object));
- QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint, QPoint(10,20))"));
+ QCOMPARE(object.toString(), QString::fromLatin1("QPoint(10, 20)"));
}
}
@@ -526,22 +618,27 @@ void tst_QJSEngine::newVariant_valueOfEnum()
void tst_QJSEngine::newRegExp()
{
QJSEngine eng;
- QJSValue rexp = eng.toScriptValue(QRegExp("foo"));
- QVERIFY(!rexp.isUndefined());
- QCOMPARE(rexp.isRegExp(), true);
- QCOMPARE(rexp.isObject(), true);
- QCOMPARE(rexp.isCallable(), false);
- // prototype should be RegExp.prototype
- QVERIFY(!rexp.prototype().isUndefined());
- QCOMPARE(rexp.prototype().isObject(), true);
- // Get [[Class]] internal property of RegExp Prototype Object.
- // See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
- // See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
- QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
- QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
- QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
+ QJSValue rexps[] = {
+ eng.toScriptValue(QRegularExpression("foo")),
+ eng.toScriptValue(QRegExp("foo"))
+ };
+ for (const auto &rexp : rexps) {
+ QVERIFY(!rexp.isUndefined());
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isObject(), true);
+ QCOMPARE(rexp.isCallable(), false);
+ // prototype should be RegExp.prototype
+ QVERIFY(!rexp.prototype().isUndefined());
+ QCOMPARE(rexp.prototype().isObject(), true);
+ // Get [[Class]] internal property of RegExp Prototype Object.
+ // See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
+ // See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
+ QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
+ QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
+ QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
- QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
+ QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
+ }
}
void tst_QJSEngine::jsRegExp()
@@ -1351,12 +1448,10 @@ public:
Q_DECLARE_METATYPE(Foo)
Q_DECLARE_METATYPE(Foo*)
-Q_DECLARE_METATYPE(QLinkedList<QString>)
Q_DECLARE_METATYPE(QList<Foo>)
Q_DECLARE_METATYPE(QVector<QChar>)
Q_DECLARE_METATYPE(QStack<int>)
Q_DECLARE_METATYPE(QQueue<char>)
-Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
void tst_QJSEngine::valueConversion_basic()
{
@@ -1493,15 +1588,15 @@ void tst_QJSEngine::valueConversion_QVariant()
QCOMPARE(val.toString(), str);
}
{
- QJSValue val = eng.toScriptValue(qVariantFromValue((QObject*)this));
+ QJSValue val = eng.toScriptValue(QVariant::fromValue((QObject*)this));
QVERIFY(!val.isVariant());
QVERIFY(val.isQObject());
QCOMPARE(val.toQObject(), (QObject*)this);
}
{
- QVariant var = qVariantFromValue(QPoint(123, 456));
+ QVariant var = QVariant::fromValue(QPoint(123, 456));
QJSValue val = eng.toScriptValue(var);
- QVERIFY(val.isVariant());
+ QVERIFY(!val.isVariant());
QCOMPARE(val.toVariant(), var);
}
@@ -1607,6 +1702,28 @@ void tst_QJSEngine::valueConversion_regExp()
}
}
+void tst_QJSEngine::valueConversion_RegularExpression()
+{
+ QJSEngine eng;
+ {
+ QRegularExpression in = QRegularExpression("foo");
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
+ QCOMPARE(out.pattern(), in.pattern());
+ QCOMPARE(out.patternOptions(), in.patternOptions());
+ }
+ {
+ QRegularExpression in = QRegularExpression("foo",
+ QRegularExpression::CaseInsensitiveOption);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(val), in);
+ QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
+ QCOMPARE(out.patternOptions(), in.patternOptions());
+ }
+}
+
Q_DECLARE_METATYPE(QGradient)
Q_DECLARE_METATYPE(QGradient*)
Q_DECLARE_METATYPE(QLinearGradient)
@@ -2956,6 +3073,8 @@ void tst_QJSEngine::reentrancy_objectCreation()
QJSValue r2 = eng2.evaluate("new RegExp('foo', 'gim')");
QCOMPARE(qjsvalue_cast<QRegExp>(r1), qjsvalue_cast<QRegExp>(r2));
QCOMPARE(qjsvalue_cast<QRegExp>(r2), qjsvalue_cast<QRegExp>(r1));
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(r1), qjsvalue_cast<QRegularExpression>(r2));
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(r2), qjsvalue_cast<QRegularExpression>(r1));
}
{
QJSValue o1 = eng1.newQObject(temp);
@@ -3151,6 +3270,56 @@ void tst_QJSEngine::qRegExpInport()
}
}
+void tst_QJSEngine::qRegularExpressionImport_data()
+{
+ QTest::addColumn<QRegularExpression>("rx");
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("matched");
+
+ QTest::newRow("normal") << QRegularExpression("(test|foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("normal2") << QRegularExpression("(Test|Foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive") << QRegularExpression("(test|foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive2") << QRegularExpression("(Test|Foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
+ QTest::newRow("b(a*)(b*)") << QRegularExpression("b(a*)(b*)", QRegularExpression::CaseInsensitiveOption) << "aaabbBbaAabaAaababaaabbaaab";
+ QTest::newRow("greedy") << QRegularExpression("a*(a*)", QRegularExpression::CaseInsensitiveOption) << "aaaabaaba";
+ QTest::newRow("wildcard") << QRegularExpression(".*\\.txt") << "file.txt";
+ QTest::newRow("wildcard 2") << QRegularExpression("a.b\\.txt") << "ab.txt abb.rtc acb.txt";
+ QTest::newRow("slash") << QRegularExpression("g/.*/s", QRegularExpression::CaseInsensitiveOption) << "string/string/string";
+ QTest::newRow("slash2") << QRegularExpression("g / .* / s", QRegularExpression::CaseInsensitiveOption) << "string / string / string";
+ QTest::newRow("fixed") << QRegularExpression("a\\*aa\\.a\\(ba\\)\\*a\\\\ba", QRegularExpression::CaseInsensitiveOption) << "aa*aa.a(ba)*a\\ba";
+ QTest::newRow("fixed insensitive") << QRegularExpression("A\\*A", QRegularExpression::CaseInsensitiveOption) << "a*A A*a A*A a*a";
+ QTest::newRow("fixed sensitive") << QRegularExpression("A\\*A") << "a*A A*a A*A a*a";
+ QTest::newRow("html") << QRegularExpression("<b>(.*)</b>") << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("html minimal") << QRegularExpression("^<b>(.*)</b>$") << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("aaa") << QRegularExpression("a{2,5}") << "aAaAaaaaaAa";
+ QTest::newRow("aaa minimal") << QRegularExpression("^a{2,5}$") << "aAaAaaaaaAa";
+ QTest::newRow("minimal") << QRegularExpression("^.*\\} [*8]$") << "}?} ?} *";
+ QTest::newRow(".? minimal") << QRegularExpression("^.?$") << ".?";
+ QTest::newRow(".+ minimal") << QRegularExpression("^.+$") << ".+";
+ QTest::newRow("[.?] minimal") << QRegularExpression("^[.?]$") << ".?";
+ QTest::newRow("[.+] minimal") << QRegularExpression("^[.+]$") << ".+";
+}
+
+void tst_QJSEngine::qRegularExpressionImport()
+{
+ QFETCH(QRegularExpression, rx);
+ QFETCH(QString, string);
+
+ QJSEngine eng;
+ QJSValue rexp;
+ rexp = eng.toScriptValue(rx);
+
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isCallable(), false);
+
+ QJSValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
+ QJSValue result = func.call(QJSValueList() << string << rexp);
+
+ const QRegularExpressionMatch match = rx.match(string);
+ for (int i = 0; i <= match.lastCapturedIndex(); i++)
+ QCOMPARE(result.property(i).toString(), match.captured(i));
+}
+
// QScriptValue::toDateTime() returns a local time, whereas JS dates
// are always stored as UTC. Qt Script must respect the current time
// zone, and correctly adjust for daylight saving time that may be in
@@ -4156,7 +4325,10 @@ void tst_QJSEngine::engineForObject()
QVERIFY(!qjsEngine(&object));
QJSValue wrapper = engine.newQObject(&object);
QQmlEngine::setObjectOwnership(&object, QQmlEngine::CppOwnership);
+ QVERIFY(qjsEngine(&object));
+#ifdef QT_DEPRECATED
QCOMPARE(qjsEngine(&object), wrapper.engine());
+#endif
}
QVERIFY(!qjsEngine(&object));
}
@@ -4171,6 +4343,7 @@ void tst_QJSEngine::intConversion_QTBUG43309()
QCOMPARE(result.toNumber(), 25.0);
}
+#ifdef QT_DEPRECATED
// QTBUG-44039 and QTBUG-43885:
void tst_QJSEngine::toFixed()
{
@@ -4182,6 +4355,7 @@ void tst_QJSEngine::toFixed()
QVERIFY(result.isString());
QCOMPARE(result.toString(), QStringLiteral("12.1"));
}
+#endif
void tst_QJSEngine::argumentEvaluationOrder()
{
@@ -4693,6 +4867,87 @@ void tst_QJSEngine::noAccumulatorInTemplateLiteral()
qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc);
}
+void tst_QJSEngine::interrupt_data()
+{
+ QTest::addColumn<int>("jitThreshold");
+ QTest::addColumn<QString>("code");
+
+ const int big = (1 << 24);
+ for (int i = 0; i <= big; i += big) {
+ const char *mode = i ? "interpret" : "jit";
+ QTest::addRow("for with content / %s", mode) << i << "var a = 0; for (;;) { a += 2; }";
+ QTest::addRow("for empty / %s", mode) << i << "for (;;) {}";
+ QTest::addRow("for continue / %s", mode) << i << "for (;;) { continue; }";
+ QTest::addRow("while with content / %s", mode) << i << "var a = 0; while (true) { a += 2; }";
+ QTest::addRow("while empty / %s", mode) << i << "while (true) {}";
+ QTest::addRow("while continue / %s", mode) << i << "while (true) { continue; }";
+ QTest::addRow("do with content / %s", mode) << i << "var a = 0; do { a += 2; } while (true);";
+ QTest::addRow("do empty / %s", mode) << i << "do {} while (true);";
+ QTest::addRow("do continue / %s", mode) << i << "do { continue; } while (true);";
+ QTest::addRow("nested loops / %s", mode) << i << "while (true) { for (;;) {} }";
+ QTest::addRow("labeled continue / %s", mode) << i << "a: while (true) { for (;;) { continue a; } }";
+ QTest::addRow("labeled break / %s", mode) << i << "while (true) { a: for (;;) { break a; } }";
+ QTest::addRow("tail call / %s", mode) << i << "'use strict';\nfunction x() { return x(); }; x();";
+ QTest::addRow("huge array join / %s", mode) << i << "Array(1E9)|1";
+ }
+}
+
+class TemporaryJitThreshold
+{
+ Q_DISABLE_COPY_MOVE(TemporaryJitThreshold)
+public:
+ TemporaryJitThreshold(int threshold) {
+ m_wasSet = qEnvironmentVariableIsSet(m_envVar);
+ m_value = qgetenv(m_envVar);
+ qputenv(m_envVar, QByteArray::number(threshold));
+ }
+
+ ~TemporaryJitThreshold()
+ {
+ if (m_wasSet)
+ qputenv(m_envVar, m_value);
+ else
+ qunsetenv(m_envVar);
+ }
+
+private:
+ const char *m_envVar = "QV4_JIT_CALL_THRESHOLD";
+ bool m_wasSet = false;
+ QByteArray m_value;
+};
+
+void tst_QJSEngine::interrupt()
+{
+#if QT_CONFIG(cxx11_future)
+ QFETCH(int, jitThreshold);
+ QFETCH(QString, code);
+
+ TemporaryJitThreshold threshold(jitThreshold);
+ Q_UNUSED(threshold);
+
+ QJSEngine *engineInThread = nullptr;
+ QScopedPointer<QThread> worker(QThread::create([&engineInThread, &code, jitThreshold](){
+ QJSEngine jsEngine;
+ engineInThread = &jsEngine;
+ QJSValue result = jsEngine.evaluate(code);
+ QVERIFY(jsEngine.isInterrupted());
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), QString::fromLatin1("Error: Interrupted"));
+ engineInThread = nullptr;
+ }));
+ worker->start();
+
+ QTRY_VERIFY(engineInThread);
+
+ engineInThread->setInterrupted(true);
+
+ QVERIFY(worker->wait());
+ QVERIFY(!engineInThread);
+#else
+ QSKIP("This test requires C++11 futures");
+#endif
+}
+
void tst_QJSEngine::triggerBackwardJumpWithDestructuring()
{
QJSEngine engine;
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index a34a9e5188..37d0ea4dea 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -52,7 +52,9 @@ void tst_QJSValue::ctor_invalid()
{
QJSValue v;
QVERIFY(v.isUndefined());
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -63,7 +65,9 @@ void tst_QJSValue::ctor_undefinedWithEngine()
QJSValue v = eng.toScriptValue(QVariant());
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -75,7 +79,9 @@ void tst_QJSValue::ctor_nullWithEngine()
QVERIFY(!v.isUndefined());
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -88,7 +94,9 @@ void tst_QJSValue::ctor_boolWithEngine()
QCOMPARE(v.isBool(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -101,7 +109,9 @@ void tst_QJSValue::ctor_intWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -118,7 +128,9 @@ void tst_QJSValue::ctor_int()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -131,7 +143,9 @@ void tst_QJSValue::ctor_uintWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -148,7 +162,9 @@ void tst_QJSValue::ctor_uint()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -161,7 +177,9 @@ void tst_QJSValue::ctor_floatWithEngine()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -178,7 +196,9 @@ void tst_QJSValue::ctor_float()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -191,7 +211,9 @@ void tst_QJSValue::ctor_stringWithEngine()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), &eng);
+#endif
}
}
@@ -203,7 +225,9 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
{
QJSValue v("ciao");
@@ -211,7 +235,9 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
}
@@ -223,12 +249,16 @@ void tst_QJSValue::ctor_copyAndAssignWithEngine()
QJSValue v = eng.toScriptValue(1.0);
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v2.engine(), &eng);
+#endif
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v3.engine(), &eng);
+#endif
QJSValue v4 = eng.toScriptValue(2.0);
QCOMPARE(v4.strictlyEquals(v), false);
@@ -253,7 +283,9 @@ void tst_QJSValue::ctor_undefined()
QJSValue v(QJSValue::UndefinedValue);
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_null()
@@ -262,7 +294,9 @@ void tst_QJSValue::ctor_null()
QVERIFY(!v.isUndefined());
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_bool()
@@ -273,7 +307,9 @@ void tst_QJSValue::ctor_bool()
QCOMPARE(v.isBool(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
+#ifdef QT_DEPRECATED
QCOMPARE(v.engine(), (QJSEngine *)nullptr);
+#endif
}
void tst_QJSValue::ctor_copyAndAssign()
@@ -281,12 +317,16 @@ void tst_QJSValue::ctor_copyAndAssign()
QJSValue v(1.0);
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v2.engine(), (QJSEngine *)nullptr);
+#endif
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
+#ifdef QT_DEPRECATED
QCOMPARE(v3.engine(), (QJSEngine *)nullptr);
+#endif
QJSValue v4(2.0);
QCOMPARE(v4.strictlyEquals(v), false);
@@ -411,8 +451,8 @@ void tst_QJSValue::toString()
// variant should use internal valueOf(), then fall back to QVariant::toString(),
// then fall back to "QVariant(typename)"
QJSValue variant = eng.toScriptValue(QPoint(10, 20));
- QVERIFY(variant.isVariant());
- QCOMPARE(variant.toString(), QString::fromLatin1("QVariant(QPoint, QPoint(10,20))"));
+ QVERIFY(!variant.isVariant());
+ QCOMPARE(variant.toString(), QString::fromLatin1("QPoint(10, 20)"));
variant = eng.toScriptValue(QUrl());
QVERIFY(variant.isVariant());
QVERIFY(variant.toString().isEmpty());
@@ -423,7 +463,9 @@ void tst_QJSValue::toString()
QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
o = createUnboundValue(o);
+#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
+#endif
QCOMPARE(o.toString(), QStringLiteral("[object Object]"));
}
@@ -435,7 +477,9 @@ void tst_QJSValue::toString()
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
o = createUnboundValue(o);
+#ifdef QT_DEPRECATED
QVERIFY(!o.engine());
+#endif
QCOMPARE(o.toString(), QStringLiteral("1,2,3"));
}
@@ -1034,6 +1078,20 @@ void tst_QJSValue::toVariant()
QJSValue rxObject = eng.toScriptValue(rx);
QVERIFY(rxObject.isRegExp());
QVariant var = rxObject.toVariant();
+
+ // We can't roundtrip a QRegExp this way, as toVariant() has no information on whether we
+ // want QRegExp or QRegularExpression. It will always create a QRegularExpression.
+ QCOMPARE(var.type(), QMetaType::QRegularExpression);
+ QRegularExpression result = var.toRegularExpression();
+ QCOMPARE(result.pattern(), rx.pattern());
+ QCOMPARE(result.patternOptions() & QRegularExpression::CaseInsensitiveOption, 0);
+ }
+
+ {
+ QRegularExpression rx = QRegularExpression("[0-9a-z]+");
+ QJSValue rxObject = eng.toScriptValue(rx);
+ QVERIFY(rxObject.isRegExp());
+ QVariant var = rxObject.toVariant();
QCOMPARE(var, QVariant(rx));
}
@@ -1114,7 +1172,7 @@ void tst_QJSValue::toQObject_nonQObject_data()
QTest::newRow("array") << engine->newArray();
QTest::newRow("date") << engine->evaluate("new Date(124)");
QTest::newRow("variant(12345)") << engine->toScriptValue(QVariant(12345));
- QTest::newRow("variant((QObject*)0)") << engine->toScriptValue(qVariantFromValue((QObject*)nullptr));
+ QTest::newRow("variant((QObject*)0)") << engine->toScriptValue(QVariant::fromValue((QObject*)nullptr));
QTest::newRow("newQObject(0)") << engine->newQObject(nullptr);
}
@@ -1201,6 +1259,32 @@ void tst_QJSValue::toRegExp()
QVERIFY(qjsvalue_cast<QRegExp>(eng.toScriptValue(QVariant())).isEmpty());
}
+void tst_QJSValue::toRegularExpression()
+{
+ QJSEngine eng;
+ {
+ QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/foo/"));
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
+ QVERIFY(!(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption));
+ }
+ {
+ QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/bar/gi"));
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
+ QVERIFY(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption);
+ }
+
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("[]")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("{}")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.globalObject()).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue()).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(123)).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(false)).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("null")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.toScriptValue(QVariant())).pattern().isEmpty());
+}
+
void tst_QJSValue::isArray_data()
{
newEngine();
@@ -1601,10 +1685,14 @@ void tst_QJSValue::getSetProperty()
QCOMPARE(object.property("baz").toNumber(), num.toNumber());
QJSValue strstr = QJSValue("bar");
+#ifdef QT_DEPRECATED
QCOMPARE(strstr.engine(), (QJSEngine *)nullptr);
+#endif
object.setProperty("foo", strstr);
QCOMPARE(object.property("foo").toString(), strstr.toString());
+#ifdef QT_DEPRECATED
QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
+#endif
QJSValue numnum = QJSValue(123.0);
object.setProperty("baz", numnum);
@@ -2255,8 +2343,8 @@ void tst_QJSValue::strictlyEquals()
{
QJSValue var1 = eng.toScriptValue(QVariant(QStringList() << "a"));
QJSValue var2 = eng.toScriptValue(QVariant(QStringList() << "a"));
- QVERIFY(var1.isArray());
- QVERIFY(var2.isArray());
+ QVERIFY(!var1.isArray());
+ QVERIFY(!var2.isArray());
QVERIFY(!var1.strictlyEquals(var2));
}
{
@@ -2294,7 +2382,7 @@ void tst_QJSValue::castToPointer()
QBrush *bp = qjsvalue_cast<QBrush*>(v);
QVERIFY(!bp);
- QJSValue v2 = eng.toScriptValue(qVariantFromValue(cp));
+ QJSValue v2 = eng.toScriptValue(QVariant::fromValue(cp));
QCOMPARE(qjsvalue_cast<QColor*>(v2), cp);
}
}
@@ -2496,15 +2584,18 @@ void tst_QJSValue::engineDeleted()
delete eng;
QVERIFY(v1.isUndefined());
- QVERIFY(!v1.engine());
QVERIFY(v2.isUndefined());
- QVERIFY(!v2.engine());
QVERIFY(v3.isUndefined());
- QVERIFY(!v3.engine());
QVERIFY(v4.isUndefined());
- QVERIFY(!v4.engine());
QVERIFY(v5.isString()); // was not bound to engine
+
+#ifdef QT_DEPRECATED
+ QVERIFY(!v1.engine());
+ QVERIFY(!v2.engine());
+ QVERIFY(!v3.engine());
+ QVERIFY(!v4.engine());
QVERIFY(!v5.engine());
+#endif
QVERIFY(v3.property("foo").isUndefined());
}
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
index ccbacb3acc..f704169d43 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
@@ -74,6 +74,7 @@ private slots:
void toQObject();
void toDateTime();
void toRegExp();
+ void toRegularExpression();
void isArray_data();
void isArray();
void isDate();
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 5448088ee5..db9bb52010 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -70,6 +70,7 @@ PRIVATETESTS += \
qqmltranslation \
qqmlimport \
qqmlobjectmodel \
+ qqmltablemodel \
qv4assembler \
qv4mm \
qv4identifiertable \
@@ -104,7 +105,3 @@ qtConfig(private_tests): \
qtNomakeTools( \
qmlplugindump \
)
-
-QtConfig(qml_tracing) {
- PRIVATETESTS += v4traced
-}
diff --git a/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml b/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml
new file mode 100644
index 0000000000..2128a54d81
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/parameterAdjustment.qml
@@ -0,0 +1,7 @@
+import QtQml 2.12
+
+QtObject {
+ signal testSignal(string a, int b, string c, bool d, bool e, real f, real g, bool h, int i, int j, string k, int l, string m, string n)
+ onTestSignal: {}
+ Component.onCompleted: testSignal("a", 1, "b", true, true, 0.1, 0.1, true, 1, 1, "a", 1, "a", "a")
+}
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
index 53b26ccfae..4daf1d35c3 100644
--- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -17,7 +17,8 @@ RESOURCES += \
data/jsmoduleimport.qml \
data/script.mjs \
data/module.mjs \
- data/utils.mjs
+ data/utils.mjs \
+ data/parameterAdjustment.qml
workerscripts_test.files = \
data/worker.js \
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 741989e732..4a1f5378a6 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -36,6 +36,7 @@
#include <QSysInfo>
#include <QLoggingCategory>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <qtranslator.h>
#include "../../shared/util.h"
@@ -72,6 +73,8 @@ private slots:
void reproducibleCache_data();
void reproducibleCache();
+
+ void parameterAdjustment();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -669,6 +672,14 @@ void tst_qmlcachegen::reproducibleCache()
QCOMPARE(contents1, contents2);
}
+void tst_qmlcachegen::parameterAdjustment()
+{
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/parameterAdjustment.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull()); // Doesn't crash
+}
+
QTEST_GUILESS_MAIN(tst_qmlcachegen)
#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmldiskcache/dummy_imports.qml b/tests/auto/qml/qmldiskcache/dummy_imports.qml
new file mode 100644
index 0000000000..b9a196e188
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++
+// code in tst_parserstress.cpp
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 70a5a73e0f..1f0115b926 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -30,10 +30,11 @@
#include <private/qv4compileddata_p.h>
#include <private/qv4compiler_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmlcomponent_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQmlFileSelector>
@@ -119,7 +120,8 @@ struct TestCompiler
{
closeMapping();
testFilePath = baseDirectory + QStringLiteral("/test.qml");
- cacheFilePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
+ cacheFilePath = QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(testFilePath));
mappedFile.setFileName(cacheFilePath);
}
@@ -186,8 +188,10 @@ struct TestCompiler
bool verify()
{
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
- return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), &lastErrorString);
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
+ = QV4::ExecutableCompilationUnit::create();
+ return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath),
+ QFileInfo(testFilePath).lastModified(), &lastErrorString);
}
void closeMapping()
@@ -264,8 +268,9 @@ void tst_qmldiskcache::loadLocalAsFallback()
f.write(reinterpret_cast<const char *>(&unit), sizeof(unit));
}
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
- bool loaded = unit->loadFromDisk(QUrl::fromLocalFile(testCompiler.testFilePath), QFileInfo(testCompiler.testFilePath).lastModified(),
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ bool loaded = unit->loadFromDisk(QUrl::fromLocalFile(testCompiler.testFilePath),
+ QFileInfo(testCompiler.testFilePath).lastModified(),
&testCompiler.lastErrorString);
QVERIFY2(loaded, qPrintable(testCompiler.lastErrorString));
QCOMPARE(unit->objectCount(), 1);
@@ -324,7 +329,10 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(2));
QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number));
- QCOMPARE(obj->bindingTable()->valueAsNumber(reinterpret_cast<const QV4::Value *>(testUnit->constants())), double(42));
+
+ QCOMPARE(reinterpret_cast<const QV4::Value *>(testUnit->constants())
+ [obj->bindingTable()->value.constantValueIndex].doubleValue(),
+ double(42));
QCOMPARE(quint32(testUnit->functionTableSize), quint32(1));
@@ -573,7 +581,8 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
- QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)));
+ QFile cacheFile(QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(testFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
@@ -588,7 +597,8 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 100);
- QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(selectedTestFilePath)));
+ QFile cacheFile(QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(selectedTestFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
}
@@ -636,10 +646,21 @@ void tst_qmldiskcache::localAliases()
}
}
+static QSet<QString> entrySet(const QDir &dir)
+{
+ const auto &list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
+ return QSet<QString>(list.cbegin(), list.cend());
+}
+
+static QSet<QString> entrySet(const QDir &dir, const QStringList &filters)
+{
+ const auto &list = dir.entryList(filters);
+ return QSet<QString>(list.cbegin(), list.cend());
+}
+
void tst_qmldiskcache::cacheResources()
{
- const QSet<QString> existingFiles =
- m_qmlCacheDirectory.entryList(QDir::Files | QDir::NoDotAndDotDot).toSet();
+ const QSet<QString> existingFiles = entrySet(m_qmlCacheDirectory);
QQmlEngine engine;
@@ -650,8 +671,7 @@ void tst_qmldiskcache::cacheResources()
QCOMPARE(obj->property("value").toInt(), 20);
}
- const QSet<QString> entries =
- m_qmlCacheDirectory.entryList(QDir::NoDotAndDotDot | QDir::Files).toSet().subtract(existingFiles);
+ const QSet<QString> entries = entrySet(m_qmlCacheDirectory).subtract(existingFiles);
QCOMPARE(entries.count(), 1);
QDateTime cacheFileTimeStamp;
@@ -680,8 +700,7 @@ void tst_qmldiskcache::cacheResources()
}
{
- const QSet<QString> entries =
- m_qmlCacheDirectory.entryList(QDir::NoDotAndDotDot | QDir::Files).toSet().subtract(existingFiles);
+ const QSet<QString> entries = entrySet(m_qmlCacheDirectory).subtract(existingFiles);
QCOMPARE(entries.count(), 1);
QCOMPARE(QFileInfo(m_qmlCacheDirectory.absoluteFilePath(*entries.cbegin())).lastModified().toMSecsSinceEpoch(),
@@ -738,7 +757,8 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes()
QVERIFY2(firstDependentTypeClassName.contains("QMLTYPE"), firstDependentTypeClassName.constData());
QVERIFY2(secondDependentTypeClassName.contains("QMLTYPE"), secondDependentTypeClassName.constData());
- const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
+ const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -816,7 +836,8 @@ void tst_qmldiskcache::singletonDependency()
QCOMPARE(obj->property("value").toInt(), 42);
}
- const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
+ const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -873,7 +894,8 @@ void tst_qmldiskcache::cppRegisteredSingletonDependency()
QCOMPARE(value.toInt(), 42);
}
- const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
+ const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath(
+ QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -902,8 +924,7 @@ void tst_qmldiskcache::cppRegisteredSingletonDependency()
void tst_qmldiskcache::cacheModuleScripts()
{
- const QSet<QString> existingFiles =
- m_qmlCacheDirectory.entryList(QDir::Files | QDir::NoDotAndDotDot).toSet();
+ const QSet<QString> existingFiles = entrySet(m_qmlCacheDirectory);
QQmlEngine engine;
@@ -924,8 +945,7 @@ void tst_qmldiskcache::cacheModuleScripts()
QVERIFY(!compilationUnit->backingFile.isNull());
}
- const QSet<QString> entries =
- m_qmlCacheDirectory.entryList(QStringList("*.mjsc")).toSet().subtract(existingFiles);
+ const QSet<QString> entries = entrySet(m_qmlCacheDirectory, QStringList("*.mjsc"));
QCOMPARE(entries.count(), 1);
diff --git a/tests/auto/qml/qmllint/data/CatchStatement.qml b/tests/auto/qml/qmllint/data/CatchStatement.qml
new file mode 100644
index 0000000000..e0f70fce7e
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/CatchStatement.qml
@@ -0,0 +1,8 @@
+import QtQml 2.12
+
+QtObject {
+ function f() {
+ try {} catch(err) {}
+ console.log(err);
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/FromRoot.qml b/tests/auto/qml/qmllint/data/FromRoot.qml
new file mode 100644
index 0000000000..021c09285e
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/FromRoot.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int unqualified: 42
+
+ Item {
+ Item {
+ x: unqualified // user defined property from root
+ }
+
+ QtObject {
+ property int check: x // existing property from root
+ }
+ }
+
+}
diff --git a/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml b/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml
new file mode 100644
index 0000000000..774a1cfc7c
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/IdFromOuterSpace.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ x: alien.x
+
+ Component.onCompleted: {
+ console.log(alien);
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/SignalHandler.qml b/tests/auto/qml/qmllint/data/SignalHandler.qml
new file mode 100644
index 0000000000..865277cedb
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/SignalHandler.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+MouseArea {
+ onDoubleClicked: {
+ console.log(mouse);
+ // do further things
+ }
+ onClicked: console.info(mouse)
+ onPositionChanged: {
+ console.log(mouse)
+ }
+ onPressAndHold: console.warn(mouse)
+}
diff --git a/tests/auto/qml/qmllint/data/WithStatement.qml b/tests/auto/qml/qmllint/data/WithStatement.qml
new file mode 100644
index 0000000000..5641f21eeb
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/WithStatement.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ Item {
+ id: target
+ property int test: 42
+ }
+ Component.onCompleted: {
+ with(target) {
+ console.log(test);
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml
new file mode 100644
index 0000000000..097baa6fcf
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/catchIdentifierNoWarning.qml
@@ -0,0 +1,7 @@
+import QtQml 2.12
+
+QtObject {
+ function f() {
+ try {} catch(err) {console.log(err);}
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/nonSpuriousParentWarning.qml b/tests/auto/qml/qmllint/data/nonSpuriousParentWarning.qml
new file mode 100644
index 0000000000..a59b736929
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/nonSpuriousParentWarning.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.12
+import QtQml 2.12
+
+Item {
+ QtObject {
+ property int x: parent.x
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/spuriousParentWarning.qml b/tests/auto/qml/qmllint/data/spuriousParentWarning.qml
new file mode 100644
index 0000000000..1323593031
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/spuriousParentWarning.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.12
+
+Item {
+ Unknown {
+ property int x: parent.x
+ }
+}
diff --git a/tests/auto/qml/qmllint/main.cpp b/tests/auto/qml/qmllint/main.cpp
deleted file mode 100644
index eedbd7c2f2..0000000000
--- a/tests/auto/qml/qmllint/main.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** 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/
-**
-** This file is part of the plugins 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 <QtTest/QtTest>
-#include <QProcess>
-#include <QString>
-
-class TestQmllint: public QObject
-{
- Q_OBJECT
-
-private Q_SLOTS:
- void initTestCase();
- void test();
- void test_data();
-private:
- QString m_qmllintPath;
-};
-
-void TestQmllint::initTestCase()
-{
- m_qmllintPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint");
-#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));
- }
-}
-
-void TestQmllint::test_data()
-{
- QTest::addColumn<QString>("filename");
- QTest::addColumn<bool>("isValid");
-
- // Valid files:
- QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true;
- QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true;
- QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true;
-
- // Invalid files:
- QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false;
- QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false;
-}
-
-void TestQmllint::test()
-{
- QFETCH(QString, filename);
- QFETCH(bool, isValid);
- filename = QStringLiteral("data/") + filename;
- QStringList args;
- args << QStringLiteral("--silent") << filename;
-
- bool success = QProcess::execute(m_qmllintPath, args) == 0;
- QCOMPARE(success, isValid);
-}
-
-QTEST_MAIN(TestQmllint)
-#include "main.moc"
diff --git a/tests/auto/qml/qmllint/qmllint.pro b/tests/auto/qml/qmllint/qmllint.pro
index b53a6f6877..95470b4085 100644
--- a/tests/auto/qml/qmllint/qmllint.pro
+++ b/tests/auto/qml/qmllint/qmllint.pro
@@ -1,6 +1,11 @@
-TEMPLATE = app
-TARGET = testqmllint
-INCLUDEPATH += .
+CONFIG += testcase
+TARGET = tst_qmllint
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmllint.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
-SOURCES += main.cpp
QT += testlib
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
new file mode 100644
index 0000000000..582f146dca
--- /dev/null
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** 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/
+**
+** This file is part of the plugins 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 <QtTest/QtTest>
+#include <QProcess>
+#include <QString>
+
+#include <util.h>
+
+class TestQmllint: public QQmlDataTest
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase() override;
+ void test();
+ void test_data();
+ void testUnqualified();
+ void testUnqualified_data();
+ void testUnqualifiedNoSpuriousParentWarning();
+ void catchIdentifierNoFalsePositive();
+private:
+ QString m_qmllintPath;
+};
+
+void TestQmllint::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ m_qmllintPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint");
+#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));
+ }
+}
+
+void TestQmllint::test_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<bool>("isValid");
+
+ // Valid files:
+ QTest::newRow("Simple_QML") << QStringLiteral("Simple.qml") << true;
+ QTest::newRow("QML_importing_JS") << QStringLiteral("importing_js.qml") << true;
+ QTest::newRow("QTBUG-45916_JS_with_pragma_and_import") << QStringLiteral("QTBUG-45916.js") << true;
+
+ // Invalid files:
+ QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") << false;
+ QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") << false;
+}
+
+void TestQmllint::testUnqualified()
+{
+ auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ QFETCH(QString, filename);
+ QFETCH(QString, warningMessage);
+ QFETCH(int, warningLine);
+ QFETCH(int, warningColumn);
+ QStringList args;
+ args << QStringLiteral("-U") << testFile(filename) << QStringLiteral("-I") << qmlImportDir;
+
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode());
+ QString output = process.readAllStandardError();
+ QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %d:%d", warningLine, warningColumn)));
+ 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
+ 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;
+ // access catch identifier outside catch block
+ QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21;
+}
+
+void TestQmllint::testUnqualifiedNoSpuriousParentWarning()
+{
+ auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ {
+ QString filename = testFile("spuriousParentWarning.qml");
+ QStringList args;
+ args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode() == 0);
+ }
+ {
+ QString filename = testFile("nonSpuriousParentWarning.qml");
+ QStringList args;
+ args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode());
+ }
+}
+
+void TestQmllint::catchIdentifierNoFalsePositive()
+{
+ auto qmlImportDir = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ QString filename = QLatin1String("catchIdentifierNoWarning.qml");
+ filename.prepend(QStringLiteral("data/"));
+ QStringList args;
+ args << QStringLiteral("-U") << filename << QStringLiteral("-I") << qmlImportDir;
+ QProcess process;
+ process.start(m_qmllintPath, args);
+ QVERIFY(process.waitForFinished());
+ QVERIFY(process.exitStatus() == QProcess::NormalExit);
+ QVERIFY(process.exitCode() == 0);
+}
+
+void TestQmllint::test()
+{
+ QFETCH(QString, filename);
+ QFETCH(bool, isValid);
+ QStringList args;
+ args << QStringLiteral("--silent") << testFile(filename);
+
+ bool success = QProcess::execute(m_qmllintPath, args) == 0;
+ QCOMPARE(success, isValid);
+}
+
+QTEST_MAIN(TestQmllint)
+#include "tst_qmllint.moc"
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
index d1e74aecef..e244369581 100644
--- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -64,6 +64,7 @@ tst_qmlmin::tst_qmlmin()
void tst_qmlmin::initTestCase()
{
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
qmlminPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlmin");
#ifdef Q_OS_WIN
qmlminPath += QLatin1String(".exe");
@@ -129,6 +130,10 @@ void tst_qmlmin::initTestCase()
invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js";
invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml";
invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.2.qml";
+ invalidFiles << "tests/auto/qml/qqmllanguage/data/fuzzed.3.qml";
+ // generatorFunction.qml is not invalid per se, but the minifier cannot handle yield statements
+ invalidFiles << "tests/auto/qml/qqmlecmascript/data/generatorFunction.qml";
+#endif
}
QStringList tst_qmlmin::findFiles(const QDir &d)
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/Derived.qml b/tests/auto/qml/qmlplugindump/data/dumper/Imports/Derived.qml
new file mode 100644
index 0000000000..2f0ac401d7
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/Derived.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import dumper.Imports 1.0
+
+Imports {
+ property int something: 2
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro
index d20ea967ea..b4bd9baf5b 100644
--- a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro
@@ -17,7 +17,7 @@ HEADERS += \
imports.h
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
- cp.files = qmldir plugins.qmltypes CompositeImports.qml
+ cp.files = qmldir plugins.qmltypes CompositeImports.qml Derived.qml
cp.path = $$OUT_PWD
COPIES += cp
}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes
index 937dd60a9e..fb13928ba0 100644
--- a/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes
@@ -14,4 +14,14 @@ Module {
exports: ["dumper.Imports/Imports 1.0"]
exportMetaObjectRevisions: [0]
}
+ Component {
+ prototype: "Imports"
+ name: "dumper.Imports/Derived 1.0"
+ exports: ["dumper.Imports/Derived 1.0"]
+ exportMetaObjectRevisions: [0]
+ isComposite: true
+ isCreatable: false
+ isSingleton: true
+ Property { name: "something"; type: "int" }
+ }
}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir
index c9058a7f95..f84fca1d75 100644
--- a/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir
@@ -1,3 +1,4 @@
module dumper.Imports
plugin Imports
CompositeImports 1.0 CompositeImports.qml
+singleton Derived 1.0 Derived.qml
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index a9c28a0911..0f5eea8b95 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -52,6 +52,7 @@ private slots:
void removeObjectsWhenDestroyed();
void loadTranslation_data();
void loadTranslation();
+ void setInitialProperties();
private:
QString buildDir;
@@ -96,6 +97,9 @@ void tst_qqmlapplicationengine::basicLoading()
// will break.
void tst_qqmlapplicationengine::testNonResolvedPath()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Android stores QML files in resources, and the path to a resource cannot be relative in this case");
+#endif
{
// NOTE NOTE NOTE! Missing testFileUrl is *WANTED* here! We want a
// non-resolved URL.
@@ -117,6 +121,9 @@ void tst_qqmlapplicationengine::testNonResolvedPath()
void tst_qqmlapplicationengine::application_data()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Cannot launch external process on Android");
+#endif
QTest::addColumn<QByteArray>("qmlFile");
QTest::addColumn<QByteArray>("expectedStdErr");
@@ -269,6 +276,23 @@ void tst_qqmlapplicationengine::loadTranslation()
QCOMPARE(rootObject->property("translation").toString(), translation);
}
+void tst_qqmlapplicationengine::setInitialProperties()
+{
+ QQmlApplicationEngine test {};
+ {
+ test.setInitialProperties(QVariantMap{{"success", false}});
+ test.load(testFileUrl("basicTest.qml"));
+ QVERIFY(!test.rootObjects().empty());
+ QCOMPARE(test.rootObjects().first()->property("success").toBool(), false);
+ }
+ {
+ test.setInitialProperties({{"success", true}});
+ test.load(testFileUrl("basicTest.qml"));
+ QCOMPARE(test.rootObjects().size(), 2);
+ QCOMPARE(test.rootObjects().at(1)->property("success").toBool(), true);
+ }
+}
+
QTEST_MAIN(tst_qqmlapplicationengine)
#include "tst_qqmlapplicationengine.moc"
diff --git a/tests/auto/qml/qqmlbinding/data/MyComponent.qml b/tests/auto/qml/qqmlbinding/data/MyComponent.qml
new file mode 100644
index 0000000000..5892539a5d
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/MyComponent.qml
@@ -0,0 +1,2 @@
+import QtQuick 2.3
+QtObject { property real p: 0 }
diff --git a/tests/auto/qml/qqmlbinding/data/bindToQMLComponent.qml b/tests/auto/qml/qqmlbinding/data/bindToQMLComponent.qml
new file mode 100644
index 0000000000..471db9023b
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/bindToQMLComponent.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property MyComponent myProperty
+ Binding {
+ target: root
+ property: "myProperty"
+ value: myObject
+ }
+ MyComponent { id: myObject }
+}
diff --git a/tests/auto/qml/qqmlbinding/data/nanPropertyToInt.qml b/tests/auto/qml/qqmlbinding/data/nanPropertyToInt.qml
new file mode 100644
index 0000000000..366dbf0464
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/nanPropertyToInt.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.11
+
+Item {
+ visible: true
+ width: 320
+ height: 200
+ property int val: other.val
+
+ Rectangle {
+ id: other
+ anchors.fill: parent;
+ property int val: undefined / 2
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/data/noUnexpectedStringConversion.qml b/tests/auto/qml/qqmlbinding/data/noUnexpectedStringConversion.qml
new file mode 100644
index 0000000000..d0f30c5da5
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/noUnexpectedStringConversion.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.12
+import QtQuick.Window 2.12
+
+Window {
+visible: true
+width: 640
+height: 480
+title: qsTr("Hello World")
+
+ Rectangle {
+ id: colorRect
+ objectName: "colorRect"
+ anchors.fill: parent
+ Text {
+ objectName: "colorLabel"
+ id: colorLabel
+ }
+ }
+
+ Binding {
+ target: colorLabel
+ property: "text"
+ value: "red"
+ }
+ Binding {
+ target: colorRect
+ property: "color"
+ value: "red"
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml
new file mode 100644
index 0000000000..b42f975fe0
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQml 2.14
+
+Rectangle {
+ height: 400
+ width: 400
+
+ Rectangle {
+ property bool when: true
+
+ id: myItem
+ objectName: "myItem"
+ height: 300
+ width: 200
+ }
+
+ property var boundValue: 100
+
+ Binding {
+ restoreMode: Binding.RestoreValue
+ objectName: "theBinding"
+ target: myItem
+ property: "height"
+ when: myItem.when
+ value: boundValue
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml
new file mode 100644
index 0000000000..1f63457ab6
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQml 2.14
+
+Rectangle {
+ height: 400
+ width: 400
+
+ Rectangle {
+ property bool when: true
+
+ id: myItem
+ objectName: "myItem"
+ height: 300
+ width: 200
+ property var foo: 42
+ }
+
+ property var boundValue: 13
+
+ Binding {
+ restoreMode: Binding.RestoreBindingOrValue
+ objectName: "theBinding"
+ target: myItem
+ property: "foo"
+ when: myItem.when
+ value: boundValue
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml
new file mode 100644
index 0000000000..f34c3b40cf
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQml 2.14
+
+Rectangle {
+ height: 400
+ width: 400
+
+ Rectangle {
+ property bool when: true
+
+ id: myItem
+ objectName: "myItem"
+ height: 300
+ width: 200
+ property var foo: original
+ property bool fooCheck: foo === original && foo.bar() === 42
+ }
+
+ property var original: ({ bar: function() { return 42 } })
+
+ property var boundValue: 13
+
+ Binding {
+ restoreMode: Binding.RestoreBinding
+ objectName: "theBinding"
+ target: myItem
+ property: "foo"
+ when: myItem.when
+ value: boundValue
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
index 34cf21024d..2610402455 100644
--- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
+++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
@@ -42,6 +42,9 @@ private slots:
void binding();
void whenAfterValue();
void restoreBinding();
+ void restoreBindingValue();
+ void restoreBindingVarValue();
+ void restoreBindingJSValue();
void restoreBindingWithLoop();
void restoreBindingWithoutCrash();
void deletedObject();
@@ -51,6 +54,9 @@ private slots:
void disabledOnReadonlyProperty();
void delayed();
void bindingOverwriting();
+ void bindToQmlComponent();
+ void bindingDoesNoWeirdConversion();
+ void bindNaNToInt();
private:
QQmlEngine engine;
@@ -64,7 +70,7 @@ void tst_qqmlbinding::binding()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("test-binding.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect { qobject_cast<QQuickRectangle*>(c.create()) };
QVERIFY(rect != nullptr);
QQmlBind *binding3 = qobject_cast<QQmlBind*>(rect->findChild<QQmlBind*>("binding3"));
@@ -81,18 +87,16 @@ void tst_qqmlbinding::binding()
QQmlBind *binding = qobject_cast<QQmlBind*>(rect->findChild<QQmlBind*>("binding1"));
QVERIFY(binding != nullptr);
- QCOMPARE(binding->object(), qobject_cast<QObject*>(rect));
+ QCOMPARE(binding->object(), qobject_cast<QObject*>(rect.get()));
QCOMPARE(binding->property(), QLatin1String("text"));
QCOMPARE(binding->value().toString(), QLatin1String("Hello"));
-
- delete rect;
}
void tst_qqmlbinding::whenAfterValue()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("test-binding2.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect {qobject_cast<QQuickRectangle*>(c.create())};
QVERIFY(rect != nullptr);
QCOMPARE(rect->color(), QColor("yellow"));
@@ -100,15 +104,13 @@ void tst_qqmlbinding::whenAfterValue()
rect->setProperty("changeColor", true);
QCOMPARE(rect->color(), QColor("red"));
-
- delete rect;
}
void tst_qqmlbinding::restoreBinding()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBinding.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect { qobject_cast<QQuickRectangle*>(c.create()) };
QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
@@ -130,15 +132,85 @@ void tst_qqmlbinding::restoreBinding()
//original binding restored
myItem->setY(49);
QCOMPARE(myItem->x(), qreal(100-49));
+}
+
+void tst_qqmlbinding::restoreBindingValue()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("restoreBinding2.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));
+ QVERIFY(!rect.isNull());
+
+ auto myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
+ QVERIFY(myItem != nullptr);
+
+ QCOMPARE(myItem->height(), 100);
+ myItem->setProperty("when", QVariant(false));
+ QCOMPARE(myItem->height(), 300); // make sure the original value was restored
+
+ myItem->setProperty("when", QVariant(true));
+ QCOMPARE(myItem->height(), 100); // make sure the value specified in Binding is set
+ rect->setProperty("boundValue", 200);
+ QCOMPARE(myItem->height(), 200); // make sure the changed binding value is set
+ myItem->setProperty("when", QVariant(false));
+ // make sure that the original value is back, not e.g. the value from before the
+ // change (i.e. 100)
+ QCOMPARE(myItem->height(), 300);
+}
+
+void tst_qqmlbinding::restoreBindingVarValue()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("restoreBinding3.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));
+ QVERIFY(!rect.isNull());
+
+ auto myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
+ QVERIFY(myItem != nullptr);
+
+ QCOMPARE(myItem->property("foo"), 13);
+ myItem->setProperty("when", QVariant(false));
+ QCOMPARE(myItem->property("foo"), 42); // make sure the original value was restored
+
+ myItem->setProperty("when", QVariant(true));
+ QCOMPARE(myItem->property("foo"), 13); // make sure the value specified in Binding is set
+ rect->setProperty("boundValue", 31337);
+ QCOMPARE(myItem->property("foo"), 31337); // make sure the changed binding value is set
+ myItem->setProperty("when", QVariant(false));
+ // make sure that the original value is back, not e.g. the value from before the
+ // change (i.e. 100)
+ QCOMPARE(myItem->property("foo"), 42);
+}
+
+void tst_qqmlbinding::restoreBindingJSValue()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("restoreBinding4.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));
+ QVERIFY(!rect.isNull());
+
+ auto myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
+ QVERIFY(myItem != nullptr);
+
+ QCOMPARE(myItem->property("fooCheck"), false);
+ myItem->setProperty("when", QVariant(false));
+ QCOMPARE(myItem->property("fooCheck"), true); // make sure the original value was restored
+
+ myItem->setProperty("when", QVariant(true));
+ QCOMPARE(myItem->property("fooCheck"), false); // make sure the value specified in Binding is set
+ rect->setProperty("boundValue", 31337);
+ QCOMPARE(myItem->property("fooCheck"), false); // make sure the changed binding value is set
+ myItem->setProperty("when", QVariant(false));
+ // make sure that the original value is back, not e.g. the value from before the change
+ QCOMPARE(myItem->property("fooCheck"), true);
- delete rect;
}
void tst_qqmlbinding::restoreBindingWithLoop()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBindingWithLoop.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect {qobject_cast<QQuickRectangle*>(c.create())};
QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
@@ -166,15 +238,13 @@ void tst_qqmlbinding::restoreBindingWithLoop()
myItem->setY(49);
QCOMPARE(myItem->x(), qreal(49 + 100));
-
- delete rect;
}
void tst_qqmlbinding::restoreBindingWithoutCrash()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBindingWithoutCrash.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect {qobject_cast<QQuickRectangle*>(c.create())};
QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
@@ -205,8 +275,6 @@ void tst_qqmlbinding::restoreBindingWithoutCrash()
//original binding restored
myItem->setY(49);
QCOMPARE(myItem->x(), qreal(100-49));
-
- delete rect;
}
//QTBUG-20692
@@ -214,15 +282,13 @@ void tst_qqmlbinding::deletedObject()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("deletedObject.qml"));
- QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
+ QScopedPointer<QQuickRectangle> rect {qobject_cast<QQuickRectangle*>(c.create())};
QVERIFY(rect != nullptr);
QGuiApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
//don't crash
rect->setProperty("activateBinding", true);
-
- delete rect;
}
void tst_qqmlbinding::warningOnUnknownProperty()
@@ -231,9 +297,8 @@ void tst_qqmlbinding::warningOnUnknownProperty()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("unknownProperty.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item { qobject_cast<QQuickItem *>(c.create()) };
QVERIFY(item);
- delete item;
QCOMPARE(messageHandler.messages().count(), 1);
@@ -247,9 +312,8 @@ void tst_qqmlbinding::warningOnReadOnlyProperty()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("readonlyProperty.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item { qobject_cast<QQuickItem *>(c.create()) };
QVERIFY(item);
- delete item;
QCOMPARE(messageHandler.messages().count(), 1);
@@ -263,9 +327,8 @@ void tst_qqmlbinding::disabledOnUnknownProperty()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("disabledUnknown.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item { qobject_cast<QQuickItem *>(c.create()) };
QVERIFY(item);
- delete item;
QCOMPARE(messageHandler.messages().count(), 0);
}
@@ -276,10 +339,8 @@ void tst_qqmlbinding::disabledOnReadonlyProperty()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("disabledReadonly.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item { qobject_cast<QQuickItem *>(c.create()) };
QVERIFY(item);
- delete item;
-
QCOMPARE(messageHandler.messages().count(), 0);
}
@@ -287,21 +348,19 @@ void tst_qqmlbinding::delayed()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("delayed.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item {qobject_cast<QQuickItem*>(c.create())};
QVERIFY(item != nullptr);
// update on creation
QCOMPARE(item->property("changeCount").toInt(), 1);
- QMetaObject::invokeMethod(item, "updateText");
+ QMetaObject::invokeMethod(item.get(), "updateText");
// doesn't update immediately
QCOMPARE(item->property("changeCount").toInt(), 1);
QCoreApplication::processEvents();
// only updates once (non-delayed would update twice)
QCOMPARE(item->property("changeCount").toInt(), 2);
-
- delete item;
}
void tst_qqmlbinding::bindingOverwriting()
@@ -311,14 +370,45 @@ void tst_qqmlbinding::bindingOverwriting()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("bindingOverwriting.qml"));
- QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
+ QScopedPointer<QQuickItem> item {qobject_cast<QQuickItem*>(c.create())};
QVERIFY(item);
- delete item;
QLoggingCategory::setFilterRules(QString());
QCOMPARE(messageHandler.messages().count(), 2);
}
+void tst_qqmlbinding::bindToQmlComponent()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("bindToQMLComponent.qml"));
+ QVERIFY(c.create());
+}
+
+// QTBUG-78943
+void tst_qqmlbinding::bindingDoesNoWeirdConversion()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("noUnexpectedStringConversion.qml"));
+ QScopedPointer<QObject> o {c.create()};
+ QVERIFY(o);
+ QObject *colorRect = o->findChild<QObject*>("colorRect");
+ QVERIFY(colorRect);
+ QCOMPARE(qvariant_cast<QColor>(colorRect->property("color")), QColorConstants::Red);
+ QObject *colorLabel = o->findChild<QObject*>("colorLabel");
+ QCOMPARE(colorLabel->property("text").toString(), QLatin1String("red"));
+ QVERIFY(colorLabel);
+}
+
+//QTBUG-72442
+void tst_qqmlbinding::bindNaNToInt()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("nanPropertyToInt.qml"));
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create()));
+
+ QVERIFY(item != nullptr);
+ QCOMPARE(item->property("val").toInt(), 0);
+}
QTEST_MAIN(tst_qqmlbinding)
#include "tst_qqmlbinding.moc"
diff --git a/tests/auto/qml/qqmlchangeset/qqmlchangeset.pro b/tests/auto/qml/qqmlchangeset/qqmlchangeset.pro
index 9f854f1fa2..cdac5c0ff9 100644
--- a/tests/auto/qml/qqmlchangeset/qqmlchangeset.pro
+++ b/tests/auto/qml/qqmlchangeset/qqmlchangeset.pro
@@ -4,4 +4,4 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmlchangeset.cpp
-QT += core-private gui-private qml-private testlib
+QT += core-private gui-private qml-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml
new file mode 100644
index 0000000000..0541c9b104
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/allJSONTypes.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.14
+
+Item {
+ property int i
+ property bool b
+ property double d
+ property string s
+ property var nothing
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml
new file mode 100644
index 0000000000..acf08e94d2
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/variantBasedInitialization.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.14
+
+Item {
+ property int i
+ property bool b
+ property double d
+ property string s
+ property var nothing
+ property url myurl
+ property color c
+ property font myfont
+ property date mydate
+ property point mypoint
+ property size mysize
+ property rect myrect
+ property matrix4x4 matrix
+ property quaternion quat
+ property vector2d vec2
+ property vector3d vec3
+ property vector4d vec4
+}
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index a872cece96..1d2fa42b75 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -35,7 +35,6 @@
#include <QtQuick>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
-#include <private/qv8engine_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qv4qmlcontext_p.h>
#include <private/qv4scopedvalue_p.h>
@@ -122,6 +121,7 @@ private slots:
void relativeUrl_data();
void relativeUrl();
void setDataNoEngineNoSegfault();
+ void testSetInitialProperties();
private:
QQmlEngine engine;
@@ -222,12 +222,12 @@ void tst_qqmlcomponent::qmlCreateObjectAutoParent()
QVERIFY(window_item);
QVERIFY(window_window);
- QCOMPARE(qtobject_item->metaObject()->className(), "QQuickItem");
- QCOMPARE(qtobject_window->metaObject()->className(), "QQuickWindow");
- QCOMPARE(item_item->metaObject()->className(), "QQuickItem");
- QCOMPARE(item_window->metaObject()->className(), "QQuickWindow");
- QCOMPARE(window_item->metaObject()->className(), "QQuickItem");
- QCOMPARE(window_window->metaObject()->className(), "QQuickWindow");
+ QVERIFY(QByteArray(qtobject_item->metaObject()->className()).startsWith("QQuickItem"));
+ QVERIFY(QByteArray(qtobject_window->metaObject()->className()).startsWith("QQuickWindow"));
+ QVERIFY(QByteArray(item_item->metaObject()->className()).startsWith("QQuickItem"));
+ QVERIFY(QByteArray(item_window->metaObject()->className()).startsWith("QQuickWindow"));
+ QVERIFY(QByteArray(window_item->metaObject()->className()).startsWith("QQuickItem"));
+ QVERIFY(QByteArray(window_window->metaObject()->className()).startsWith("QQuickWindow"));
QCOMPARE(qtobject_qtobject->parent(), qtobjectParent);
QCOMPARE(qtobject_item->parent(), qtobjectParent);
@@ -637,9 +637,11 @@ void tst_qqmlcomponent::relativeUrl_data()
{
QTest::addColumn<QUrl>("url");
+#if !defined(Q_OS_ANDROID)
QTest::addRow("fromLocalFile") << QUrl::fromLocalFile("data/QtObjectComponent.qml");
QTest::addRow("fromLocalFileHash") << QUrl::fromLocalFile("data/QtObjectComponent#2.qml");
QTest::addRow("constructor") << QUrl("data/QtObjectComponent.qml");
+#endif
QTest::addRow("absolute") << QUrl::fromLocalFile(QFINDTESTDATA("data/QtObjectComponent.qml"));
QTest::addRow("qrc") << QUrl("qrc:/data/QtObjectComponent.qml");
}
@@ -666,6 +668,101 @@ void tst_qqmlcomponent::setDataNoEngineNoSegfault()
QVERIFY(!c);
}
+void tst_qqmlcomponent::testSetInitialProperties()
+{
+ QQmlEngine eng;
+ {
+ // JSON based initialization
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("allJSONTypes.qml"));
+ QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
+ QVERIFY(obj);
+ comp.setInitialProperties(obj.get(), QVariantMap {
+ {QLatin1String("i"), 42},
+ {QLatin1String("b"), true},
+ {QLatin1String("d"), 3.1416},
+ {QLatin1String("s"), QLatin1String("hello world")},
+ {QLatin1String("nothing"), QVariant::fromValue(nullptr)}
+ });
+ comp.completeCreate();
+ if (!comp.errors().empty())
+ qDebug() << comp.errorString() << comp.errors();
+ QVERIFY(comp.errors().empty());
+ QCOMPARE(obj->property("i"), 42);
+ QCOMPARE(obj->property("b"), true);
+ QCOMPARE(obj->property("d"), 3.1416);
+ QCOMPARE(obj->property("s"), QLatin1String("hello world"));
+ QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr));
+ }
+ {
+ // QVariant
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("variantBasedInitialization.qml"));
+ QScopedPointer<QObject> obj { comp.beginCreate(eng.rootContext()) };
+ QVERIFY(obj);
+ QUrl myurl = comp.url();
+ QFont myfont;
+ QDateTime mydate = QDateTime::currentDateTime();
+ QPoint mypoint {1,2};
+ QSizeF mysize {0.5, 0.3};
+ QMatrix4x4 matrix {};
+ QQuaternion quat {5.0f, 0.3f, 0.2f, 0.1f};
+ QVector2D vec2 {2.0f, 3.1f};
+ QVector3D vec3 {1.0f, 2.0, 3.0f};
+ QVector4D vec4 {1.0f, 2.0f, 3.0f, 4.0f};
+#define ASJSON(NAME) {QLatin1String(#NAME), NAME}
+ comp.setInitialProperties(obj.get(), QVariantMap {
+ {QLatin1String("i"), 42},
+ {QLatin1String("b"), true},
+ {QLatin1String("d"), 3.1416},
+ {QLatin1String("s"), QLatin1String("hello world")},
+ {QLatin1String("nothing"), QVariant::fromValue( nullptr)},
+ ASJSON(myurl),
+ ASJSON(myfont),
+ ASJSON(mydate),
+ ASJSON(mypoint),
+ ASJSON(mysize),
+ ASJSON(matrix),
+ ASJSON(quat),
+ ASJSON(vec2), ASJSON(vec3), ASJSON(vec4)
+ });
+#undef ASJSON
+ comp.completeCreate();
+ if (!comp.errors().empty())
+ qDebug() << comp.errorString() << comp.errors();
+ QVERIFY(comp.errors().empty());
+ QCOMPARE(obj->property("i"), 42);
+ QCOMPARE(obj->property("b"), true);
+ QCOMPARE(obj->property("d"), 3.1416);
+ QCOMPARE(obj->property("s"), QLatin1String("hello world"));
+ QCOMPARE(obj->property("nothing"), QVariant::fromValue(nullptr));
+#define COMPARE(NAME) QCOMPARE(obj->property(#NAME), NAME)
+ COMPARE(myurl);
+ COMPARE(myfont);
+ COMPARE(mydate);
+ COMPARE(mypoint);
+ COMPARE(mysize);
+ COMPARE(matrix);
+ COMPARE(quat);
+ COMPARE(vec2);
+ COMPARE(vec3);
+ COMPARE(vec4);
+#undef COMPARE
+
+ }
+ {
+ // createWithInitialProperties: setting a nonexistent property
+ QQmlComponent comp(&eng);
+ comp.loadUrl(testFileUrl("allJSONTypes.qml"));
+ QScopedPointer<QObject> obj {
+ comp.createWithInitialProperties(QVariantMap { {"notThePropertiesYoureLookingFor", 42} })
+ };
+ qDebug() << comp.errorString();
+ QVERIFY(obj);
+ QVERIFY(comp.errorString().contains("Could not set property notThePropertiesYoureLookingFor"));
+ }
+}
+
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
diff --git a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml
index 462a9577ff..462a9577ff 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-no-signal-name.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml
index 154c309c9c..154c309c9c 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-targetchange.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-targetchange.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml
index 0780dd1509..0780dd1509 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-ignored.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-ignored.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml
index 3da3e0f5d1..3da3e0f5d1 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-notarget.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-notarget.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml
index 2c55215579..2c55215579 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals-parent.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals-parent.qml
diff --git a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml
index a351016b4a..a351016b4a 100644
--- a/tests/auto/qml/qqmlconnections/data/connection-unknownsignals.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/connection-unknownsignals.qml
diff --git a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml
index 1a823f87f6..1a823f87f6 100644
--- a/tests/auto/qml/qqmlconnections/data/disabled-at-start.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/disabled-at-start.qml
diff --git a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml
index 80e459966b..80e459966b 100644
--- a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/override-proxy-type.qml
diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml
index 1d0b557069..1d0b557069 100644
--- a/tests/auto/qml/qqmlconnections/data/rewriteError-global.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-global.qml
diff --git a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml
index a4849e994b..a4849e994b 100644
--- a/tests/auto/qml/qqmlconnections/data/rewriteError-unnamed.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/rewriteError-unnamed.qml
diff --git a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml
index 7de488c2dd..7de488c2dd 100644
--- a/tests/auto/qml/qqmlconnections/data/singletontype-target.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/singletontype-target.qml
diff --git a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml
index d5aa0f102a..d5aa0f102a 100644
--- a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection-implicit.qml
diff --git a/tests/auto/qml/qqmlconnections/data/test-connection.qml b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml
index f44cbc047f..f44cbc047f 100644
--- a/tests/auto/qml/qqmlconnections/data/test-connection.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/test-connection.qml
diff --git a/tests/auto/qml/qqmlconnections/data/trimming.qml b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml
index 4c37eb22af..4c37eb22af 100644
--- a/tests/auto/qml/qqmlconnections/data/trimming.qml
+++ b/tests/auto/qml/qqmlconnections/data/bindings/trimming.qml
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml
new file mode 100644
index 0000000000..04cc36b3c5
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-no-signal-name.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.4
+
+Item {
+ id: blaBlaBla
+ function hint() {
+ }
+
+ Connections {
+ //target: blaBlaBla
+ // function onHint() { hint() };
+ on: true
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml
new file mode 100644
index 0000000000..692194e837
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-targetchange.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Item {
+ Component {
+ id: item1
+ Item {
+ objectName: "item1"
+ }
+ }
+ Component {
+ id: item2
+ Item {
+ objectName: "item2"
+ }
+ }
+ Loader {
+ id: loader
+ sourceComponent: item1
+ }
+ Connections {
+ objectName: "connections"
+ target: loader.item
+ function onWidthChanged() { loader.sourceComponent = item2 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml
new file mode 100644
index 0000000000..f70d8cdb15
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-ignored.qml
@@ -0,0 +1,17 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property Connections c1: Connections {
+ target: root;
+ function onNotFooBar1() {}
+ ignoreUnknownSignals: true
+ }
+
+ property Connections c2: Connections {
+ objectName: "connections"
+ function onNotFooBar2() {}
+ ignoreUnknownSignals: true
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml
new file mode 100644
index 0000000000..7658728dd9
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-notarget.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property Connections c1: Connections {
+ objectName: "connections"
+ target: null
+ function onNotFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml
new file mode 100644
index 0000000000..ece76b0cf7
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals-parent.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ property Connections c1: Connections {
+ objectName: "connections"
+ function onFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml
new file mode 100644
index 0000000000..a198a724d0
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/connection-unknownsignals.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+
+QtObject {
+ id: screen
+
+ property Connections c1: Connections {
+ objectName: "connections"
+ target: screen
+ function onFooBar() {}
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml
new file mode 100644
index 0000000000..981437fe8c
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/disabled-at-start.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.9
+
+Item {
+ id: root
+
+ property bool tested: false
+ signal testMe()
+
+ Connections {
+ target: root
+ enabled: false
+ function onTestMe() { root.tested = true; }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml
new file mode 100644
index 0000000000..b83f0baa11
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/override-proxy-type.qml
@@ -0,0 +1,13 @@
+import QtQml 2.12
+import test.proxy 1.0
+
+Proxy {
+ property int testEnum: 0;
+ id: proxy
+ property Connections connections: Connections {
+ target: proxy
+ function onSomeSignal() { testEnum = Proxy.EnumValue }
+ }
+
+ Component.onCompleted: someSignal()
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml
new file mode 100644
index 0000000000..de3154c431
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-global.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+import Test 1.0
+
+TestObject {
+ property QtObject connection: Connections {
+ function onSignalWithGlobalName() { ran = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml
new file mode 100644
index 0000000000..fa1d1b17d7
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/rewriteError-unnamed.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Test 1.0
+
+TestObject {
+ property QtObject connection: Connections {
+ function onUnnamedArgumentSignal() { ran = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml
new file mode 100644
index 0000000000..935b610351
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/singletontype-target.qml
@@ -0,0 +1,22 @@
+import QtQml 2.0
+import MyTestSingletonType 1.0 as MyTestSingletonType
+
+QtObject {
+ id: rootObject
+ objectName: "rootObject"
+ property int newIntPropValue: 12
+
+ property int moduleIntPropChangedCount: 0
+ property int moduleOtherSignalCount: 0
+
+ function setModuleIntProp() {
+ MyTestSingletonType.Api.intProp = newIntPropValue;
+ newIntPropValue = newIntPropValue + 1;
+ }
+
+ property Connections c: Connections {
+ target: MyTestSingletonType.Api
+ function onIntPropChanged() { moduleIntPropChangedCount = moduleIntPropChangedCount + 1 }
+ function onOtherSignal() { moduleOtherSignalCount = moduleOtherSignalCount + 1 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml
new file mode 100644
index 0000000000..2ed5278636
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection-implicit.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ width: 50
+
+ property bool tested: false
+
+ Connections { function onWidthChanged() { tested = true } }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml
new file mode 100644
index 0000000000..c706797ea4
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/test-connection.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ id: screen; width: 50
+
+ property bool tested: false
+ signal testMe
+
+ Connections {
+ objectName: "connections"
+ target: screen;
+ function onWidthChanged() { screen.tested = true }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/data/functions/trimming.qml b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml
new file mode 100644
index 0000000000..7dfd673539
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/functions/trimming.qml
@@ -0,0 +1,13 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property string tested
+ signal testMe(int param1, string param2)
+
+ property Connections c: Connections {
+ target: root
+ function onTestMe(param1, param2) { root.tested = param2 + param1 }
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index dc29363fcf..07af519a3d 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -42,29 +42,57 @@ public:
private slots:
void defaultValues();
void properties();
+
+ void connection_data() { prefixes(); }
void connection();
+
+ void trimming_data() { prefixes(); }
void trimming();
+
+ void targetChanged_data() { prefixes(); };
void targetChanged();
+
void unknownSignals_data();
void unknownSignals();
+
void errors_data();
void errors();
+
+ void rewriteErrors_data() { prefixes(); }
void rewriteErrors();
+
+ void singletonTypeTarget_data() { prefixes(); }
void singletonTypeTarget();
+
+ void enableDisable_QTBUG_36350_data() { prefixes(); }
void enableDisable_QTBUG_36350();
+
+ void disabledAtStart_data() { prefixes(); }
void disabledAtStart();
+
+ void clearImplicitTarget_data() { prefixes(); }
void clearImplicitTarget();
void onWithoutASignal();
+
+ void noAcceleratedGlobalLookup_data() { prefixes(); }
void noAcceleratedGlobalLookup();
private:
QQmlEngine engine;
+ void prefixes();
};
tst_qqmlconnections::tst_qqmlconnections()
{
}
+void tst_qqmlconnections::prefixes()
+{
+ QTest::addColumn<QString>("prefix");
+ QTest::newRow("functions") << QString("functions");
+ QTest::newRow("bindings") << QString("bindings");
+}
+
void tst_qqmlconnections::defaultValues()
{
QQmlEngine engine;
@@ -93,8 +121,9 @@ void tst_qqmlconnections::properties()
void tst_qqmlconnections::connection()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -110,8 +139,9 @@ void tst_qqmlconnections::connection()
void tst_qqmlconnections::trimming()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("trimming.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/trimming.qml"));
QObject *object = c.create();
QVERIFY(object != nullptr);
@@ -131,8 +161,9 @@ void tst_qqmlconnections::trimming()
// Confirm that target can be changed by one of our signal handlers
void tst_qqmlconnections::targetChanged()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("connection-targetchange.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/connection-targetchange.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -158,10 +189,15 @@ void tst_qqmlconnections::unknownSignals_data()
QTest::addColumn<QString>("file");
QTest::addColumn<QString>("error");
- QTest::newRow("basic") << "connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
- QTest::newRow("parent") << "connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
- QTest::newRow("ignored") << "connection-unknownsignals-ignored.qml" << ""; // should be NO error
- QTest::newRow("notarget") << "connection-unknownsignals-notarget.qml" << ""; // should be NO error
+ QTest::newRow("functions/basic") << "functions/connection-unknownsignals.qml" << ":6:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.";
+ QTest::newRow("functions/parent") << "functions/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Detected function \"onFooBar\" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.";
+ QTest::newRow("functions/ignored") << "functions/connection-unknownsignals-ignored.qml" << ""; // should be NO error
+ QTest::newRow("functions/notarget") << "functions/connection-unknownsignals-notarget.qml" << ""; // should be NO error
+
+ QTest::newRow("bindings/basic") << "bindings/connection-unknownsignals.qml" << ":6:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
+ QTest::newRow("bindings/parent") << "bindings/connection-unknownsignals-parent.qml" << ":4:30: QML Connections: Cannot assign to non-existent property \"onFooBar\"";
+ QTest::newRow("bindings/ignored") << "bindings/connection-unknownsignals-ignored.qml" << ""; // should be NO error
+ QTest::newRow("bindings/notarget") << "bindings/connection-unknownsignals-notarget.qml" << ""; // should be NO error
}
void tst_qqmlconnections::unknownSignals()
@@ -239,10 +275,11 @@ private:
void tst_qqmlconnections::rewriteErrors()
{
+ QFETCH(QString, prefix);
qmlRegisterType<TestObject>("Test", 1, 0, "TestObject");
{
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("rewriteError-unnamed.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-unnamed.qml"));
QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != nullptr);
@@ -254,7 +291,7 @@ void tst_qqmlconnections::rewriteErrors()
{
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("rewriteError-global.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/rewriteError-global.qml"));
QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1());
TestObject *obj = qobject_cast<TestObject*>(c.create());
QVERIFY(obj != nullptr);
@@ -305,8 +342,9 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
// QTBUG-20937
void tst_qqmlconnections::singletonTypeTarget()
{
+ QFETCH(QString, prefix);
qmlRegisterSingletonType<MyTestSingletonType>("MyTestSingletonType", 1, 0, "Api", module_api_factory);
- QQmlComponent component(&engine, testFileUrl("singletontype-target.qml"));
+ QQmlComponent component(&engine, testFileUrl(prefix + "/singletontype-target.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -331,8 +369,9 @@ void tst_qqmlconnections::singletonTypeTarget()
void tst_qqmlconnections::enableDisable_QTBUG_36350()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -358,8 +397,9 @@ void tst_qqmlconnections::enableDisable_QTBUG_36350()
void tst_qqmlconnections::disabledAtStart()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("disabled-at-start.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/disabled-at-start.qml"));
QObject * const object = c.create();
QVERIFY(object != nullptr);
@@ -376,8 +416,9 @@ void tst_qqmlconnections::disabledAtStart()
//QTBUG-56499
void tst_qqmlconnections::clearImplicitTarget()
{
+ QFETCH(QString, prefix);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("test-connection-implicit.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/test-connection-implicit.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item != nullptr);
@@ -421,14 +462,15 @@ signals:
void tst_qqmlconnections::noAcceleratedGlobalLookup()
{
+ QFETCH(QString, prefix);
qRegisterMetaType<Proxy::MyEnum>();
qmlRegisterType<Proxy>("test.proxy", 1, 0, "Proxy");
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("override-proxy-type.qml"));
+ QQmlComponent c(&engine, testFileUrl(prefix + "/override-proxy-type.qml"));
QVERIFY(c.isReady());
QScopedPointer<QObject> object(c.create());
const QVariant val = object->property("testEnum");
- QCOMPARE(val.type(), QMetaType::Int);
+ QCOMPARE(val.type(), QVariant::Int);
QCOMPARE(val.toInt(), int(Proxy::EnumValue));
}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index cb4bee0d3a..6754f22049 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -71,6 +71,7 @@ private slots:
void outerContextObject();
void contextObjectHierarchy();
+ void destroyContextProperty();
private:
QQmlEngine engine;
@@ -892,6 +893,31 @@ void tst_qqmlcontext::contextObjectHierarchy()
});
}
+void tst_qqmlcontext::destroyContextProperty()
+{
+ QScopedPointer<QQmlContext> context;
+ QScopedPointer<QObject> objectThatOutlivesEngine(new QObject);
+ {
+ QQmlEngine engine;
+ context.reset(new QQmlContext(&engine));
+
+ {
+ QObject object;
+ context->setContextProperty(QLatin1String("a"), &object);
+ QCOMPARE(qvariant_cast<QObject *>(context->contextProperty(QLatin1String("a"))), &object);
+ }
+
+ QCOMPARE(qvariant_cast<QObject *>(context->contextProperty(QLatin1String("a"))), nullptr);
+ context->setContextProperty(QLatin1String("b"), objectThatOutlivesEngine.data());
+ }
+
+ // dropDestroyedObject() should not crash, even if the engine is gone.
+ objectThatOutlivesEngine.reset();
+
+ // We're not allowed to call context->contextProperty("b") anymore.
+ // TODO: Or are we?
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"
diff --git a/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp b/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp
index 99cabb4b09..13e4d4c53b 100644
--- a/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp
+++ b/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp
@@ -71,7 +71,7 @@ void tst_qqmlcpputils::fastConnect()
{
MyObject obj;
- qmlobject_connect(&obj, MyObject, SIGNAL(signal1()), &obj, MyObject, SLOT(slot1()))
+ qmlobject_connect(&obj, MyObject, SIGNAL(signal1()), &obj, MyObject, SLOT(slot1()));
obj.signal1();
QCOMPARE(obj.slotCount, 1);
diff --git a/tests/auto/qml/qqmldirparser/qqmldirparser.pro b/tests/auto/qml/qqmldirparser/qqmldirparser.pro
index dda74b1ef9..b5373a6e8f 100644
--- a/tests/auto/qml/qqmldirparser/qqmldirparser.pro
+++ b/tests/auto/qml/qqmldirparser/qqmldirparser.pro
@@ -6,3 +6,5 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmldirparser.cpp
include (../../shared/util.pri)
+
+TESTDATA = data/*
diff --git a/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp b/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp
index 3643ca65c6..1e690e38dd 100644
--- a/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp
+++ b/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp
@@ -32,6 +32,7 @@
#include <QObject>
#include <QQmlEngine>
#include <QQmlComponent>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmldirparser_p.h>
#include <QDebug>
@@ -56,12 +57,21 @@ tst_qqmldirparser::tst_qqmldirparser()
namespace {
- QStringList toStringList(const QList<QQmlError> &errors)
+ QStringList toStringList(const QList<QQmlJS::DiagnosticMessage> &errors)
{
QStringList rv;
- foreach (const QQmlError &e, errors)
- rv.append(e.toString());
+ for (const QQmlJS::DiagnosticMessage &e : errors) {
+ QString errorString = QLatin1String("qmldir");
+ if (e.line > 0) {
+ errorString += QLatin1Char(':') + QString::number(e.line);
+ if (e.column > 0)
+ errorString += QLatin1Char(':') + QString::number(e.column);
+ }
+
+ errorString += QLatin1String(": ") + e.message;
+ rv.append(errorString);
+ }
return rv;
}
diff --git a/tests/auto/qml/qqmlecmascript/data/generatorFunction.qml b/tests/auto/qml/qqmlecmascript/data/generatorFunction.qml
new file mode 100644
index 0000000000..66bb642f34
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/generatorFunction.qml
@@ -0,0 +1,22 @@
+import QtQml 2.12
+
+QtObject {
+ id: root
+ property bool test1: false;
+ property bool test2: false;
+ property bool test3: false;
+ property bool done: false;
+ function *gen() {
+ yield 1
+ yield 2
+ yield 3
+ }
+
+ Component.onCompleted: {
+ let it = root.gen();
+ root.test1 = (it.next().value == 1);
+ root.test2 = (it.next().value == 2);
+ root.test3 = (it.next().value == 3);
+ root.done = it.next().done;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml b/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml
new file mode 100644
index 0000000000..b22f8ab71e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regularExpression: "[a-zA-z]"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/regularExpression.qml b/tests/auto/qml/qqmlecmascript/data/regularExpression.qml
new file mode 100644
index 0000000000..6f31ffd305
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regularExpression.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regularExpression: /[a-zA-z]/
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
new file mode 100644
index 0000000000..0a75ea6f36
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ property var field: { "key": "value"};
+ property list<QtObject> mylist: [
+ QtObject {id: a},
+ QtObject {id: b}
+ ];
+ property var object: QtObject {};
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
index 54d29dfc94..9fdb7f92f3 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
@@ -1,4 +1,5 @@
import Qt.test 1.0
+import QtQuick 2.0 // We need the the QtQuick color provider for colorProperty
MyQmlObject
{
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index 4547a74470..3233e7f105 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -33,6 +33,7 @@
#include <QtQml/qqmlexpression.h>
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
+#include <QtCore/qregularexpression.h>
#include <QtQml/qqmllist.h>
#include <QtCore/qrect.h>
#include <QtGui/qmatrix.h>
@@ -49,7 +50,6 @@
#include <QtQml/qqmlcomponent.h>
#include <private/qqmlengine_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4qobjectwrapper_p.h>
class MyQmlAttachedObject : public QObject
@@ -101,6 +101,7 @@ class MyQmlObject : public QObject
Q_PROPERTY(QQmlListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp)
+ Q_PROPERTY(QRegularExpression regularExpression READ regularExpression WRITE setRegularExpression)
Q_PROPERTY(int nonscriptable READ nonscriptable WRITE setNonscriptable SCRIPTABLE false)
Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged)
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
@@ -170,6 +171,12 @@ public:
QRegExp regExp() { return m_regExp; }
void setRegExp(const QRegExp &regExp) { m_regExp = regExp; }
+ QRegularExpression regularExpression() { return m_regularExpression; }
+ void setRegularExpression(const QRegularExpression &regularExpression)
+ {
+ m_regularExpression = regularExpression;
+ }
+
int console() const { return 11; }
int nonscriptable() const { return 0; }
@@ -270,6 +277,7 @@ private:
int m_value;
int m_resetProperty;
QRegExp m_regExp;
+ QRegularExpression m_regularExpression;
QVariant m_variant;
QJSValue m_qjsvalue;
int m_intProperty;
@@ -788,11 +796,11 @@ public:
Q_INVOKABLE void method_real(qreal a) { invoke(10); m_actuals << a; }
Q_INVOKABLE void method_QString(QString a) { invoke(11); m_actuals << a; }
Q_INVOKABLE void method_QPointF(QPointF a) { invoke(12); m_actuals << a; }
- Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
- Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
+ Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << QVariant::fromValue(a); }
+ Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << QVariant::fromValue(a); }
+ Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << QVariant::fromValue(b); }
Q_INVOKABLE void method_QByteArray(QByteArray value) { invoke(29); m_actuals << value; }
- Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << qVariantFromValue(b); return b.call(); }
+ Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << QVariant::fromValue(b); return b.call(); }
Q_INVOKABLE QJSValue method_intQJSValue(int a, int b) { m_actuals << a << b; return QJSValue();} // Should never be called.
Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; }
@@ -1090,13 +1098,11 @@ class MyItemUsingRevisionedObject : public QObject
Q_PROPERTY(MyRevisionedClass *revisioned READ revisioned)
public:
- MyItemUsingRevisionedObject() {
- m_revisioned = new MyRevisionedClass;
- }
+ MyItemUsingRevisionedObject() : m_revisioned (new MyRevisionedClass) {}
- MyRevisionedClass *revisioned() const { return m_revisioned; }
+ MyRevisionedClass *revisioned() const { return m_revisioned.get(); }
private:
- MyRevisionedClass *m_revisioned;
+ QScopedPointer<MyRevisionedClass> m_revisioned;
};
QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered)
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 7a9c611269..8824dfd019 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -47,6 +47,7 @@
#include <private/qv4alloca_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4object_p.h>
+#include <private/qv4script_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qqmlabstractbinding_p.h>
@@ -236,6 +237,7 @@ private slots:
void functionAssignment_afterBinding();
void eval();
void function();
+ void topLevelGeneratorFunction();
void qtbug_10696();
void qtbug_11606();
void qtbug_11600();
@@ -376,6 +378,7 @@ private slots:
void hugeRegexpQuantifiers();
void singletonTypeWrapperLookup();
void getThisObject();
+ void semicolonAfterProperty();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1770,10 +1773,10 @@ void tst_qqmlecmascript::componentCreation()
}
QQmlComponent component(&engine, testUrl);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
- QMetaObject::invokeMethod(object, method.toUtf8());
+ QMetaObject::invokeMethod(object.get(), method.toUtf8());
QQmlComponent *created = object->componentProperty();
if (creationError.isEmpty()) {
@@ -1781,7 +1784,7 @@ void tst_qqmlecmascript::componentCreation()
QObject *expectedParent = reinterpret_cast<QObject *>(quintptr(-1));
if (createdParent == QLatin1String("obj")) {
- expectedParent = object;
+ expectedParent = object.get();
} else if ((createdParent == QLatin1String("null")) || createdParent.isEmpty()) {
expectedParent = nullptr;
}
@@ -2506,6 +2509,13 @@ void tst_qqmlecmascript::regExpBug()
delete object;
}
+ {
+ QQmlComponent component(&engine, testFileUrl("regularExpression.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
+ QVERIFY(!object.isNull());
+ QCOMPARE(object->regularExpression().pattern(), QLatin1String("[a-zA-z]"));
+ }
+
//QTBUG-23068
{
QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
@@ -2515,6 +2525,18 @@ void tst_qqmlecmascript::regExpBug()
QVERIFY(!object);
QCOMPARE(component.errorString(), err);
}
+
+ {
+ const QString err = QString::fromLatin1("%1:6 Invalid property assignment: "
+ "regular expression expected; "
+ "use /pattern/ syntax\n")
+ .arg(testFileUrl("regularExpression.2.qml").toString());
+ QQmlComponent component(&engine, testFileUrl("regularExpression.2.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(!object);
+ QCOMPARE(component.errorString(), err);
+ }
}
static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source)
@@ -2569,7 +2591,7 @@ static inline bool evaluate_value(QV4::ExecutionEngine *v4, const QV4::Value &o,
scope.engine->catchException();
return false;
}
- return QV4::Runtime::method_strictEqual(value, result);
+ return QV4::Runtime::StrictEqual::call(value, result);
}
static inline QV4::ReturnedValue evaluate(QV4::ExecutionEngine *v4, const QV4::Value &o,
@@ -2899,35 +2921,35 @@ void tst_qqmlecmascript::callQtInvokables()
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr));
+ QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", QV4::Primitive::undefinedValue()));
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr));
+ QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", QV4::Primitive::undefinedValue()));
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr));
+ QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", QV4::Primitive::undefinedValue()));
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr));
+ QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)nullptr));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", QV4::Primitive::undefinedValue()));
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)o));
+ QCOMPARE(o->actuals().at(0), QVariant::fromValue((QObject *)o));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", QV4::Primitive::undefinedValue()));
@@ -3182,13 +3204,13 @@ void tst_qqmlecmascript::callQtInvokables()
void tst_qqmlecmascript::resolveClashingProperties()
{
- ClashingNames *o = new ClashingNames();
+ QScopedPointer<ClashingNames> o(new ClashingNames());
QQmlEngine qmlengine;
QV4::ExecutionEngine *engine = qmlengine.handle();
QV4::Scope scope(engine);
- QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o));
+ QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o.get()));
QV4::ObjectIterator it(scope, object->as<QV4::Object>(), QV4::ObjectIterator::EnumerableOnly);
QV4::ScopedValue name(scope);
QV4::ScopedValue value(scope);
@@ -3203,7 +3225,7 @@ void tst_qqmlecmascript::resolveClashingProperties()
QString key = name->toQStringNoThrow();
if (key == QLatin1String("clashes")) {
value = v;
- QV4::ScopedValue typeString(scope, QV4::Runtime::method_typeofValue(engine, value));
+ QV4::ScopedValue typeString(scope, QV4::Runtime::TypeofValue::call(engine, value));
QString type = typeString->toQStringNoThrow();
if (type == QLatin1String("boolean")) {
QVERIFY(!seenProperty);
@@ -6151,7 +6173,7 @@ void tst_qqmlecmascript::variants()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("variants.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("undefinedVariant").type(), QVariant::Invalid);
@@ -6160,13 +6182,13 @@ void tst_qqmlecmascript::variants()
QCOMPARE(object->property("doubleVariant").type(), QVariant::Double);
QVariant result;
- QMetaObject::invokeMethod(object, "checkNull", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(object.get(), "checkNull", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(object, "checkUndefined", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(object.get(), "checkUndefined", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(object, "checkNumber", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(object.get(), "checkNumber", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
}
@@ -6408,6 +6430,28 @@ void tst_qqmlecmascript::function()
delete o;
}
+// QTBUG-77096
+void tst_qqmlecmascript::topLevelGeneratorFunction()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("generatorFunction.qml"));
+
+ QScopedPointer<QObject> o {component.create()};
+ QVERIFY(o != nullptr);
+
+ // check that generator works correctly in QML
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("done").toBool(), true);
+
+ // check that generator is accessible from C++
+ QVariant returnedValue;
+ QMetaObject::invokeMethod(o.get(), "gen", Q_RETURN_ARG(QVariant, returnedValue));
+ auto it = returnedValue.value<QJSValue>();
+ QCOMPARE(it.property("next").callWithInstance(it).property("value").toInt(), 1);
+}
+
// Test the "Qt.include" method
void tst_qqmlecmascript::include()
{
@@ -7034,12 +7078,12 @@ void tst_qqmlecmascript::realToInt()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("realToInt.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
- QMetaObject::invokeMethod(object, "test1");
+ QMetaObject::invokeMethod(object.get(), "test1");
QCOMPARE(object->value(), int(4));
- QMetaObject::invokeMethod(object, "test2");
+ QMetaObject::invokeMethod(object.get(), "test2");
QCOMPARE(object->value(), int(7));
}
@@ -7048,7 +7092,7 @@ void tst_qqmlecmascript::urlProperty()
QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
object->setStringProperty("http://qt-project.org");
QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
@@ -7063,7 +7107,7 @@ void tst_qqmlecmascript::urlPropertyWithEncoding()
QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
object->setStringProperty("http://qt-project.org");
const QUrl encoded = QUrl::fromEncoded("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
@@ -7098,7 +7142,7 @@ void tst_qqmlecmascript::dynamicString()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicString.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("stringProperty").toString(),
QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
@@ -7108,7 +7152,7 @@ void tst_qqmlecmascript::deleteLaterObjectMethodCall()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteLaterObjectMethodCall.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7116,7 +7160,7 @@ void tst_qqmlecmascript::automaticSemicolon()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7124,7 +7168,7 @@ void tst_qqmlecmascript::compatibilitySemicolon()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compatibilitySemicolon.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7132,7 +7176,7 @@ void tst_qqmlecmascript::incrDecrSemicolon1()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon1.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7140,7 +7184,7 @@ void tst_qqmlecmascript::incrDecrSemicolon2()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon2.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7156,7 +7200,7 @@ void tst_qqmlecmascript::unaryExpression()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("unaryExpression.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -7296,7 +7340,7 @@ void tst_qqmlecmascript::switchStatement()
QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("switchStatement.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7319,7 +7363,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7342,7 +7386,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7369,7 +7413,7 @@ void tst_qqmlecmascript::switchStatement()
QString warning = component.url().toString() + ":4:5: Unable to assign [undefined] to int";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7393,7 +7437,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.5.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7416,7 +7460,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.6.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7444,7 +7488,7 @@ void tst_qqmlecmascript::withStatement()
{
QUrl url = testFileUrl("withStatement.1.qml");
QQmlComponent component(&engine, url);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->value(), 123);
@@ -7456,7 +7500,7 @@ void tst_qqmlecmascript::tryStatement()
QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("tryStatement.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->value(), 123);
@@ -7464,7 +7508,7 @@ void tst_qqmlecmascript::tryStatement()
{
QQmlComponent component(&engine, testFileUrl("tryStatement.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->value(), 321);
@@ -7472,7 +7516,7 @@ void tst_qqmlecmascript::tryStatement()
{
QQmlComponent component(&engine, testFileUrl("tryStatement.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->qjsvalue().isUndefined());
@@ -7480,7 +7524,7 @@ void tst_qqmlecmascript::tryStatement()
{
QQmlComponent component(&engine, testFileUrl("tryStatement.4.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->qjsvalue().isUndefined());
@@ -7621,7 +7665,7 @@ void tst_qqmlecmascript::onDestruction()
// component instance. This shouldn't crash.
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("onDestruction.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj != nullptr);
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
@@ -7962,19 +8006,19 @@ void tst_qqmlecmascript::dateParse()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("date.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
if (object == nullptr)
qDebug() << component.errorString();
QVERIFY(object != nullptr);
QVariant q;
- QMetaObject::invokeMethod(object, "test_is_invalid_jsDateTime", Q_RETURN_ARG(QVariant, q));
+ QMetaObject::invokeMethod(object.get(), "test_is_invalid_jsDateTime", Q_RETURN_ARG(QVariant, q));
QVERIFY(q.toBool());
- QMetaObject::invokeMethod(object, "test_is_invalid_qtDateTime", Q_RETURN_ARG(QVariant, q));
+ QMetaObject::invokeMethod(object.get(), "test_is_invalid_qtDateTime", Q_RETURN_ARG(QVariant, q));
QVERIFY(q.toBool());
- QMetaObject::invokeMethod(object, "test_rfc2822_date", Q_RETURN_ARG(QVariant, q));
+ QMetaObject::invokeMethod(object.get(), "test_rfc2822_date", Q_RETURN_ARG(QVariant, q));
QCOMPARE(q.toLongLong(), 1379512851000LL);
}
@@ -7983,14 +8027,14 @@ void tst_qqmlecmascript::utcDate()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("utcdate.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
if (object == nullptr)
qDebug() << component.errorString();
QVERIFY(object != nullptr);
QVariant q;
QVariant val = QString::fromLatin1("2014-07-16T23:30:31");
- QMetaObject::invokeMethod(object, "check_utc", Q_RETURN_ARG(QVariant, q), Q_ARG(QVariant, val));
+ QMetaObject::invokeMethod(object.get(), "check_utc", Q_RETURN_ARG(QVariant, q), Q_ARG(QVariant, val));
QVERIFY(q.toBool());
}
@@ -7999,20 +8043,20 @@ void tst_qqmlecmascript::negativeYear()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("negativeyear.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
if (object == nullptr)
qDebug() << component.errorString();
QVERIFY(object != nullptr);
QVariant q;
- QMetaObject::invokeMethod(object, "check_negative_tostring", Q_RETURN_ARG(QVariant, q));
+ QMetaObject::invokeMethod(object.get(), "check_negative_tostring", Q_RETURN_ARG(QVariant, q));
// Only check for the year. We hope that every language writes the year in arabic numerals and
// in relation to a specific dude's date of birth. We also hope that no language adds a "-2001"
// junk string somewhere in the middle.
QVERIFY(q.toString().indexOf(QStringLiteral("-2001")) != -1);
- QMetaObject::invokeMethod(object, "check_negative_toisostring", Q_RETURN_ARG(QVariant, q));
+ QMetaObject::invokeMethod(object.get(), "check_negative_toisostring", Q_RETURN_ARG(QVariant, q));
QCOMPARE(q.toString().left(16), QStringLiteral("result: -002000-"));
}
@@ -8055,6 +8099,7 @@ void tst_qqmlecmascript::jsOwnedObjectsDeletedOnEngineDestroy()
QCOMPARE(spy1.count(), 1);
QCOMPARE(spy2.count(), 1);
+ deleteObject.deleteNestedObject();
delete object;
}
@@ -8066,7 +8111,7 @@ void tst_qqmlecmascript::updateCall()
QString file("updateCall.qml");
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(file));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -8077,7 +8122,7 @@ void tst_qqmlecmascript::numberParsing()
QString file("numberParsing.%1.qml");
file = file.arg(i);
QQmlComponent component(&engine, testFileUrl(file));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
for (int i = 1; i < 3; ++i) {
@@ -8260,8 +8305,8 @@ void tst_qqmlecmascript::idsAsLValues()
QString err = QString(QLatin1String("%1:5: Error: left-hand side of assignment operator is not an lvalue")).arg(testFileUrl("idAsLValue.qml").toString());
QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
QTest::ignoreMessage(QtWarningMsg, qPrintable(err));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(!object);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!qobject_cast<MyQmlObject*>(object.get()));
}
void tst_qqmlecmascript::qtbug_34792()
@@ -8334,7 +8379,9 @@ void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext()
void tst_qqmlecmascript::importedScriptsAccessOnObjectWithInvalidContext()
{
QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
+ const QUrl url = testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(url.toString() + ":29: TypeError: Cannot read property 'Foo' of null"));
+ QQmlComponent component(&engine, url);
QScopedPointer<QObject> obj(component.create());
if (obj.isNull())
qDebug() << component.errors().first().toString();
@@ -8474,10 +8521,10 @@ void tst_qqmlecmascript::readUnregisteredQObjectProperty()
qmlRegisterType<ObjectContainer>("Test", 1, 0, "ObjectContainer");
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("accessUnregisteredQObjectProperty.qml"));
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root);
- QMetaObject::invokeMethod(root, "readProperty");
+ QMetaObject::invokeMethod(root.get(), "readProperty");
QCOMPARE(root->property("container").value<ObjectContainer*>()->mGetterCalled, true);
}
@@ -8486,10 +8533,10 @@ void tst_qqmlecmascript::writeUnregisteredQObjectProperty()
qmlRegisterType<ObjectContainer>("Test", 1, 0, "ObjectContainer");
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("accessUnregisteredQObjectProperty.qml"));
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root);
- QMetaObject::invokeMethod(root, "writeProperty");
+ QMetaObject::invokeMethod(root.get(), "writeProperty");
QCOMPARE(root->property("container").value<ObjectContainer*>()->mSetterCalled, true);
}
@@ -9112,8 +9159,8 @@ void tst_qqmlecmascript::singletonTypeWrapperLookup()
});
auto cleanup = qScopeGuard([&]() {
- qmlUnregisterType(singletonTypeId1);
- qmlUnregisterType(singletonTypeId2);
+ QQmlMetaType::unregisterType(singletonTypeId1);
+ QQmlMetaType::unregisterType(singletonTypeId2);
});
QQmlComponent component(&engine, testFileUrl("SingletonLookupTest.qml"));
@@ -9141,6 +9188,16 @@ void tst_qqmlecmascript::getThisObject()
QTRY_COMPARE(qvariant_cast<QObject *>(test->property("self")), test.data());
}
+// QTBUG-77954
+void tst_qqmlecmascript::semicolonAfterProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("semicolonAfterProperty.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> test(component.create());
+ QVERIFY(!test.isNull());
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/qqmlengine.pro b/tests/auto/qml/qqmlengine/qqmlengine.pro
index d2eb92bfd5..8946201ea0 100644
--- a/tests/auto/qml/qqmlengine/qqmlengine.pro
+++ b/tests/auto/qml/qqmlengine/qqmlengine.pro
@@ -4,6 +4,8 @@ macx:CONFIG -= app_bundle
include (../../shared/util.pri)
+TESTDATA = data/*
+
SOURCES += tst_qqmlengine.cpp
QT += core-private gui-private qml-private network testlib
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 0cb6753020..64f167b47e 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -43,6 +43,7 @@
#include <QQmlIncubationController>
#include <QTemporaryDir>
#include <private/qqmlengine_p.h>
+#include <private/qqmltypedata_p.h>
#include <QQmlAbstractUrlInterceptor>
class tst_qqmlengine : public QQmlDataTest
@@ -427,7 +428,7 @@ void tst_qqmlengine::trimComponentCache()
engine.setIncubationController(&componentCache);
QQmlComponent component(&engine, testFileUrl(file));
- QVERIFY(component.isReady());
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
@@ -741,13 +742,17 @@ public:
CustomSelector(const QUrl &base):m_base(base){}
virtual QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType d)
{
- if (url.scheme() != QStringLiteral("file"))
+ if ((url.scheme() != QStringLiteral("file") && url.scheme() != QStringLiteral("qrc"))
+ || url.path().contains("QtQml"))
return url;
if (!m_interceptionPoints.contains(d))
return url;
- if (url.path().endsWith("Test.2/qmldir"))//Special case
- return QUrl::fromLocalFile(m_base.path() + "interception/module/intercepted/qmldir");
+ if (url.path().endsWith("Test.2/qmldir")) {//Special case
+ QUrl url = m_base;
+ url.setPath(m_base.path() + "interception/module/intercepted/qmldir");
+ return url;
+ }
// Special case: with 5.10 we always add the implicit import, so we need to explicitly handle this case now
if (url.path().endsWith("intercepted/qmldir"))
return url;
@@ -835,7 +840,7 @@ void tst_qqmlengine::urlInterceptor()
QFETCH(QString, expectedAbsoluteUrl);
QQmlEngine e;
- e.setImportPathList(QStringList() << testFileUrl("interception/imports").toLocalFile());
+ e.addImportPath(testFileUrl("interception/imports").url());
CustomSelector cs(testFileUrl(""));
cs.m_interceptionPoints = interceptionPoint;
e.setUrlInterceptor(&cs);
@@ -935,7 +940,7 @@ void tst_qqmlengine::cppSignalAndEval()
{
ObjectCaller objectCaller;
QQmlEngine engine;
- engine.rootContext()->setContextProperty(QLatin1Literal("CallerCpp"), &objectCaller);
+ engine.rootContext()->setContextProperty(QLatin1String("CallerCpp"), &objectCaller);
QQmlComponent c(&engine);
c.setData("import QtQuick 2.9\n"
"Item {\n"
@@ -1015,6 +1020,65 @@ void tst_qqmlengine::singletonInstance()
}
{
+ int data = 30;
+ auto id = qmlRegisterSingletonType<CppSingleton>("Qt.test",1,0,"CapturingLambda",[data](QQmlEngine*, QJSEngine*){ // register qobject singleton with capturing lambda
+ auto o = new CppSingleton;
+ o->setProperty("data", data);
+ return o;
+ });
+ QJSValue value = engine.singletonInstance<QJSValue>(id);
+ QVERIFY(!value.isUndefined());
+ QVERIFY(value.isQObject());
+ QObject *instance = value.toQObject();
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+ QCOMPARE(instance->property("data"), data);
+ }
+ {
+ qmlRegisterSingletonType<CppSingleton>("Qt.test",1,0,"NotAmbiguous", [](QQmlEngine* qeng, QJSEngine* jeng) -> QObject* {return CppSingleton::create(qeng, jeng);}); // test that overloads for qmlRegisterSingleton are not ambiguous
+ }
+ {
+ // Register QObject* directly
+ CppSingleton single;
+ int id = qmlRegisterSingletonInstance("Qt.test", 1, 0, "CppOwned",
+ &single);
+ QQmlEngine engine2;
+ CppSingleton *singlePtr = engine2.singletonInstance<CppSingleton *>(id);
+ QVERIFY(singlePtr);
+ QCOMPARE(&single, singlePtr);
+ QVERIFY(engine2.objectOwnership(singlePtr) == QQmlEngine::CppOwnership);
+ }
+
+ {
+ CppSingleton single;
+ QQmlEngine engineA;
+ QQmlEngine engineB;
+ int id = qmlRegisterSingletonInstance("Qt.test", 1, 0, "CppOwned", &single);
+ auto singlePtr = engineA.singletonInstance<CppSingleton *>(id);
+ QVERIFY(singlePtr);
+ singlePtr = engineA.singletonInstance<CppSingleton *>(id); // accessing the singleton multiple times from the same engine is fine
+ QVERIFY(singlePtr);
+ QTest::ignoreMessage(QtMsgType::QtCriticalMsg, "<Unknown File>: qmlRegisterSingletonType(): \"CppOwned\" is not available because the callback function returns a null pointer.");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: Singleton registered by registerSingletonInstance must only be accessed from one engine");
+ QCOMPARE(&single, singlePtr);
+ auto noSinglePtr = engineB.singletonInstance<CppSingleton *>(id);
+ QVERIFY(!noSinglePtr);
+ }
+
+ {
+ CppSingleton single;
+ QThread newThread {};
+ single.moveToThread(&newThread);
+ QCOMPARE(single.thread(), &newThread);
+ QQmlEngine engineB;
+ int id = qmlRegisterSingletonInstance("Qt.test", 1, 0, "CppOwned", &single);
+ QTest::ignoreMessage(QtMsgType::QtCriticalMsg, "<Unknown File>: qmlRegisterSingletonType(): \"CppOwned\" is not available because the callback function returns a null pointer.");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: Registered object must live in the same thread as the engine it was registered with");
+ auto noSinglePtr = engineB.singletonInstance<CppSingleton *>(id);
+ QVERIFY(!noSinglePtr);
+ }
+
+ {
// Invalid types
QJSValue value;
value = engine.singletonInstance<QJSValue>(-4711);
@@ -1043,6 +1107,16 @@ void tst_qqmlengine::singletonInstance()
SomeQObjectClass * instance = engine.singletonInstance<SomeQObjectClass*>(cppSingletonTypeId);
QVERIFY(!instance);
}
+
+ {
+ // deleted object
+ auto dayfly = new QObject{};
+ auto id = qmlRegisterSingletonInstance("Vanity", 1, 0, "Dayfly", dayfly);
+ delete dayfly;
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: The registered singleton has already been deleted. Ensure that it outlives the engine.");
+ QObject *instance = engine.singletonInstance<QObject*>(id);
+ QVERIFY(!instance);
+ }
}
void tst_qqmlengine::aggressiveGc()
diff --git a/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp b/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp
index 7a7185e909..f282e60417 100644
--- a/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp
+++ b/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp
@@ -195,7 +195,7 @@ void tst_qqmlerror::debug()
}
{
- QUrl url(dataDirectoryUrl().resolved(QUrl("test.txt")));
+ QUrl url = testFileUrl("test.txt");
QQmlError error;
error.setUrl(url);
error.setDescription("An Error");
diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
index 1decc04ad2..0ba29d6b6a 100644
--- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
+++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlscriptstring.h>
@@ -125,10 +126,12 @@ void tst_qqmlexpression::expressionFromDataComponent()
QQmlEngine engine;
QQmlComponent c(&engine);
- QUrl url = testFileUrl("expressionFromDataComponent.qml");
+ const QString fn(QLatin1String("expressionFromDataComponent.qml"));
+ QUrl url = testFileUrl(fn);
+ QString path = testFile(fn);
{
- QFile f(url.toLocalFile());
+ QFile f(path);
QVERIFY(f.open(QIODevice::ReadOnly));
c.setData(f.readAll(), url);
}
diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
index 341a49bf09..16b8fe578d 100644
--- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
+++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
@@ -47,18 +47,21 @@ class tst_qqmlextensionplugin : public QObject
{
Q_OBJECT
- bool isDuplicate(QString file, const QList<QString> & files) {
-#ifndef DEBUG_SUFFIX
- Q_UNUSED(file)
- Q_UNUSED(files)
- return false;
-#else
+ static QStringList removeDuplicates(QStringList files) {
+#ifdef DEBUG_SUFFIX
+ const auto isDuplicate = [files] (QString file) {
# ifdef QT_DEBUG
- return !file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(SUFFIX, DEBUG_SUFFIX));
+ return !file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(SUFFIX, DEBUG_SUFFIX));
# else
- return file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(DEBUG_SUFFIX, SUFFIX));
+ return file.endsWith(DEBUG_SUFFIX) && files.contains(file.replace(DEBUG_SUFFIX, SUFFIX));
# endif
+ };
+
+ files.erase(std::remove_if(files.begin(), files.end(), isDuplicate),
+ files.end());
+
#endif
+ return files;
}
public:
@@ -84,12 +87,7 @@ void tst_qqmlextensionplugin::iidCheck_data()
}
}
- for (QMutableListIterator<QString> it(files); it.hasNext(); ) {
- QString file = it.next();
- if (isDuplicate(file, files)) {
- it.remove();
- }
- }
+ files = removeDuplicates(std::move(files));
QTest::addColumn<QString>("filePath");
foreach (const QString &file, files) {
diff --git a/tests/auto/qml/qqmlimport/qqmlimport.pro b/tests/auto/qml/qqmlimport/qqmlimport.pro
index c8b0f68d9f..ba80547f4e 100644
--- a/tests/auto/qml/qqmlimport/qqmlimport.pro
+++ b/tests/auto/qml/qqmlimport/qqmlimport.pro
@@ -6,3 +6,8 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qqmlimport.cpp
include (../../shared/util.pri)
+
+TESTDATA = data/* \
+ MyPluginSupported/* \
+ MyPluginUnsupported/* \
+ FormFromQmlDir/*
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index a9657eba1d..ca1e52ad2c 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -78,7 +78,7 @@ void tst_QQmlImport::testDesignerSupported()
QVERIFY(window->errors().isEmpty());
QString warningString("%1:30:1: module does not support the designer \"MyPluginUnsupported\" \n import MyPluginUnsupported 1.0\r \n ^ ");
-#ifndef Q_OS_WIN
+#if !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID)
warningString.remove('\r');
#endif
warningString = warningString.arg(testFileUrl("testfile_unsupported.qml").toString());
@@ -130,6 +130,9 @@ void tst_QQmlImport::uiFormatLoading()
void tst_QQmlImport::importPathOrder()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath) returns bogus path on Android, but its nevertheless unusable.");
+#endif
QStringList expectedImportPaths;
QString appDirPath = QCoreApplication::applicationDirPath();
QString qml2Imports = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
diff --git a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
index 542ec44736..e8ed8e91b1 100644
--- a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
+++ b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
@@ -9,4 +9,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private testlib
+QT += core-private gui-private qml-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
index a66f13e6bb..9c5e09c77c 100644
--- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
+++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
@@ -31,7 +31,7 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
-#include <QtQml/private/qqmlinstantiator_p.h>
+#include <QtQmlModels/private/qqmlinstantiator_p.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlincubator.h>
#include "../../shared/util.h"
diff --git a/tests/auto/qml/qqmllanguage/data/alias.17.qml b/tests/auto/qml/qqmllanguage/data/alias.17.qml
new file mode 100644
index 0000000000..a76dd120b6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.17.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.12
+
+Item {
+ id: root
+ anchors.fill: parent
+ width: 100
+ height: 100
+ property bool success: checkValue === aliasUser.topMargin
+ property int checkValue: 42
+ Rectangle {
+ id: myItem
+ objectName: "myItem"
+ color: "blue"
+ anchors.topMargin: root.checkValue
+ width: 50
+ height: 50
+ Text {text: "source:\n" + myItem.anchors.topMargin}
+ }
+
+ Rectangle {
+ property alias topMargin: myItem.anchors.topMargin
+ id: aliasUser
+ objectName: "aliasUser"
+ color: "red"
+ anchors.left: myItem.right
+ width: 50
+ height: 50
+ Text {objectName: "myText"; text: "alias:\n" + aliasUser.topMargin}
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt b/tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt
diff --git a/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml b/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml
new file mode 100644
index 0000000000..3567cdb5a3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml
@@ -0,0 +1,6 @@
+import QML 1.0
+QtObject {
+ property Component component: Component {
+ QtObject {}
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
index 30748234bc..5a144f2db5 100644
--- a/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
@@ -1 +1 @@
-3:5:Invalid grouped property access
+3:5:Invalid grouped property access: Property "value" with primitive type "int".
diff --git a/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
new file mode 100644
index 0000000000..26931a4f10
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/functionParameterTypes.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0 as QQ
+import QtQml 2.0 as Core
+QQ.Item {
+ id: root
+ function returnItem() : Core.QtObject { return root; }
+ function takeString(arg: string) { return arg; }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt
index 92ce4c649f..8dca84b34e 100644
--- a/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.2.errors.txt
@@ -1,2 +1 @@
5:1:TetZ$ is not a type
--1:-1:Invalid QML type name "TetZ$"
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml b/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml
index e726f6783c..f164ec98ea 100644
--- a/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.2.qml
Binary files differ
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt
new file mode 100644
index 0000000000..da17dc5599
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.3.errors.txt
@@ -0,0 +1,2 @@
+3:2:Unexpected token `version number'
+1:1:Expected a qualified name id or a string literal
diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml b/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml
new file mode 100644
index 0000000000..6861ebf8a9
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/fuzzed.3.qml
Binary files differ
diff --git a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
index 810fd31b41..5deec4ccf9 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
@@ -1 +1 @@
-5:5:Invalid grouped property access
+5:5:Invalid grouped property access: Property "o" with primitive type "int".
diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
index 945dacf8ab..887d87b9fb 100644
--- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
@@ -1 +1 @@
-4:18:Can not assign value of type "int" to property "x", expecting an object
+4:18:Cannot assign value of type "MyTypeObject" to property "x", expecting "int"
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
new file mode 100644
index 0000000000..1655f9264a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
@@ -0,0 +1 @@
+3:23:Cannot assign to property of unknown type "SomethingUnknown*".
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
new file mode 100644
index 0000000000..c22fd65350
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
@@ -0,0 +1,4 @@
+import Test 1.0
+MyQmlObject {
+ somethingUnknown: SomethingKnown {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml b/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml
new file mode 100644
index 0000000000..6dee30de95
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/signalParameterTypes.3.qml
@@ -0,0 +1,19 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+
+ property bool success: false
+
+ signal testSignal(param: bool)
+
+ function handleTestSignal(param) {
+ success = param
+ }
+
+ Component.onCompleted: {
+ success = false;
+ root.testSignal.connect(handleTestSignal)
+ root.testSignal(true);
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt
new file mode 100644
index 0000000000..b316acae30
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.errors.txt
@@ -0,0 +1 @@
+5:14:Type annotations are not permitted in variable declarations
diff --git a/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml
new file mode 100644
index 0000000000..655fe4c226
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/typeAnnotations.2.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ function notYet() {
+ var x: string = "ko"
+ return x
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.pro b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
index 3e88f3f0db..724a27320c 100644
--- a/tests/auto/qml/qqmllanguage/qqmllanguage.pro
+++ b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
@@ -17,3 +17,5 @@ include (../../shared/util.pri)
OTHER_FILES += \
data/readonlyObjectProperty.qml
+
+android: RESOURCES += qqmllanguage.qrc
diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.qrc b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc
new file mode 100644
index 0000000000..f5212ac75c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/qqmllanguage.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+<file alias="data/I18nTypeÁâãäå.qml">data/I18nType30.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index f9a6ee8e5a..6956533196 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -27,6 +27,8 @@
****************************************************************************/
#include "testtypes.h"
+#include <private/qv4qmlcontext_p.h>
+
static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
@@ -60,6 +62,7 @@ void registerTypes()
qmlRegisterType<MyRevisionedClass,1>("Test",1,1,"MyRevisionedClass");
qmlRegisterType<MyRevisionedIllegalOverload>("Test",1,0,"MyRevisionedIllegalOverload");
qmlRegisterType<MyRevisionedLegalOverload>("Test",1,0,"MyRevisionedLegalOverload");
+ qmlRegisterType<SomethingKnown>("Test",1,0,"SomethingKnown");
// Register the uncreatable base class
qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Test",1,1);
@@ -125,7 +128,7 @@ QVariant myCustomVariantTypeConverter(const QString &data)
}
-void CustomBindingParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void CustomBindingParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
Q_ASSERT(customBinding);
@@ -154,7 +157,7 @@ void CustomBinding::componentComplete()
}
}
-void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
if (bindings.count() != 1) {
error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test"));
@@ -184,7 +187,7 @@ void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::Compil
}
}
-void SimpleObjectCustomParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &bindings)
+void SimpleObjectCustomParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &bindings)
{
SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
Q_ASSERT(o);
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index bb6e9582c2..1aab24841a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -89,6 +89,14 @@ private:
int m_value2;
};
+class SomethingUnknown : public QObject {
+ Q_OBJECT
+};
+
+class SomethingKnown : public SomethingUnknown {
+ Q_OBJECT
+};
+
class MyQmlObject : public QObject, public MyInterface
{
Q_OBJECT
@@ -104,6 +112,7 @@ class MyQmlObject : public QObject, public MyInterface
Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
Q_PROPERTY(int nonScriptable READ nonScriptable WRITE setNonScriptable SCRIPTABLE false)
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
+ Q_PROPERTY(SomethingUnknown* somethingUnknown READ somethingUnknown WRITE setSomethingUnknown NOTIFY somethingUnknownChanged)
Q_INTERFACES(MyInterface)
public:
@@ -151,6 +160,9 @@ public:
int childAddedEventCount() const { return m_childAddedEventCount; }
+ SomethingUnknown* somethingUnknown() const { return nullptr; }
+ void setSomethingUnknown(SomethingUnknown* something) { Q_UNUSED(something); }
+
public slots:
void basicSlot() { qWarning("MyQmlObject::basicSlot"); }
void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); }
@@ -162,6 +174,7 @@ signals:
void oddlyNamedNotifySignal();
void signalWithDefaultArg(int parameter = 5);
void qjsvalueChanged();
+ void somethingUnknownChanged();
protected:
virtual bool event(QEvent *event);
@@ -781,15 +794,15 @@ class MyCustomParserType : public QObject
class MyCustomParserTypeParser : public QQmlCustomParser
{
public:
- virtual void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
};
class EnumSupportingCustomParser : public QQmlCustomParser
{
public:
- virtual void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
- virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
+ virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
};
class MyParserStatus : public QObject, public QQmlParserStatus
@@ -1275,15 +1288,15 @@ public:
void setTarget(QObject *newTarget) { m_target = newTarget; }
QPointer<QObject> m_target;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding*> bindings;
QByteArray m_bindingData;
};
class CustomBindingParser : public QQmlCustomParser
{
- virtual void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
+ virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
};
class SimpleObjectWithCustomParser : public QObject
@@ -1328,8 +1341,8 @@ private:
class SimpleObjectCustomParser : public QQmlCustomParser
{
- virtual void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
+ virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) {}
+ virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &);
};
class RootObjectInCreationTester : public QObject
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 63fc55ad0f..fae74f1f25 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -208,6 +208,7 @@ private slots:
void remoteLoadCrash();
void signalWithDefaultArg();
void signalParameterTypes();
+ void functionParameterTypes();
// regression tests for crashes
void crash1();
@@ -242,12 +243,11 @@ private slots:
void compositeSingletonModuleQualified();
void compositeSingletonInstantiateError();
void compositeSingletonDynamicPropertyError();
- void compositeSingletonDynamicSignal();
+ void compositeSingletonDynamicSignalAndJavaScriptPragma();
void compositeSingletonQmlRegisterTypeError();
void compositeSingletonQmldirNoPragmaError();
void compositeSingletonQmlDirError();
void compositeSingletonRemote();
- void compositeSingletonJavaScriptPragma();
void compositeSingletonSelectors();
void compositeSingletonRegistered();
void compositeSingletonCircular();
@@ -369,7 +369,8 @@ private:
void tst_qqmllanguage::cleanupTestCase()
{
- QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml"))));
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc"))
+ QVERIFY(QFile::remove(testFile(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml"))));
}
void tst_qqmllanguage::insertedSemicolon_data()
@@ -620,11 +621,29 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("fuzzed.1") << "fuzzed.1.qml" << "fuzzed.1.errors.txt" << false;
QTest::newRow("fuzzed.2") << "fuzzed.2.qml" << "fuzzed.2.errors.txt" << false;
-}
+ QTest::newRow("fuzzed.3") << "fuzzed.3.qml" << "fuzzed.3.errors.txt" << false;
+
+ QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false;
+
+ QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
+ QTest::newRow("propertyUnknownType") << "propertyUnknownType.qml" << "propertyUnknownType.errors.txt" << false;
+}
void tst_qqmllanguage::errors()
{
+#ifdef Q_OS_ANDROID
+ if (qstrcmp(QTest::currentDataTag(), "fuzzed.2") == 0) {
+ QSKIP("Gives different errors on Android");
+ /* Only gives one error on Android:
+
+ qrc:/data/fuzzed.2.qml:1:1: "
+ import"
+ ^
+ So, it seems to complain about the first import (which is understandable)
+ */
+ }
+#endif
QFETCH(QString, file);
QFETCH(QString, errorFile);
QFETCH(bool, create);
@@ -1458,8 +1477,8 @@ void tst_qqmllanguage::dynamicObjectProperties()
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr));
- QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)nullptr));
+ QCOMPARE(object->property("objectProperty"), QVariant::fromValue((QObject*)nullptr));
+ QVERIFY(object->property("objectProperty2") != QVariant::fromValue((QObject*)nullptr));
}
{
QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml"));
@@ -1467,7 +1486,7 @@ void tst_qqmllanguage::dynamicObjectProperties()
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr));
+ QVERIFY(object->property("objectProperty") != QVariant::fromValue((QObject*)nullptr));
}
}
@@ -1736,7 +1755,7 @@ void tst_qqmllanguage::aliasProperties()
// Write through alias
MyQmlObject *v2 = new MyQmlObject();
v2->setParent(object.data());
- object->setProperty("aliasObject", qVariantFromValue(v2));
+ object->setProperty("aliasObject", QVariant::fromValue(v2));
MyQmlObject *v3 =
qvariant_cast<MyQmlObject *>(object->property("aliasObject"));
QVERIFY(v3 != nullptr);
@@ -1951,6 +1970,69 @@ void tst_qqmllanguage::aliasProperties()
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
}
+
+ // Alias to grouped property
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.17.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QVERIFY(object->property("success").toBool());
+ }
+
+ // Alias to grouped property updates
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.17.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QObject *aliasUser = object->findChild<QObject*>(QLatin1String("aliasUser"));
+ QVERIFY(aliasUser);
+ QQmlProperty checkValueProp(object.get(), "checkValue");
+ QVERIFY(checkValueProp.isValid());
+ checkValueProp.write(777);
+ QCOMPARE(object->property("checkValue").toInt(), 777);
+ QCOMPARE(aliasUser->property("topMargin").toInt(), 777);
+ }
+
+ // Write to alias to grouped property
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.17.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QObject *aliasUser = object->findChild<QObject*>(QLatin1String("aliasUser"));
+ QVERIFY(aliasUser);
+ QQmlProperty topMarginProp {aliasUser, "topMargin"};
+ QVERIFY(topMarginProp.isValid());
+ topMarginProp.write(777);
+ QObject *myItem = object->findChild<QObject*>(QLatin1String("myItem"));
+ QVERIFY(myItem);
+ auto anchors = myItem->property("anchors").value<QObject*>();
+ QVERIFY(anchors);
+ QCOMPARE(anchors->property("topMargin").toInt(), 777);
+ }
+
+ // Binding to alias to grouped property gets updated
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.17.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QObject *aliasUser = object->findChild<QObject*>(QLatin1String("aliasUser"));
+ QVERIFY(aliasUser);
+ QQmlProperty topMarginProp {aliasUser, "topMargin"};
+ QVERIFY(topMarginProp.isValid());
+ topMarginProp.write(20);
+ QObject *myText = object->findChild<QObject*>(QLatin1String("myText"));
+ QVERIFY(myText);
+ auto text = myText->property("text").toString();
+ QCOMPARE(text, "alias:\n20");
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -2223,7 +2305,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize));
memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize);
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = td->compilationUnit();
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit = td->compilationUnit();
compilationUnit->setUnitData(qmlUnit);
const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
@@ -2233,9 +2315,9 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
const QV4::CompiledData::Binding *binding = rootObject->bindingTable() + i;
if (compilationUnit->stringAt(binding->propertyNameIndex) != QString("scriptProperty"))
continue;
- QCOMPARE(binding->valueAsScriptString(compilationUnit.data()), QString("intProperty"));
+ QCOMPARE(compilationUnit->bindingValueAsScriptString(binding), QString("intProperty"));
const_cast<QV4::CompiledData::Binding*>(binding)->stringIndex = 0; // empty string index
- QVERIFY(binding->valueAsScriptString(compilationUnit.data()).isEmpty());
+ QVERIFY(compilationUnit->bindingValueAsScriptString(binding).isEmpty());
break;
}
QVERIFY(i < rootObject->nBindings);
@@ -2481,7 +2563,15 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QCOMPARE(QString(object->metaObject()->className()), type);
+ const QMetaObject *meta = object->metaObject();
+ for (; meta; meta = meta->superClass()) {
+ const QString className(meta->className());
+ if (!className.contains("_QMLTYPE_") && !className.contains("_QML_")) {
+ QCOMPARE(className, type);
+ break;
+ }
+ }
+ QVERIFY(meta != nullptr);
}
engine.setImportPathList(defaultImportPathList);
@@ -2673,11 +2763,15 @@ void tst_qqmllanguage::importsLocal_data()
"Test {}"
<< (!qmlCheckTypes()?"TestType":"")
<< (!qmlCheckTypes()?"":"Test is ambiguous. Found in org/qtproject/Test/ and in subdir/");
- QTest::newRow("file URL survives percent-encoding")
- << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n"
- "Test {}"
- << "QQuickRectangle"
- << "";
+
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) {
+ // file URL doesn't work with qrc scheme
+ QTest::newRow("file URL survives percent-encoding")
+ << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n"
+ "Test {}"
+ << "QQuickRectangle"
+ << "";
+ }
}
void tst_qqmllanguage::importsLocal()
@@ -3436,7 +3530,11 @@ void tst_qqmllanguage::uncreatableTypesAsProperties()
void tst_qqmllanguage::initTestCase()
{
QQmlDataTest::initTestCase();
- QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory()));
+ if (dataDirectoryUrl().scheme() == QLatin1String("qrc"))
+ engine.addImportPath(dataDirectory());
+ else
+ QVERIFY2(QDir::setCurrent(dataDirectory()), qPrintable("Could not chdir to " + dataDirectory()));
+
defaultImportPathList = engine.importPathList();
@@ -3467,11 +3565,13 @@ void tst_qqmllanguage::initTestCase()
// For POSIX, this will just be data/I18nType.qml, since POSIX is 7-bit
// For iso8859-1 locale, this will just be data/I18nType?????.qml where ????? is 5 8-bit characters
// For utf-8 locale, this will be data/I18nType??????????.qml where ?????????? is 5 8-bit characters, UTF-8 encoded
- QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile());
- QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString())));
- QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile());
- QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString())));
- out.write(in.readAll());
+ if (dataDirectoryUrl().scheme() != QLatin1String("qrc")) {
+ QFile in(testFileUrl(QLatin1String("I18nType30.qml")).toLocalFile());
+ QVERIFY2(in.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(in.fileName(), in.errorString())));
+ QFile out(testFileUrl(QString::fromUtf8("I18nType\303\201\303\242\303\243\303\244\303\245.qml")).toLocalFile());
+ QVERIFY2(out.open(QIODevice::WriteOnly), qPrintable(QString::fromLatin1("Cannot open '%1': %2").arg(out.fileName(), out.errorString())));
+ out.write(in.readAll());
+ }
// Register a Composite Singleton.
qmlRegisterSingletonType(testFileUrl("singleton/RegisteredCompositeSingletonType.qml"), "org.qtproject.Test", 1, 0, "RegisteredSingleton");
@@ -3694,6 +3794,38 @@ void tst_qqmllanguage::signalParameterTypes()
QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
}
+
+ // dynamic signal connections
+ {
+ QQmlComponent component(&engine, testFileUrl("signalParameterTypes.3.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
+ QVERIFY(obj->property("success").toBool());
+ }
+}
+
+void tst_qqmllanguage::functionParameterTypes()
+{
+ QQmlComponent component(&engine, testFileUrl("functionParameterTypes.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(!obj.isNull(), qPrintable(component.errorString()));
+ const QMetaObject *metaObject = obj->metaObject();
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("returnItem()"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.returnType(), QMetaType::type("QObject*"));
+ QObject *returnedPtr = nullptr;
+ slot.invoke(obj.data(), Qt::DirectConnection, Q_RETURN_ARG(QObject*, returnedPtr));
+ QCOMPARE(returnedPtr, obj.data());
+ }
+
+ {
+ QMetaMethod slot = metaObject->method(metaObject->indexOfSlot("takeString(QString)"));
+ QVERIFY(slot.isValid());
+ QCOMPARE(slot.parameterCount(), 1);
+ QCOMPARE(slot.parameterType(0), int(QMetaType::QString));
+ }
}
// QTBUG-20639
@@ -3812,7 +3944,7 @@ void tst_qqmllanguage::scopedEnumsWithNameClash()
{
auto typeId = qmlRegisterUncreatableType<ScopedEnumsWithNameClash>("ScopedEnumsWithNameClashTest", 1, 0, "ScopedEnum", "Dummy reason");
auto registryGuard = qScopeGuard([typeId]() {
- qmlUnregisterType(typeId);
+ QQmlMetaType::unregisterType(typeId);
});
QQmlEngine engine;
@@ -3831,7 +3963,7 @@ void tst_qqmllanguage::scopedEnumsWithResolvedNameClash()
{
auto typeId = qmlRegisterUncreatableType<ScopedEnumsWithResolvedNameClash>("ScopedEnumsWithResolvedNameClashTest", 1, 0, "ScopedEnum", "Dummy reason");
auto registryGuard = qScopeGuard([typeId]() {
- qmlUnregisterType(typeId);
+ QQmlMetaType::unregisterType(typeId);
});
QQmlEngine engine;
@@ -3951,7 +4083,7 @@ void tst_qqmllanguage::objectDeletionNotify()
void tst_qqmllanguage::scopedProperties()
{
- QQmlComponent component(&engine, testFile("scopedProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("scopedProperties.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -3960,7 +4092,7 @@ void tst_qqmllanguage::scopedProperties()
void tst_qqmllanguage::deepProperty()
{
- QQmlComponent component(&engine, testFile("deepProperty.qml"));
+ QQmlComponent component(&engine, testFileUrl("deepProperty.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QFont font = qvariant_cast<QFont>(qvariant_cast<QObject*>(o->property("someObject"))->property("font"));
@@ -3978,14 +4110,16 @@ void tst_qqmllanguage::implicitImportsLast()
if (engine.importPathList() == defaultImportPathList)
engine.addImportPath(testFile("lib"));
- QQmlComponent component(&engine, testFile("localOrderTest.qml"));
+ QQmlComponent component(&engine, testFileUrl("localOrderTest.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QQuickMouseArea")));
+ QVERIFY(QString(object->metaObject()->superClass()->superClass()->className())
+ .startsWith(QLatin1String("QQuickMouseArea")));
QObject* object2 = object->property("item").value<QObject*>();
QVERIFY(object2 != nullptr);
- QCOMPARE(QString(object2->metaObject()->className()), QLatin1String("QQuickRectangle"));
+ QCOMPARE(QString(object2->metaObject()->superClass()->className()),
+ QLatin1String("QQuickRectangle"));
engine.setImportPathList(defaultImportPathList);
}
@@ -3998,7 +4132,7 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file
if (!fileName || !propertyName)
return;
- QQmlComponent component(&engine, testFile(fileName));
+ QQmlComponent component(&engine, testFileUrl(fileName));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -4040,7 +4174,7 @@ void verifyCompositeSingletonPropertyValues(QObject* o, const char* n1, int v1,
// Reads values from a composite singleton type
void tst_qqmllanguage::compositeSingletonProperties()
{
- QQmlComponent component(&engine, testFile("singletonTest1.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest1.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4087,14 +4221,14 @@ void tst_qqmllanguage::compositeSingletonDifferentEngine()
// pragma Singleton in a non-type qml file fails
void tst_qqmllanguage::compositeSingletonNonTypeError()
{
- QQmlComponent component(&engine, testFile("singletonTest4.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest4.qml"));
VERIFY_ERRORS("singletonTest4.error.txt");
}
// Loads the singleton using a namespace qualifier
void tst_qqmllanguage::compositeSingletonQualifiedNamespace()
{
- QQmlComponent component(&engine, testFile("singletonTest5.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest5.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4119,7 +4253,7 @@ void tst_qqmllanguage::compositeSingletonModule()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest6.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest6.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4145,7 +4279,7 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest7.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest7.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4171,7 +4305,7 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
{
engine.addImportPath(testFile("singleton/module"));
- QQmlComponent component(&engine, testFile("singletonTest8.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest8.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4195,27 +4329,46 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
// Tries to instantiate a type with a pragma Singleton and fails
void tst_qqmllanguage::compositeSingletonInstantiateError()
{
- QQmlComponent component(&engine, testFile("singletonTest9.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest9.qml"));
VERIFY_ERRORS("singletonTest9.error.txt");
}
// Having a composite singleton type as dynamic property type is allowed
void tst_qqmllanguage::compositeSingletonDynamicPropertyError()
{
- QQmlComponent component(&engine, testFile("singletonTest10.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest10.qml"));
VERIFY_ERRORS(0);
}
-// Having a composite singleton type as dynamic signal parameter succeeds
-// (like C++ singleton)
-void tst_qqmllanguage::compositeSingletonDynamicSignal()
+void tst_qqmllanguage::compositeSingletonDynamicSignalAndJavaScriptPragma()
{
- QQmlComponent component(&engine, testFile("singletonTest11.qml"));
- VERIFY_ERRORS(0);
- QScopedPointer<QObject> o(component.create());
- QVERIFY(o != nullptr);
+ {
+ // Having a composite singleton type as dynamic signal parameter succeeds
+ // (like C++ singleton)
- verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55);
+ QQmlComponent component(&engine, testFileUrl("singletonTest11.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
+
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55);
+ }
+ {
+ // Load a composite singleton type and a javascript file that has .pragma library
+ // in it. This will make sure that the javascript .pragma does not get mixed with
+ // the pragma Singleton changes.
+
+ QQmlComponent component(&engine, testFileUrl("singletonTest16.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
+
+ // The value1 that is read from the SingletonType was changed from 125 to 99
+ // above. As the type is a singleton and
+ // the engine has not been destroyed, we just retrieve the old instance and
+ // the value is still 99.
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333);
+ }
}
// Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it.
@@ -4224,21 +4377,21 @@ void tst_qqmllanguage::compositeSingletonQmlRegisterTypeError()
{
qmlRegisterType(testFileUrl("singleton/registeredComposite/CompositeType.qml"),
"CompositeSingletonTest", 1, 0, "RegisteredCompositeType");
- QQmlComponent component(&engine, testFile("singletonTest12.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest12.qml"));
VERIFY_ERRORS("singletonTest12.error.txt");
}
// Qmldir defines a type as a singleton, but the qml file does not have a pragma Singleton.
void tst_qqmllanguage::compositeSingletonQmldirNoPragmaError()
{
- QQmlComponent component(&engine, testFile("singletonTest13.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest13.qml"));
VERIFY_ERRORS("singletonTest13.error.txt");
}
// Invalid singleton definition in the qmldir file results in an error
void tst_qqmllanguage::compositeSingletonQmlDirError()
{
- QQmlComponent component(&engine, testFile("singletonTest14.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest14.qml"));
VERIFY_ERRORS("singletonTest14.error.txt");
}
@@ -4267,30 +4420,13 @@ void tst_qqmllanguage::compositeSingletonRemote()
verifyCompositeSingletonPropertyValues(o.data(), "value1", 525, "value2", 355);
}
-// Load a composite singleton type and a javascript file that has .pragma library
-// in it. This will make sure that the javascript .pragma does not get mixed with
-// the pragma Singleton changes.
-void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
-{
- QQmlComponent component(&engine, testFile("singletonTest16.qml"));
- VERIFY_ERRORS(0);
- QScopedPointer<QObject> o(component.create());
- QVERIFY(o != nullptr);
-
- // The value1 that is read from the SingletonType was changed from 125 to 99
- // in compositeSingletonDynamicSignal() above. As the type is a singleton and
- // the engine has not been destroyed, we just retrieve the old instance and
- // the value is still 99.
- verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333);
-}
-
// Reads values from a Singleton accessed through selectors.
void tst_qqmllanguage::compositeSingletonSelectors()
{
QQmlEngine e2;
QQmlFileSelector qmlSelector(&e2);
qmlSelector.setExtraSelectors(QStringList() << "basicSelector");
- QQmlComponent component(&e2, testFile("singletonTest1.qml"));
+ QQmlComponent component(&e2, testFileUrl("singletonTest1.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4302,7 +4438,7 @@ void tst_qqmllanguage::compositeSingletonSelectors()
// qmlRegisterSingletonType.
void tst_qqmllanguage::compositeSingletonRegistered()
{
- QQmlComponent component(&engine, testFile("singletonTest17.qml"));
+ QQmlComponent component(&engine, testFileUrl("singletonTest17.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4312,7 +4448,7 @@ void tst_qqmllanguage::compositeSingletonRegistered()
void tst_qqmllanguage::compositeSingletonCircular()
{
- QQmlComponent component(&engine, testFile("circularSingleton.qml"));
+ QQmlComponent component(&engine, testFileUrl("circularSingleton.qml"));
VERIFY_ERRORS(0);
QQmlTestMessageHandler messageHandler;
@@ -4346,7 +4482,7 @@ void tst_qqmllanguage::singletonsHaveContextAndEngine()
void tst_qqmllanguage::customParserBindingScopes()
{
- QQmlComponent component(&engine, testFile("customParserBindingScopes.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserBindingScopes.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4357,7 +4493,7 @@ void tst_qqmllanguage::customParserBindingScopes()
void tst_qqmllanguage::customParserEvaluateEnum()
{
- QQmlComponent component(&engine, testFile("customParserEvaluateEnum.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserEvaluateEnum.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4365,7 +4501,7 @@ void tst_qqmllanguage::customParserEvaluateEnum()
void tst_qqmllanguage::customParserProperties()
{
- QQmlComponent component(&engine, testFile("customParserProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("customParserProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4379,7 +4515,7 @@ void tst_qqmllanguage::customParserProperties()
void tst_qqmllanguage::customParserWithExtendedObject()
{
- QQmlComponent component(&engine, testFile("customExtendedParserProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("customExtendedParserProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4397,7 +4533,7 @@ void tst_qqmllanguage::customParserWithExtendedObject()
void tst_qqmllanguage::nestedCustomParsers()
{
- QQmlComponent component(&engine, testFile("nestedCustomParsers.qml"));
+ QQmlComponent component(&engine, testFileUrl("nestedCustomParsers.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4411,7 +4547,7 @@ void tst_qqmllanguage::nestedCustomParsers()
void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
{
- QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml"));
+ QQmlComponent component(&engine, testFileUrl("preservePropertyCacheOnGroupObjects.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4430,7 +4566,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
void tst_qqmllanguage::propertyCacheInSync()
{
- QQmlComponent component(&engine, testFile("propertyCacheInSync.qml"));
+ QQmlComponent component(&engine, testFileUrl("propertyCacheInSync.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4450,7 +4586,7 @@ void tst_qqmllanguage::propertyCacheInSync()
void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
{
- QQmlComponent component(&engine, testFile("rootObjectInCreationNotForSubObjects.qml"));
+ QQmlComponent component(&engine, testFileUrl("rootObjectInCreationNotForSubObjects.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -4476,7 +4612,7 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
// QTBUG-63036
void tst_qqmllanguage::lazyDeferredSubObject()
{
- QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml"));
+ QQmlComponent component(&engine, testFileUrl("lazyDeferredSubObject.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4491,7 +4627,7 @@ void tst_qqmllanguage::lazyDeferredSubObject()
// QTBUG-63200
void tst_qqmllanguage::deferredProperties()
{
- QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4608,7 +4744,7 @@ static void testExecuteDeferredOnce(const QQmlProperty &property)
void tst_qqmllanguage::executeDeferredPropertiesOnce()
{
- QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4708,7 +4844,7 @@ void tst_qqmllanguage::deleteSingletons()
QPointer<QObject> singleton;
{
QQmlEngine tmpEngine;
- QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml"));
+ QQmlComponent component(&tmpEngine, testFileUrl("singletonTest5.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -4735,7 +4871,7 @@ void tst_qqmllanguage::arrayBuffer_data()
void tst_qqmllanguage::arrayBuffer()
{
QFETCH(QString, file);
- QQmlComponent component(&engine, testFile(file));
+ QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(0);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -4969,7 +5105,6 @@ void tst_qqmllanguage::instanceof()
if (QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomRectangle") ||
QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle"))
- QEXPECT_FAIL("", "QTBUG-58477: QML type rules are a little lax", Continue);
QCOMPARE(returnValue, expectedValue.toBool());
} else {
QVERIFY(expr.hasError());
@@ -5005,7 +5140,8 @@ void tst_qqmllanguage::accessDeletedObject()
{
QQmlEngine engine;
- engine.rootContext()->setContextProperty("objectCreator", new ObjectCreator);
+ QScopedPointer<ObjectCreator> creator(new ObjectCreator);
+ engine.rootContext()->setContextProperty("objectCreator", creator.get());
QQmlComponent component(&engine, testFileUrl("accessDeletedObject.qml"));
VERIFY_ERRORS(0);
diff --git a/tests/auto/qml/qqmllistcompositor/qqmllistcompositor.pro b/tests/auto/qml/qqmllistcompositor/qqmllistcompositor.pro
index 4ada590a2a..62ad85547e 100644
--- a/tests/auto/qml/qqmllistcompositor/qqmllistcompositor.pro
+++ b/tests/auto/qml/qqmllistcompositor/qqmllistcompositor.pro
@@ -4,4 +4,4 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmllistcompositor.cpp
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro b/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
index 8e3aed0baf..4d44d6b22b 100644
--- a/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
+++ b/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
@@ -8,4 +8,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index 771f3e5c4e..75a932b6f4 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -30,7 +30,7 @@
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickanimation_p.h>
#include <QtQml/private/qqmlengine_p.h>
-#include <QtQml/private/qqmllistmodel_p.h>
+#include <QtQmlModels/private/qqmllistmodel_p.h>
#include <QtQml/private/qqmlexpression_p.h>
#include <QQmlComponent>
@@ -128,6 +128,8 @@ private slots:
void qobjectTrackerForDynamicModelObjects();
void crash_append_empty_array();
void dynamic_roles_crash_QTBUG_38907();
+ void nestedListModelIteration();
+ void undefinedAppendShouldCauseError();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -760,11 +762,11 @@ void tst_qqmllistmodel::set()
RUNEXPR("model.set(0, {test:true})");
QCOMPARE(RUNEXPR("model.get(0).test").toBool(), true); // triggers creation of model cache
- QCOMPARE(model.data(0, 0), qVariantFromValue(true));
+ QCOMPARE(model.data(0, 0), QVariant::fromValue(true));
RUNEXPR("model.set(0, {test:false})");
QCOMPARE(RUNEXPR("model.get(0).test").toBool(), false); // tests model cache is updated
- QCOMPARE(model.data(0, 0), qVariantFromValue(false));
+ QCOMPARE(model.data(0, 0), QVariant::fromValue(false));
QString warning = QString::fromLatin1("<Unknown File>: Can't create role for unsupported data type");
if (isValidErrorMessage(warning, dynamicRoles))
@@ -1667,6 +1669,61 @@ void tst_qqmllistmodel::dynamic_roles_crash_QTBUG_38907()
QVERIFY(retVal.toBool());
}
+void tst_qqmllistmodel::nestedListModelIteration()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg ,R"({"subItems":[{"a":1,"b":0,"c":0},{"a":0,"b":2,"c":0},{"a":0,"b":0,"c":3}]})");
+ component.setData(
+ R"(import QtQuick 2.5
+ Item {
+ visible: true
+ width: 640
+ height: 480
+ ListModel {
+ id : model
+ }
+ Component.onCompleted: {
+ var tempData = {
+ subItems: [{a: 1}, {b: 2}, {c: 3}]
+ }
+ model.insert(0, tempData)
+ console.log(JSON.stringify(model.get(0)))
+ }
+ })",
+ QUrl());
+ QScopedPointer<QObject>(component.create());
+}
+
+// QTBUG-63569
+void tst_qqmllistmodel::undefinedAppendShouldCauseError()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ R"(import QtQuick 2.5
+ Item {
+ width: 640
+ height: 480
+ ListModel {
+ id : model
+ }
+ Component.onCompleted: {
+ var tempData = {
+ faulty: undefined
+ }
+ model.insert(0, tempData)
+ tempData.faulty = null
+ model.insert(0, tempData)
+ }
+ })",
+ QUrl());
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: faulty is undefined. Adding an object with a undefined member does not create a role for it.");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "<Unknown File>: faulty is null. Adding an object with a null member does not create a role for it.");
+ QScopedPointer<QObject>(component.create());
+}
+
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmllistmodelworkerscript/qqmllistmodelworkerscript.pro b/tests/auto/qml/qqmllistmodelworkerscript/qqmllistmodelworkerscript.pro
index 9e1cea9867..de58c0c075 100644
--- a/tests/auto/qml/qqmllistmodelworkerscript/qqmllistmodelworkerscript.pro
+++ b/tests/auto/qml/qqmllistmodelworkerscript/qqmllistmodelworkerscript.pro
@@ -8,4 +8,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
index 21b0508e4d..b5e8800d0e 100644
--- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
+++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
@@ -29,7 +29,7 @@
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQml/private/qqmlengine_p.h>
-#include <QtQml/private/qqmllistmodel_p.h>
+#include <QtQmlModels/private/qqmllistmodel_p.h>
#include <QtQml/private/qqmlexpression_p.h>
#include <QQmlComponent>
@@ -162,7 +162,7 @@ QQuickItem *tst_qqmllistmodelworkerscript::createWorkerTest(QQmlEngine *eng, QQm
QQuickItem *item = qobject_cast<QQuickItem*>(component->create());
QQmlEngine::setContextForObject(model, eng->rootContext());
if (item)
- item->setProperty("model", qVariantFromValue(model));
+ item->setProperty("model", QVariant::fromValue(model));
return item;
}
diff --git a/tests/auto/qml/qqmllocale/data/localeAsCppProperty.qml b/tests/auto/qml/qqmllocale/data/localeAsCppProperty.qml
new file mode 100644
index 0000000000..ff80f3cf85
--- /dev/null
+++ b/tests/auto/qml/qqmllocale/data/localeAsCppProperty.qml
@@ -0,0 +1,6 @@
+import QtQml 2.2
+import Test 1.0
+Calendar {
+ locale: Qt.locale('en_GB')
+ property var testLocale
+}
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index eb6eb62648..a90749208c 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -32,6 +32,8 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtCore/QDateTime>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qscopedpointer.h>
#include <qcolor.h>
#include "../../shared/util.h"
@@ -1214,10 +1216,9 @@ private:
void tst_qqmllocale::localeAsCppProperty()
{
- QQmlComponent component(&engine);
qmlRegisterType<Calendar>("Test", 1, 0, "Calendar");
- component.setData("import QtQml 2.2\nimport Test 1.0\nCalendar { locale: Qt.locale('en_GB'); property var testLocale }", QUrl());
- QVERIFY(!component.isError());
+ QQmlComponent component(&engine, testFileUrl("localeAsCppProperty.qml"));
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
QTRY_VERIFY(component.isReady());
Calendar *item = qobject_cast<Calendar*>(component.create());
@@ -1271,13 +1272,21 @@ void tst_qqmllocale::timeZoneUpdated()
// Set the timezone to Brisbane time, AEST-10:00
setTimeZone(QByteArray("Australia/Brisbane"));
+ QScopedPointer<QObject> obj;
+ auto cleanup = qScopeGuard([&original, &obj] {
+ // Restore to original time zone
+ setTimeZone(original);
+ QMetaObject::invokeMethod(obj.data(), "resetTimeZone");
+ });
+
DateFormatter formatter;
QQmlEngine e;
e.rootContext()->setContextObject(&formatter);
QQmlComponent c(&e, testFileUrl("timeZoneUpdated.qml"));
- QScopedPointer<QObject> obj(c.create());
+ QVERIFY2(!c.isError(), qPrintable(c.errorString()));
+ obj.reset(c.create());
QVERIFY(obj);
QVERIFY(obj->property("success").toBool());
@@ -1285,11 +1294,6 @@ void tst_qqmllocale::timeZoneUpdated()
setTimeZone(QByteArray("Asia/Kolkata"));
QMetaObject::invokeMethod(obj.data(), "check");
-
- // Reset to original time
- setTimeZone(original);
- QMetaObject::invokeMethod(obj.data(), "resetTimeZone");
-
QVERIFY(obj->property("success").toBool());
}
#endif
diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
index a7805922a5..76185a97e0 100644
--- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
+++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
@@ -36,7 +36,6 @@
#include <private/qqmlmetatype_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qhashedstring_p.h>
#include "../../shared/util.h"
class tst_qqmlmetatype : public QQmlDataTest
@@ -401,7 +400,7 @@ void tst_qqmlmetatype::unregisterCustomType()
QCOMPARE(enumVal.type(), QVariant::Int);
QCOMPARE(enumVal.toInt(), 1);
}
- qmlUnregisterType(controllerId);
+ QQmlMetaType::unregisterType(controllerId);
{
QQmlEngine engine;
QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
@@ -424,7 +423,7 @@ void tst_qqmlmetatype::unregisterCustomType()
QCOMPARE(enumVal.type(), QVariant::Int);
QCOMPARE(enumVal.toInt(), 111);
}
- qmlUnregisterType(controllerId);
+ QQmlMetaType::unregisterType(controllerId);
{
QQmlEngine engine;
QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
@@ -493,7 +492,7 @@ void tst_qqmlmetatype::unregisterCustomSingletonType()
QCOMPARE(stringVal.type(), QVariant::String);
QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #1"));
}
- qmlUnregisterType(staticProviderId);
+ QQmlMetaType::unregisterType(staticProviderId);
{
QQmlEngine engine;
staticProviderId = qmlRegisterSingletonType<StaticProvider2>("mytypes", 1, 0, "StaticProvider", createStaticProvider2);
@@ -509,7 +508,7 @@ void tst_qqmlmetatype::unregisterCustomSingletonType()
QCOMPARE(stringVal.type(), QVariant::String);
QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #2"));
}
- qmlUnregisterType(staticProviderId);
+ QQmlMetaType::unregisterType(staticProviderId);
{
QQmlEngine engine;
staticProviderId = qmlRegisterSingletonType<StaticProvider1>("mytypes", 1, 0, "StaticProvider", createStaticProvider1);
@@ -535,7 +534,7 @@ void tst_qqmlmetatype::normalizeUrls()
QVERIFY(QQmlMetaType::qmlType(url, /*includeNonFileImports=*/true).isValid());
QUrl normalizedURL("qrc:/tstqqmlmetatype/data/CompositeType.qml");
QVERIFY(QQmlMetaType::qmlType(normalizedURL, /*includeNonFileImports=*/true).isValid());
- qmlUnregisterType(registrationId);
+ QQmlMetaType::unregisterType(registrationId);
QVERIFY(!QQmlMetaType::qmlType(url, /*includeNonFileImports=*/true).isValid());
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/data/multiSingleton.qml b/tests/auto/qml/qqmlmoduleplugin/data/multiSingleton.qml
new file mode 100644
index 0000000000..2fc2e9f076
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/data/multiSingleton.qml
@@ -0,0 +1,6 @@
+import org.qtproject.ModuleWithQmlSingleton 1.0
+import QtQuick 2.0
+
+Item {
+ Component.onCompleted: MySingleton
+}
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml
new file mode 100644
index 0000000000..9789be8191
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton.qml
@@ -0,0 +1,16 @@
+pragma Singleton
+import QtQuick 2.0
+
+QtObject {
+ property Loader _loader: Loader {
+ source: "internal/InternalType.qml"
+ }
+
+ Component.onCompleted: {
+ if (tracker.objectName === "first")
+ tracker.objectName = "second"
+ else
+ tracker.objectName = "first"
+ //console.log("created singleton", this)
+ }
+}
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton2.qml b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton2.qml
new file mode 100644
index 0000000000..9be34eb061
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/MySingleton2.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQuick 2.0
+import org.qtproject.ModuleWithQmlSingleton 1.0
+import "."
+
+QtObject {}
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/internal/InternalType.qml b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/internal/InternalType.qml
new file mode 100644
index 0000000000..4a8badefd2
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/internal/InternalType.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import ".."
+
+QtObject {
+ Component.onCompleted: MySingleton
+}
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/moduleWithQmlSingleton.pro b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/moduleWithQmlSingleton.pro
new file mode 100644
index 0000000000..b16e0743c8
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/moduleWithQmlSingleton.pro
@@ -0,0 +1,18 @@
+TEMPLATE = lib
+CONFIG += plugin
+SOURCES = plugin.cpp
+QT = core qml
+DESTDIR = ../imports/org/qtproject/ModuleWithQmlSingleton
+
+QT += core-private gui-private qml-private
+
+IMPORT_FILES = \
+ qmldir \
+ MySingleton.qml \
+ MySingleton2.qml
+
+include (../../../shared/imports.pri)
+
+subfiles.files = internal/InternalType.qml
+subfiles.path = $$DESTDIR/internal
+COPIES += subfiles
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/plugin.cpp
new file mode 100644
index 0000000000..6329927c34
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/plugin.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+#include <QDir>
+#include <QDebug>
+
+class MyPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ MyPlugin() {}
+
+ void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == "org.qtproject.ModuleWithQmlSingleton");
+ qmlRegisterSingletonType(baseUrl().resolved(QUrl("ModuleWithQmlSingleton/MySingleton.qml")), uri, 1, 0, "MySingleton");
+ qmlRegisterSingletonType(baseUrl().resolved(QUrl("ModuleWithQmlSingleton/MySingleton2.qml")), uri, 1, 0, "MySingleton2");
+ }
+};
+
+#include "plugin.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/qmldir b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/qmldir
new file mode 100644
index 0000000000..3483f80ab1
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithQmlSingleton/qmldir
@@ -0,0 +1,2 @@
+module org.qtproject.ModuleWithQmlSingleton
+plugin moduleWithQmlSingleton
diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
index ae13a041cc..44b3ab14e6 100644
--- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
@@ -20,7 +20,8 @@ SUBDIRS =\
plugin/childplugin\
plugin.2/childplugin\
plugin.2.1/childplugin\
- plugin.2.2
+ plugin.2.2\
+ moduleWithQmlSingleton
tst_qqmlmoduleplugin_pro.depends += plugin
SUBDIRS += tst_qqmlmoduleplugin.pro
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index 97ca3fa1de..f89cc9f24a 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -78,6 +78,7 @@ private slots:
void importsChildPlugin2();
void importsChildPlugin21();
void parallelPluginImport();
+ void multiSingleton();
private:
QString m_importsDirectory;
@@ -99,7 +100,7 @@ public:
qmlRegisterModule(uri, 1, 0);
}
- void initializeEngine(QQmlEngine *engine, const char *uri) override
+ void initializeEngine(QQmlEngine *, const char *) override
{
initializeEngineEntered.lock();
leavingInitializeEngine.lock();
@@ -772,6 +773,20 @@ void tst_qqmlmoduleplugin::parallelPluginImport()
worker.wait();
}
+void tst_qqmlmoduleplugin::multiSingleton()
+{
+ QQmlEngine engine;
+ QObject obj;
+ engine.rootContext()->setContextProperty("tracker", &obj);
+ engine.addImportPath(m_importsDirectory);
+ QQmlComponent component(&engine, testFileUrl("multiSingleton.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != nullptr);
+ QCOMPARE(obj.objectName(), QLatin1String("first"));
+ delete object;
+}
+
+
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"
diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
index a5332c8860..de762d66c5 100644
--- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
+++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
@@ -342,6 +342,9 @@ void tst_qqmlnotifier::lotsOfBindings()
void tst_qqmlnotifier::deleteFromHandler()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Android seems to have problems with QProcess");
+#endif
#if !QT_CONFIG(process)
QSKIP("Need QProcess support to test qFatal.");
#else
diff --git a/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro b/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro
index 88bb630e29..5746ff754a 100644
--- a/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro
+++ b/tests/auto/qml/qqmlobjectmodel/qqmlobjectmodel.pro
@@ -5,4 +5,4 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qqmlobjectmodel.cpp
QT += qml testlib
-QT += core-private qml-private
+QT += core-private qml-private qmlmodels-private
diff --git a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
index fb63d811a8..6691fa43a0 100644
--- a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
+++ b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
@@ -25,8 +25,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <QtQml/private/qqmlobjectmodel_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlobjectmodel_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtTest/qsignalspy.h>
#include <QtTest/qtest.h>
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js
new file mode 100644
index 0000000000..f660edb69e
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/anonfunctionexpr.js
@@ -0,0 +1,3 @@
+(function () : string {
+ return "ko"
+})
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js
new file mode 100644
index 0000000000..ab85d90880
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classmemberparam.js
@@ -0,0 +1,6 @@
+
+class Foo {
+ member(param: string) {
+ return "ko"
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js
new file mode 100644
index 0000000000..a7da9e0ca7
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/classreturnvalue.js
@@ -0,0 +1,6 @@
+
+class Foo {
+ member(): string {
+ return "ko"
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js
new file mode 100644
index 0000000000..4d6021e835
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/function.js
@@ -0,0 +1,4 @@
+
+function x() : string {
+ return "ok"
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js
new file mode 100644
index 0000000000..33f2abbb61
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionexpr.js
@@ -0,0 +1,3 @@
+(function x() : string {
+ return "ko"
+})
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js
new file mode 100644
index 0000000000..2c23628e3f
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/functionparams.js
@@ -0,0 +1,3 @@
+
+function test(x: string, y: string) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js
new file mode 100644
index 0000000000..a6cc00e38a
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration.js
@@ -0,0 +1,3 @@
+
+for (var i: int = 0; i < 100; ++i) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js
new file mode 100644
index 0000000000..24d5acce98
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/iteration2.js
@@ -0,0 +1,5 @@
+
+let y = [1, 2, 3];
+
+for (let x: int of y) {
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml
new file mode 100644
index 0000000000..f435bf1b25
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/qmlnestedfunction.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.12 as MyQuick
+MyQuick.Item {
+ function factory(param: string) : MyQuick.Item {
+ function nested(foo: string) {
+ return this
+ }
+ return nested()
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js
new file mode 100644
index 0000000000..bf332ac7a8
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/disallowedtypeannotations/variables.js
@@ -0,0 +1,2 @@
+
+var x: string = "ko"
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml
new file mode 100644
index 0000000000..79a9ede3d4
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_bool.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : bool { return true; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml
new file mode 100644
index 0000000000..f58e4b92d9
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_double.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : double { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml
new file mode 100644
index 0000000000..267ad7191f
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_int.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : int { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml
new file mode 100644
index 0000000000..9973819ad2
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_real.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test() : real { return 0; }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml
new file mode 100644
index 0000000000..e632ec7154
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_string.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test(s: string) {}
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml
new file mode 100644
index 0000000000..ebf3f32561
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/basic_qmltypes_url.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ function test(u: url) {}
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml b/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml
new file mode 100644
index 0000000000..d80b5e3f87
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/parametrized.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0 as MyQuick
+MyQuick.Item {
+ function factory() : list<MyQuick.Item> {
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml b/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml
new file mode 100644
index 0000000000..cd5c1f51e5
--- /dev/null
+++ b/tests/auto/qml/qqmlparser/data/typeannotations/qmlfunction.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.12 as MyQuick
+MyQuick.Item {
+ function factory(param: string) : MyQuick.Item {
+ return this
+ }
+}
diff --git a/tests/auto/qml/qqmlparser/qqmlparser.pro b/tests/auto/qml/qqmlparser/qqmlparser.pro
index 74cb620f06..d8e4b0dd06 100644
--- a/tests/auto/qml/qqmlparser/qqmlparser.pro
+++ b/tests/auto/qml/qqmlparser/qqmlparser.pro
@@ -7,3 +7,7 @@ SOURCES += tst_qqmlparser.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\"
cross_compile: DEFINES += QTEST_CROSS_COMPILED
+
+TESTDATA = data/*
+
+include (../../shared/util.pri)
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index f16e96a385..9d8818d01e 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -32,12 +32,14 @@
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
+#include "../../shared/util.h"
+
#include <qtest.h>
#include <QDir>
#include <QDebug>
#include <cstdlib>
-class tst_qqmlparser : public QObject
+class tst_qqmlparser : public QQmlDataTest
{
Q_OBJECT
public:
@@ -55,6 +57,11 @@ private slots:
void templateLiteral();
void leadingSemicolonInClass();
void templatedReadonlyProperty();
+ void qmlImportInJSRequiresFullVersion();
+ void typeAnnotations_data();
+ void typeAnnotations();
+ void disallowedTypeAnnotations_data();
+ void disallowedTypeAnnotations();
private:
QStringList excludedDirs;
@@ -87,7 +94,7 @@ public:
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
+ qDebug() << "last 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);
@@ -113,6 +120,27 @@ public:
}
};
+struct TypeAnnotationObserver: public AST::Visitor
+{
+ bool typeAnnotationSeen = false;
+
+ void operator()(AST::Node *node)
+ {
+ AST::Node::accept(node, this);
+ }
+
+ virtual bool visit(AST::TypeAnnotation *)
+ {
+ typeAnnotationSeen = true;
+ return true;
+ }
+
+ void throwRecursionDepthError() final
+ {
+ QFAIL("Maximum statement or expression depth exceeded");
+ }
+};
+
}
tst_qqmlparser::tst_qqmlparser()
@@ -121,6 +149,7 @@ tst_qqmlparser::tst_qqmlparser()
void tst_qqmlparser::initTestCase()
{
+ QQmlDataTest::initTestCase();
// Add directories you want excluded here
// These snippets are not expected to run on their own.
@@ -299,6 +328,116 @@ void tst_qqmlparser::templatedReadonlyProperty()
QVERIFY(parser.parse());
}
+void tst_qqmlparser::qmlImportInJSRequiresFullVersion()
+{
+ {
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String(".import Test 1.0 as T"), 0, false);
+ QQmlJS::Parser parser(&engine);
+ bool b = parser.parseProgram();
+ qDebug() << parser.errorMessage();
+ QVERIFY(b);
+ }
+ {
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String(".import Test 1 as T"), 0, false);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(!parser.parseProgram());
+ }
+ {
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String(".import Test 1 as T"), 0, false);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(!parser.parseProgram());
+ }
+ {
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String(".import Test as T"), 0, false);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(!parser.parseProgram());
+ }
+}
+
+void tst_qqmlparser::typeAnnotations_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QString tests = dataDirectory() + "/typeannotations/";
+
+ QStringList files;
+ files << findFiles(QDir(tests));
+
+ for (const QString &file: qAsConst(files))
+ QTest::newRow(qPrintable(file)) << file;
+}
+
+void tst_qqmlparser::typeAnnotations()
+{
+ using namespace QQmlJS;
+
+ QFETCH(QString, file);
+
+ 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();
+ QVERIFY(ok);
+
+ check::TypeAnnotationObserver observer;
+ observer(parser.rootNode());
+
+ QVERIFY(observer.typeAnnotationSeen);
+}
+
+void tst_qqmlparser::disallowedTypeAnnotations_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QString tests = dataDirectory() + "/disallowedtypeannotations/";
+
+ QStringList files;
+ files << findFiles(QDir(tests));
+
+ for (const QString &file: qAsConst(files))
+ QTest::newRow(qPrintable(file)) << file;
+}
+
+void tst_qqmlparser::disallowedTypeAnnotations()
+{
+ using namespace QQmlJS;
+
+ QFETCH(QString, file);
+
+ 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();
+ QVERIFY(!ok);
+ QVERIFY2(parser.errorMessage().startsWith("Type annotations are not permitted "), qPrintable(parser.errorMessage()));
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml
new file mode 100644
index 0000000000..4e72a75f42
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+import io.qt.bugreports 1.0
+Item {
+ InterfaceConsumer {
+ objectName: "a1"
+ i: A {
+ property int i: 42
+ }
+ }
+
+ InterfaceConsumer {
+ objectName: "a2"
+ property A a: A {
+ property int i: 43
+ }
+ i: a
+ }
+
+ InterfaceConsumer {
+ objectName: "a3"
+ property A a: A {
+ id : aa
+ property int i: 44
+ }
+ i: aa
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/data/nullPropertyBinding.qml b/tests/auto/qml/qqmlproperty/data/nullPropertyBinding.qml
new file mode 100644
index 0000000000..4fffc7aead
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/nullPropertyBinding.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.12
+
+Item {
+ id: root
+
+ width: 640
+ height: 480
+
+ property bool toggle: false
+ property Item bound
+ property string message: "defined"
+
+ readonly property Item item: root.toggle ? root : null
+
+ Binding { target: root; property: "bound"; value: item}
+
+ function tog() {
+ console.info(root.bound ? root.bound.message: "undefined")
+ root.toggle = !root.toggle
+ return 42;
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index ed213cd01a..a15c00ad62 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -35,8 +35,12 @@
#include <private/qqmlboundsignal_p.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
#include <QtCore/private/qobject_p.h>
#include "../../shared/util.h"
+#include "qobject.h"
#include <QtQml/QQmlPropertyMap>
#include <QDebug>
@@ -145,6 +149,8 @@ private slots:
void deeplyNestedObject();
void readOnlyDynamicProperties();
void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem();
+ void nullPropertyBinding();
+ void interfaceBinding();
void floatToStringPrecision_data();
void floatToStringPrecision();
@@ -1627,7 +1633,7 @@ void tst_qqmlproperty::writeObjectToList()
MyQmlObject *object = new MyQmlObject;
QQmlProperty prop(container, "children");
- prop.write(qVariantFromValue(object));
+ prop.write(QVariant::fromValue(object));
QCOMPARE(list.count(), 1);
QCOMPARE(list.at(0), qobject_cast<QObject*>(object));
}
@@ -1644,13 +1650,13 @@ void tst_qqmlproperty::writeListToList()
QList<QObject*> objList;
objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject();
QQmlProperty prop(container, "children");
- prop.write(qVariantFromValue(objList));
+ prop.write(QVariant::fromValue(objList));
QCOMPARE(list.count(), 4);
//XXX need to try this with read/write prop (for read-only it correctly doesn't write)
/*QList<MyQmlObject*> typedObjList;
typedObjList << new MyQmlObject();
- prop.write(qVariantFromValue(&typedObjList));
+ prop.write(QVariant::fromValue(&typedObjList));
QCOMPARE(container->children()->size(), 1);*/
}
@@ -2017,9 +2023,13 @@ void tst_qqmlproperty::warnOnInvalidBinding()
expectedWarning = testUrl.toString() + QString::fromLatin1(":7:5: Unable to assign QQuickText to QQuickRectangle");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
+#if QT_CONFIG(regularexpression)
// V8 error message for invalid binding to anchor
- expectedWarning = testUrl.toString() + QString::fromLatin1(":14:9: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
- QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
+ const QRegularExpression warning(
+ "^" + testUrl.toString()
+ + ":14:9: Unable to assign QQuickItem_QML_\\d+ to QQuickAnchorLine$");
+ QTest::ignoreMessage(QtWarningMsg, warning);
+#endif
QQmlComponent component(&engine, testUrl);
QObject *obj = component.create();
@@ -2062,6 +2072,99 @@ void tst_qqmlproperty::aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSyst
QVERIFY(property.isValid());
}
+// QTBUG-77027
+void tst_qqmlproperty::nullPropertyBinding()
+{
+ const QUrl url = testFileUrl("nullPropertyBinding.qml");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, url);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "undefined");
+ QMetaObject::invokeMethod(root.get(), "tog");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "defined");
+ QMetaObject::invokeMethod(root.get(), "tog");
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "undefined");
+ QMetaObject::invokeMethod(root.get(), "tog");
+}
+
+struct Interface {
+};
+
+QT_BEGIN_NAMESPACE
+#define MyInterface_iid "io.qt.bugreports.Interface"
+Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
+QT_END_NAMESPACE
+
+class A : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class B : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class C : public QObject {
+ Q_OBJECT
+};
+
+class InterfaceConsumer : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged)
+ Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
+
+
+public:
+
+ Interface* interface() const
+ {
+ return m_interface;
+ }
+ void setInterface(Interface* interface)
+ {
+ QObject* object = reinterpret_cast<QObject*>(interface);
+ m_testValue = object->property("i").toInt();
+ emit testValueChanged();
+ if (m_interface == interface)
+ return;
+
+ m_interface = interface;
+ emit interfaceChanged();
+ }
+
+ int testValue() {
+ return m_testValue;
+ }
+
+signals:
+ void interfaceChanged();
+ void testValueChanged();
+
+private:
+ Interface* m_interface = nullptr;
+ int m_testValue = 0;
+};
+void tst_qqmlproperty::interfaceBinding()
+{
+
+ qmlRegisterInterface<Interface>("Interface");
+ qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
+ qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
+ qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
+ qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
+
+ const QUrl url = testFileUrl("interfaceBinding.qml");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, url);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->findChild<QObject*>("a1")->property("testValue").toInt(), 42);
+ QCOMPARE(root->findChild<QObject*>("a2")->property("testValue").toInt(), 43);
+ QCOMPARE(root->findChild<QObject*>("a3")->property("testValue").toInt(), 44);
+}
+
void tst_qqmlproperty::floatToStringPrecision_data()
{
QTest::addColumn<QString>("propertyName");
diff --git a/tests/auto/qml/qqmlpropertycache/data/SpecialObject1.qml b/tests/auto/qml/qqmlpropertycache/data/SpecialObject1.qml
new file mode 100644
index 0000000000..9559bc0b5f
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertycache/data/SpecialObject1.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ readonly property bool fakeProperty: false
+}
diff --git a/tests/auto/qml/qqmlpropertycache/data/SpecialObject2.qml b/tests/auto/qml/qqmlpropertycache/data/SpecialObject2.qml
new file mode 100644
index 0000000000..ed4ad04fef
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertycache/data/SpecialObject2.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ objectName: "special"
+}
diff --git a/tests/auto/qml/qqmlpropertycache/data/noDuckType.qml b/tests/auto/qml/qqmlpropertycache/data/noDuckType.qml
new file mode 100644
index 0000000000..5e1ea233b9
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertycache/data/noDuckType.qml
@@ -0,0 +1,7 @@
+import QtQml 2.9
+
+QtObject {
+ property SpecialObject1 obj1: SpecialObject1 {}
+ property SpecialObject2 obj2: SpecialObject2 {}
+ property string result: (obj1 instanceof SpecialObject2) ? "bad" : "good"
+}
diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
index 02b5302a45..c9e92cd3c9 100644
--- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
+++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
@@ -31,7 +31,6 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlcomponent.h>
-#include <private/qv8engine_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <QCryptographicHash>
#include "../../shared/util.h"
@@ -55,6 +54,7 @@ private slots:
void metaObjectSize_data();
void metaObjectSize();
void metaObjectChecksum();
+ void metaObjectsForRootElements();
private:
QQmlEngine engine;
@@ -544,4 +544,14 @@ void tst_qqmlpropertycache::metaObjectChecksum()
}
}
+void tst_qqmlpropertycache::metaObjectsForRootElements()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("noDuckType.qml"));
+ QVERIFY(c.isReady());
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("result").toString(), QString::fromLatin1("good"));
+}
+
QTEST_MAIN(tst_qqmlpropertycache)
diff --git a/tests/auto/qml/qqmlpropertymap/dummy_imports.qml b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml
new file mode 100644
index 0000000000..4ae9d3f2cf
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
index 8da300171d..b83e1e0da2 100644
--- a/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
+++ b/tests/auto/qml/qqmlpropertymap/qqmlpropertymap.pro
@@ -7,3 +7,5 @@ SOURCES += tst_qqmlpropertymap.cpp
include (../../shared/util.pri)
QT += core-private gui-private qml-private quick-private testlib
+
+TESTDATA = data/*
diff --git a/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml
new file mode 100644
index 0000000000..4ae9d3f2cf
--- /dev/null
+++ b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml
@@ -0,0 +1,8 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
index 68ed22c01c..a6f0d65453 100644
--- a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
+++ b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
@@ -78,7 +78,7 @@ void tst_qqmlstatemachine::tst_cppObjectSignal()
CppObject cppObject;
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("cppsignal.qml"));
- QVERIFY(!component.isError());
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("_cppObject", &cppObject);
diff --git a/tests/auto/qml/qqmltablemodel/data/TestModel.qml b/tests/auto/qml/qqmltablemodel/data/TestModel.qml
new file mode 100644
index 0000000000..00e1fa65a7
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/TestModel.qml
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import Qt.labs.qmlmodels 1.0
+
+import "TestUtils.js" as TestUtils
+
+TableModel {
+ id: testModel
+ objectName: "testModel"
+
+ TableModelColumn { display: "name" }
+ TableModelColumn { display: "age" }
+
+ rows: [
+ {
+ name: "John",
+ age: 22
+ },
+ {
+ name: "Oliver",
+ age: 33
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/TestUtils.js b/tests/auto/qml/qqmltablemodel/data/TestUtils.js
new file mode 100644
index 0000000000..0b92a377bb
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/TestUtils.js
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+function testModelRoleDataProvider(index, role, cellData) {
+ switch (role) {
+ case "display":
+ switch (index.column) {
+ case 0:
+ return cellData.name
+ case 1:
+ return cellData.age
+ }
+ break
+ case "name":
+ return cellData.name
+ case "age":
+ return cellData.age
+ }
+ return cellData
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/common.qml b/tests/auto/qml/qqmltablemodel/data/common.qml
new file mode 100644
index 0000000000..2f8b0c072b
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/common.qml
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.13
+import Qt.labs.qmlmodels 1.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ property alias testModel: testModel
+ property alias tableView: tableView
+
+ function appendRow(personName, personAge) {
+ testModel.appendRow({
+ name: personName,
+ age: personAge
+ })
+ }
+
+ function appendRowExtraData() {
+ testModel.appendRow({
+ name: "Foo",
+ age: 99,
+ nonExistentRole: 123
+ })
+ }
+
+ function appendRowInvalid1() {
+ testModel.appendRow(123)
+ }
+
+ function appendRowInvalid2() {
+ testModel.appendRow({
+ name: "Foo",
+ age: []
+ })
+ }
+
+ function appendRowInvalid3() {
+ testModel.appendRow([
+ { name: "Bar" },
+ { age: "111" }
+ ])
+ }
+
+ function insertRow(personName, personAge, rowIndex) {
+ testModel.insertRow(rowIndex, {
+ name: personName,
+ age: personAge
+ })
+ }
+
+ function insertRowExtraData() {
+ testModel.insertRow(0, {
+ name: "Foo",
+ age: 99,
+ nonExistentRole: 123
+ })
+ }
+
+ function insertRowInvalid1() {
+ testModel.insertRow(0, 123)
+ }
+
+ function insertRowInvalid2() {
+ testModel.insertRow(0, {
+ name: "Foo",
+ age: []
+ })
+ }
+
+ function insertRowInvalid3() {
+ testModel.insertRow(0, [
+ { name: "Bar" },
+ { age: "111" }
+ ])
+ }
+
+ function setRow(rowIndex, personName, personAge) {
+ testModel.setRow(rowIndex, {
+ name: personName,
+ age: personAge
+ })
+ }
+
+ function setRowExtraData() {
+ testModel.setRow(0, {
+ name: "Foo",
+ age: 99,
+ nonExistentRole: 123
+ })
+ }
+
+ function setRowInvalid1() {
+ testModel.setRow(0, 123)
+ }
+
+ function setRowInvalid2() {
+ testModel.setRow(0, {
+ name: "Foo",
+ age: []
+ })
+ }
+
+ function setRowInvalid3() {
+ testModel.setRow(0, [
+ { name: "Bar" },
+ { age: "111" }
+ ])
+ }
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ model: TestModel {
+ id: testModel
+ }
+ delegate: Text {
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/complex.qml b/tests/auto/qml/qqmltablemodel/data/complex.qml
new file mode 100644
index 0000000000..dbf53bac7e
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/complex.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.13
+import Qt.labs.qmlmodels 1.0
+
+TableView {
+ width: 100
+ height: 100
+ delegate: Item {
+ implicitWidth: 50
+ implicitHeight: 50
+
+ Text {
+ text: model.display
+ anchors.centerIn: parent
+ }
+ }
+ model: TableModel {
+ id: testModel
+ objectName: "testModel"
+
+ TableModelColumn {
+ display: function(modelIndex) { return testModel.rows[modelIndex.row][0].name }
+ setDisplay: function(modelIndex, cellData) { testModel.rows[modelIndex.row][0].name = cellData }
+ }
+ TableModelColumn {
+ display: function(modelIndex) { return testModel.rows[modelIndex.row][1].age }
+ setDisplay: function(modelIndex, cellData) { testModel.rows[modelIndex.row][1].age = cellData }
+ }
+
+ rows: [
+ [
+ { name: "John" },
+ { age: 22 }
+ ],
+ [
+ { name: "Oliver" },
+ { age: 33 }
+ ]
+ ]
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml
new file mode 100644
index 0000000000..d3f726bfa1
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import Qt.labs.qmlmodels 1.0
+
+TableView {
+ width: 200; height: 200
+ model: TestModel {
+ id: testModel
+
+ // This is silly: in real life, store the birthdate instead of the age,
+ // and let the delegate calculate the age, so it won't need updating
+ function happyBirthday(dude) {
+ var row = -1;
+ for (var r = 0; row < 0 && r < testModel.rowCount; ++r)
+ if (testModel.data(testModel.index(r, 0), "display") === dude)
+ row = r;
+ var index = testModel.index(row, 1)
+ testModel.setData(index, "display", testModel.data(index, "display") + 1)
+ }
+ }
+ delegate: Text {
+ id: textItem
+ text: model.display
+ TapHandler {
+ onTapped: testModel.happyBirthday(testModel.data(testModel.index(row, 0), "display"))
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/empty.qml b/tests/auto/qml/qqmltablemodel/data/empty.qml
new file mode 100644
index 0000000000..f5afbd1d27
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/empty.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import Qt.labs.qmlmodels 1.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ property alias testModel: testModel
+ property alias tableView: tableView
+
+ function setRows() {
+ testModel.rows = [
+ {
+ name: "John",
+ age: 22
+ },
+ {
+ name: "Oliver",
+ age: 33
+ }
+ ]
+ }
+
+ function appendJohn() {
+ testModel.appendRow({
+ name: "John",
+ age: 22
+ })
+ }
+
+ function appendOliver() {
+ testModel.appendRow({
+ name: "Oliver",
+ age: 33
+ })
+ }
+
+ TableModel {
+ id: testModel
+ objectName: "testModel"
+
+ TableModelColumn { display: "name" }
+ TableModelColumn { display: "age" }
+ }
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ model: testModel
+ delegate: Text {
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml b/tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml
new file mode 100644
index 0000000000..86bcb08fa2
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/omitTableModelColumnIndex.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import Qt.labs.qmlmodels 1.0
+
+TableModel {
+ objectName: "testModel"
+
+ TableModelColumn { display: "name" }
+ TableModelColumn { display: "age" }
+
+ rows: [
+ {
+ name: "John",
+ age: 22
+ },
+ {
+ name: "Oliver",
+ age: 33
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml
new file mode 100644
index 0000000000..ebfe4ed930
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import Qt.labs.qmlmodels 1.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ property alias testModel: testModel
+
+ signal shouldModify()
+ signal shouldModifyInvalidRole()
+ signal shouldModifyInvalidType()
+
+ function modify() {
+ shouldModify()
+ }
+
+ function modifyInvalidRole() {
+ shouldModifyInvalidRole()
+ }
+
+ function modifyInvalidType() {
+ shouldModifyInvalidType()
+ }
+
+ TableView {
+ anchors.fill: parent
+ model: TestModel {
+ id: testModel
+ }
+
+ delegate: Text {
+ id: textItem
+ text: model.display
+
+ Connections {
+ target: root
+ enabled: column === 1
+ onShouldModify: model.display = 18
+ }
+
+ Connections {
+ target: root
+ enabled: column === 0
+ // Invalid: should be "display".
+ onShouldModifyInvalidRole: model.age = 100
+ }
+
+ Connections {
+ target: root
+ enabled: column === 1
+ // Invalid: should be string.
+ onShouldModifyInvalidType: model.display = "Whoops"
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml
new file mode 100644
index 0000000000..01ec40270c
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import Qt.labs.qmlmodels 1.0
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ property alias testModel: testModel
+ property alias tableView: tableView
+
+ function setRowsValid() {
+ testModel.rows = [
+ {
+ name: "Max",
+ age: 20
+ },
+ {
+ name: "Imum",
+ age: 41
+ },
+ {
+ name: "Power",
+ age: 89
+ }
+ ]
+ }
+
+ function setRowsInvalid() {
+ testModel.rows = [
+ {
+ nope: "Nope",
+ age: 20
+ },
+ {
+ nope: "Nah",
+ age: 41
+ },
+ {
+ nope: "No",
+ age: 89
+ }
+ ]
+ }
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ model: TestModel {
+ id: testModel
+ }
+ delegate: Text {
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro b/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro
new file mode 100644
index 0000000000..9d298dfdf2
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/qqmltablemodel.pro
@@ -0,0 +1,10 @@
+CONFIG += testcase
+TARGET = tst_qqmltablemodel
+
+SOURCES += tst_qqmltablemodel.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core gui qml-private qml quick-private quick testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
new file mode 100644
index 0000000000..d913bcdf9a
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
@@ -0,0 +1,980 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+#include <QtCore/qregularexpression.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQmlModels/private/qqmltablemodel_p.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquicktableview_p.h>
+
+#include "../../shared/util.h"
+
+class tst_QQmlTableModel : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QQmlTableModel() {}
+
+private slots:
+ void appendRemoveRow();
+ void appendRowToEmptyModel();
+ void clear();
+ void getRow();
+ void insertRow();
+ void moveRow();
+ void setRow();
+ void setDataThroughDelegate();
+ void setRowsImperatively();
+ void setRowsMultipleTimes();
+ void dataAndEditing();
+ void omitTableModelColumnIndex();
+ void complexRow();
+};
+
+void tst_QQmlTableModel::appendRemoveRow()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+ int rowCountSignalEmissions = 0;
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(roleNames.size(), 1);
+ QVERIFY(roleNames.values().contains("display"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+
+ // Call remove() with a negative rowIndex.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*removeRow\\(\\): \"rowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, -1)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call remove() with an rowIndex that is too large.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*removeRow\\(\\): \"rowIndex\" 2 is greater than or equal to rowCount\\(\\) of 2"));
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 2)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call remove() with a valid rowIndex but negative rows.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*removeRow\\(\\): \"rows\" is less than or equal to zero"));
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, -1)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call remove() with a valid rowIndex but excessive rows.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*removeRow\\(\\): \"rows\" 3 exceeds available rowCount\\(\\) of 2 when removing from \"rowIndex\" 0"));
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, 3)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call remove() without specifying the number of rows to remove; it should remove one row.
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0)));
+ QCOMPARE(model->rowCount(), 1);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+
+ // Call append() with a row that has an unexpected role; the row should be added and the extra data ignored.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowExtraData"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+
+ // Call append() with a row that is an int.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*appendRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid1"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call append() with a row with a role of the wrong type.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*appendRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid2"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call append() with a row that is an array instead of a simple object.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*appendRow\\(\\): row manipulation functions do not support complex rows \\(row index: -1\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid3"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Call append() to insert one row.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40)));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+
+ // Call remove() and specify rowIndex and rows, removing all remaining rows.
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, 3)));
+ QCOMPARE(model->rowCount(), 0);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")), QVariant());
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")), QVariant());
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+}
+
+void tst_QQmlTableModel::appendRowToEmptyModel()
+{
+ QQuickView view(testFileUrl("empty.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 0);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 0);
+ QCOMPARE(tableView->columns(), 2);
+
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendJohn"));
+ QCOMPARE(model->rowCount(), 1);
+ QCOMPARE(model->columnCount(), 2);
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ QTRY_COMPARE(tableView->rows(), 1);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::clear()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QVERIFY(roleNames.values().contains("display"));
+ QCOMPARE(roleNames.size(), 1);
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ QVERIFY(QMetaObject::invokeMethod(model, "clear"));
+ QCOMPARE(model->rowCount(), 0);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")), QVariant());
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")), QVariant());
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ // Wait until updatePolish() gets called, which is where the size is recalculated.
+ QTRY_COMPARE(tableView->rows(), 0);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::getRow()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ // Call get() with a negative row index.
+ QVariant returnValue;
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*getRow\\(\\): \"rowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(model, "getRow", Q_RETURN_ARG(QVariant, returnValue), Q_ARG(int, -1)));
+ QVERIFY(!returnValue.isValid());
+
+ // Call get() with a row index that is too large.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*getRow\\(\\): \"rowIndex\" 2 is greater than or equal to rowCount\\(\\) of 2"));
+ QVERIFY(QMetaObject::invokeMethod(model, "getRow", Q_RETURN_ARG(QVariant, returnValue), Q_ARG(int, 2)));
+ QVERIFY(!returnValue.isValid());
+
+ // Call get() with a valid row index.
+ QVERIFY(QMetaObject::invokeMethod(model, "getRow", Q_RETURN_ARG(QVariant, returnValue), Q_ARG(int, 0)));
+ const QVariantMap rowAsVariantMap = returnValue.toMap();
+ QCOMPARE(rowAsVariantMap.value(QLatin1String("name")).toString(), QLatin1String("John"));
+ QCOMPARE(rowAsVariantMap.value(QLatin1String("age")).toInt(), 22);
+}
+
+void tst_QQmlTableModel::insertRow()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+ int rowCountSignalEmissions = 0;
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert with a negative index.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): \"rowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow",
+ Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, -1)));
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->rowCount(), 2);
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert past the last allowed index.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): \"rowIndex\" 3 is greater than rowCount\\(\\) of 2"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow",
+ Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, 3)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Call insert() with a row that is an int.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid1"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row with a role of the wrong type.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid2"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that is an array instead of a simple object.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): row manipulation functions do not support complex rows \\(row index: 0\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid3"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row has an unexpected role; the row should be added and the extra data ignored.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowExtraData"));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 3);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Insert a row at the bottom of the table.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow",
+ Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40), Q_ARG(QVariant, 3)));
+ QCOMPARE(model->rowCount(), 4);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 4);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Insert a row in the middle of the table.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRow",
+ Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30), Q_ARG(QVariant, 2)));
+ QCOMPARE(model->rowCount(), 5);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 5);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::moveRow()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->rowCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+ int rowCountSignalEmissions = 0;
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+
+ // Append some rows.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40)));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30)));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", Q_ARG(QVariant, QLatin1String("Trev")), Q_ARG(QVariant, 48)));
+ QCOMPARE(model->rowCount(), 5);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ rowCountSignalEmissions = 3;
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Try to move with a fromRowIndex that is negative.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"fromRowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, -1), Q_ARG(int, 1)));
+ // Shouldn't have changed.
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Try to move with a fromRowIndex that is too large.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"fromRowIndex\" 5 is greater than or equal to rowCount\\(\\)"));
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 5), Q_ARG(int, 1)));
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Try to move with a toRowIndex that is negative.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"toRowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, -1)));
+ // Shouldn't have changed.
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Try to move with a toRowIndex that is too large.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*moveRow\\(\\): \"toRowIndex\" 5 is greater than or equal to rowCount\\(\\)"));
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 5)));
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Move the first row to the end.
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 4)));
+ // The counts shouldn't have changed.
+ QCOMPARE(model->rowCount(), 5);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Move it back again.
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 4), Q_ARG(int, 0)));
+ QCOMPARE(model->rowCount(), 5);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+
+ // Move the first row down one by one row.
+ QVERIFY(QMetaObject::invokeMethod(model, "moveRow", Q_ARG(int, 0), Q_ARG(int, 1)));
+ QCOMPARE(model->rowCount(), 5);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("display")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+}
+
+void tst_QQmlTableModel::setRow()
+{
+ QQuickView view(testFileUrl("common.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->rowCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+ int rowCountSignalEmissions = 0;
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to set with a negative index.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRow\\(\\): \"rowIndex\" cannot be negative"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow",
+ Q_ARG(QVariant, -1), Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to set at an index past the last allowed index.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRow\\(\\): \"rowIndex\" 3 is greater than rowCount\\(\\) of 2"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow",
+ Q_ARG(QVariant, 3), Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to set a row that has an unexpected role; the row should be set and the extra data ignored.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowExtraData"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that is not an array.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRow\\(\\): expected \"row\" argument to be a QJSValue, but got int instead:\nQVariant\\(int, 123\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid1"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row with a role that is of the wrong type.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRow\\(\\): expected the property named \"age\" to be of type \"int\", but got \"QVariantList\" instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid2"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that is an array instead of a simple object.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRow\\(\\): row manipulation functions do not support complex rows \\(row index: 0\\)"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid3"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Set the first row.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow",
+ Q_ARG(QVariant, 0), Q_ARG(QVariant, QLatin1String("Max")), Q_ARG(QVariant, 40)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Set the last row.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow",
+ Q_ARG(QVariant, 1), Q_ARG(QVariant, QLatin1String("Daisy")), Q_ARG(QVariant, 30)));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), rowCountSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Append a row by passing an index that is equal to rowCount().
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRow",
+ Q_ARG(QVariant, 2), Q_ARG(QVariant, QLatin1String("Wot")), Q_ARG(QVariant, 99)));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 30);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Wot"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 99);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++rowCountSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 3);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::setDataThroughDelegate()
+{
+ QQuickView view(testFileUrl("setDataThroughDelegate.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(roleNames.size(), 1);
+ QVERIFY(roleNames.values().contains("display"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modify"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+
+ // Test setting a role that doesn't exist for a certain column.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidRole"));
+ // Should be unchanged.
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+
+ // Test setting a role with a value of the wrong type.
+ // There are two rows, so two delegates respond to the signal, which means we need to ignore two warnings.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setData\\(\\): failed converting value QVariant\\(QString, \"Whoops\"\\) " \
+ "set at row 0 column 1 with role \"display\" to \"int\""));
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setData\\(\\): failed converting value QVariant\\(QString, \"Whoops\"\\) " \
+ "set at row 1 column 1 with role \"display\" to \"int\""));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidType"));
+ // Should be unchanged.
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 18);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+}
+
+// Start off with empty rows and then set them to test rowCountChanged().
+void tst_QQmlTableModel::setRowsImperatively()
+{
+ QQuickView view(testFileUrl("empty.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 0);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 0);
+ QCOMPARE(tableView->columns(), 2);
+
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRows"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ QTRY_COMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::setRowsMultipleTimes()
+{
+ QQuickView view(testFileUrl("setRowsMultipleTimes.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged()));
+ QVERIFY(columnCountSpy.isValid());
+
+ QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged()));
+ QVERIFY(rowCountSpy.isValid());
+
+ QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>();
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Set valid rows after they've already been declared.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowsValid"));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 20);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Imum"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 41);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Power"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 89);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ QTRY_COMPARE(tableView->rows(), 3);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Set invalid rows; we should get a warning and nothing should change.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRows\\(\\): expected a property named \"name\" in row at index 0, but couldn't find one"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowsInvalid"));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 20);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Imum"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 41);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Power"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("display")).toInt(), 89);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ QCOMPARE(tableView->rows(), 3);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::dataAndEditing()
+{
+ QQuickView view(testFileUrl("dataAndSetData.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("model").value<QQmlTableModel*>();
+ QVERIFY(model);
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QVERIFY(roleNames.values().contains("display"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+ QVERIFY(QMetaObject::invokeMethod(model, "happyBirthday", Q_ARG(QVariant, QLatin1String("Oliver"))));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 34);
+}
+
+void tst_QQmlTableModel::omitTableModelColumnIndex()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("omitTableModelColumnIndex.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+
+ QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create()));
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+}
+
+void tst_QQmlTableModel::complexRow()
+{
+ QQuickView view(testFileUrl("complex.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickTableView *tableView = qobject_cast<QQuickTableView*>(view.rootObject());
+ QVERIFY(tableView);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ QQmlTableModel *model = tableView->model().value<QQmlTableModel*>();
+ QVERIFY(model);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33);
+}
+
+QTEST_MAIN(tst_QQmlTableModel)
+
+#include "tst_qqmltablemodel.moc"
diff --git a/tests/auto/qml/qqmltimer/dummy_imports.qml b/tests/auto/qml/qqmltimer/dummy_imports.qml
new file mode 100644
index 0000000000..f78e04d489
--- /dev/null
+++ b/tests/auto/qml/qqmltimer/dummy_imports.qml
@@ -0,0 +1,9 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in the
+// C++ code belonging to the test.
+
+import QtQml 2.0
+import QtQuick 2.0
+
+QtObject { } // This is needed in order to keep importscanner happy
diff --git a/tests/auto/qml/qqmltranslation/data/mylibrary.js b/tests/auto/qml/qqmltranslation/data/mylibrary.js
new file mode 100644
index 0000000000..5903db3b4b
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/mylibrary.js
@@ -0,0 +1,5 @@
+Qt.include("nested_js_translation.js")
+
+function translation_success() {
+ return qsTr("English in mylibrary");
+}
diff --git a/tests/auto/qml/qqmltranslation/data/nested_js_translation.js b/tests/auto/qml/qqmltranslation/data/nested_js_translation.js
new file mode 100644
index 0000000000..336cdedfea
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/nested_js_translation.js
@@ -0,0 +1,3 @@
+function translation_fail() {
+ return qsTr("English in translation")
+}
diff --git a/tests/auto/qml/qqmltranslation/data/preferjs.qml b/tests/auto/qml/qqmltranslation/data/preferjs.qml
new file mode 100644
index 0000000000..040fa12e4e
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/preferjs.qml
@@ -0,0 +1,8 @@
+import QtQml 2.12
+
+import "mylibrary.js" as Lib
+
+QtObject {
+ property string german1: Lib.translation_fail()
+ property string german2: Lib.translation_success()
+}
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 809a9bd9db..a75a00bd01 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -32,6 +32,7 @@
#include <QTranslator>
#include <QQmlContext>
#include <private/qqmlengine_p.h>
+#include <private/qqmltypedata_p.h>
#include "../../shared/util.h"
class tst_qqmltranslation : public QQmlDataTest
@@ -45,6 +46,7 @@ private slots:
void translation();
void idTranslation();
void translationChange();
+ void preferJSContext();
};
void tst_qqmltranslation::translation_data()
@@ -85,7 +87,8 @@ void tst_qqmltranslation::translation()
<< QStringLiteral("disambiguation")
<< QStringLiteral("singular") << QStringLiteral("plural");
- const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
+ const QV4::CompiledData::Object *rootObject
+ = compilationUnit->qmlData->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
@@ -139,7 +142,8 @@ void tst_qqmltranslation::idTranslation()
QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
QVERIFY(compilationUnit);
- const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
+ const QV4::CompiledData::Object *rootObject
+ = compilationUnit->qmlData->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
@@ -172,6 +176,10 @@ class DummyTranslator : public QTranslator
Q_UNUSED(n);
if (!qstrcmp(sourceText, "translate me"))
return QString::fromUtf8("xxx");
+ if (!qstrcmp(sourceText, "English in mylibrary") && !qstrcmp(context, "mylibrary"))
+ return QString::fromUtf8("Deutsch in mylibrary");
+ if (!qstrcmp(sourceText, "English in translation") && !qstrcmp(context, "nested_js_translation"))
+ return QString::fromUtf8("Deutsch in Setzung");
return QString();
}
@@ -210,6 +218,24 @@ void tst_qqmltranslation::translationChange()
QCoreApplication::removeTranslator(&translator);
}
+void tst_qqmltranslation::preferJSContext()
+{
+ DummyTranslator translator;
+ QCoreApplication::installTranslator(&translator);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("preferjs.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QCOMPARE(object->property("german1").toString(),
+ QStringLiteral("Deutsch in Setzung"));
+ QCOMPARE(object->property("german2").toString(),
+ QStringLiteral("Deutsch in mylibrary"));
+
+ QCoreApplication::removeTranslator(&translator);
+}
+
QTEST_MAIN(tst_qqmltranslation)
#include "tst_qqmltranslation.moc"
diff --git a/tests/auto/qml/qqmltypeloader/data/Com/Orga/BaseStyle.qml b/tests/auto/qml/qqmltypeloader/data/Com/Orga/BaseStyle.qml
new file mode 100644
index 0000000000..28521e3af2
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Com/Orga/BaseStyle.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.6
+
+Item {
+
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/Handler.qml b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/Handler.qml
new file mode 100644
index 0000000000..b20a2def11
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/Handler.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.6
+import Com.Orga 1.0
+
+Rectangle {
+ color: Style.name
+ Text {text: "Hello world!"}
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/qmldir b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/qmldir
new file mode 100644
index 0000000000..368cb65b35
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Handlers/qmldir
@@ -0,0 +1,2 @@
+module Com.Orga.Handlers
+Handler 1.0 Handler.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/Com/Orga/Style.qml b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Style.qml
new file mode 100644
index 0000000000..7951f5e768
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Com/Orga/Style.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQuick 2.6
+
+BaseStyle {
+ property color name: "black"
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Com/Orga/qmldir b/tests/auto/qml/qqmltypeloader/data/Com/Orga/qmldir
new file mode 100644
index 0000000000..9c5560b323
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Com/Orga/qmldir
@@ -0,0 +1,2 @@
+singleton Style 1.0 Style.qml
+BaseStyle 1.0 BaseStyle.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml b/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml
new file mode 100644
index 0000000000..7a054e199b
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/implicitimporttest.qml
@@ -0,0 +1,5 @@
+import modulewithimplicitimport 2.0 as MyNS
+MyNS.Test {
+ MyNS.Item {} // Implicitly imported from QtQuick
+ MyNS.ListModel {}
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml
new file mode 100644
index 0000000000..2f78302506
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/Test.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+Item {
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir
new file mode 100644
index 0000000000..10e8f90f62
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/modulewithimplicitimport/qmldir
@@ -0,0 +1,2 @@
+import QtQuick
+Test 2.0 Test.qml
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 52c722aac8..9ad53aaa8b 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -28,6 +28,7 @@
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
@@ -35,6 +36,7 @@
#include <QtCore/qprocess.h>
#endif
#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmltypedata_p.h>
#include <QtQml/private/qqmltypeloader_p.h>
#include "../../shared/testhttpserver.h"
#include "../../shared/util.h"
@@ -57,6 +59,8 @@ private slots:
void multiSingletonModule();
void implicitComponentModule();
void qrcRootPathUrl();
+ void implicitImport();
+ void compositeSingletonCycle();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -431,7 +435,7 @@ void tst_QQMLTypeLoader::redirect()
component.loadUrl(server.urlString("/Load.qml"), QQmlComponent::Asynchronous);
QTRY_VERIFY2(component.isReady(), qPrintable(component.errorString()));
- QObject *object = component.create();
+ QScopedPointer<QObject> object {component.create()};
QTRY_COMPARE(object->property("xy").toInt(), 323232);
}
@@ -511,6 +515,33 @@ void tst_QQMLTypeLoader::qrcRootPathUrl()
QCOMPARE(component.status(), QQmlComponent::Ready);
}
+void tst_QQMLTypeLoader::implicitImport()
+{
+ QQmlEngine engine;
+ engine.addImportPath(testFile("imports"));
+ QQmlComponent component(&engine, testFileUrl("implicitimporttest.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
+void tst_QQMLTypeLoader::compositeSingletonCycle()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ QVERIFY(server.serveDirectory(dataDirectory()));
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ engine.addImportPath(server.baseUrl().toString());
+ component.loadUrl(server.urlString("Com/Orga/Handlers/Handler.qml"), QQmlComponent::Asynchronous);
+ QTRY_VERIFY2(component.isReady(), qPrintable(component.errorString()));
+
+ QScopedPointer<QObject> object {component.create()};
+ QVERIFY(object);
+ QCOMPARE(qvariant_cast<QColor>(object->property("color")), QColorConstants::Black);
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"
diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
index 73d2b921a7..a2d303b507 100644
--- a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
+++ b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml
@@ -12,4 +12,7 @@ MyTypeObject {
property real hsl_s: color.hslSaturation
property real hsl_l: color.hslLightness
property variant copy: color
+
+ property bool valid: color.valid
+ property bool invalid: invalidColor.valid
}
diff --git a/tests/auto/qml/qqmlvaluetypes/testtypes.h b/tests/auto/qml/qqmlvaluetypes/testtypes.h
index bcfe4028c6..798c96e188 100644
--- a/tests/auto/qml/qqmlvaluetypes/testtypes.h
+++ b/tests/auto/qml/qqmlvaluetypes/testtypes.h
@@ -69,6 +69,7 @@ class MyTypeObject : public QObject
Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix NOTIFY changed)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
+ Q_PROPERTY(QColor invalidColor READ invalidColor CONSTANT)
Q_PROPERTY(QVariant variant READ variant NOTIFY changed)
public:
@@ -168,6 +169,8 @@ public:
QColor color() const { return m_color; }
void setColor(const QColor &v) { m_color = v; emit changed(); }
+ QColor invalidColor() const { return QColor(); }
+
QVariant variant() const { return sizef(); }
void emitRunScript() { emit runScript(); }
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index 15bd031ce3..3e9047cc5a 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -97,6 +97,7 @@ private slots:
void enumerableProperties();
void enumProperties();
void scarceTypes();
+ void nonValueTypes();
private:
QQmlEngine engine;
@@ -784,6 +785,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
QVERIFY(object != nullptr);
QCOMPARE(object->property("f_family").toString(), object->font().family());
@@ -793,8 +795,19 @@ void tst_qqmlvaluetypes::font()
QCOMPARE(object->property("f_underline").toBool(), object->font().underline());
QCOMPARE(object->property("f_overline").toBool(), object->font().overline());
QCOMPARE(object->property("f_strikeout").toBool(), object->font().strikeOut());
- QCOMPARE(object->property("f_pointSize").toDouble(), object->font().pointSizeF());
- QCOMPARE(object->property("f_pixelSize").toInt(), int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.)));
+
+ // If QFont::pixelSize() was set, QFont::pointSizeF() would return -1.
+ // If QFont::pointSizeF() was set, QFont::pixelSize() would return -1.
+ // QQuickFontValueType doesn't follow this semantic (if its -1 it calculates the value of
+ // the property from the other one)
+ double expectedPointSizeF = object->font().pointSizeF();
+ if (expectedPointSizeF == -1) expectedPointSizeF = object->font().pixelSize() * qreal(72.) / qreal(qt_defaultDpi());
+ int expectedPixelSize = object->font().pixelSize();
+ if (expectedPixelSize == -1) expectedPixelSize = int((object->font().pointSizeF() * qt_defaultDpi()) / qreal(72.));
+
+ QCOMPARE(object->property("f_pointSize").toDouble(), expectedPointSizeF);
+ QCOMPARE(object->property("f_pixelSize").toInt(), expectedPixelSize);
+
QCOMPARE(object->property("f_capitalization").toInt(), (int)object->font().capitalization());
QCOMPARE(object->property("f_letterSpacing").toDouble(), object->font().letterSpacing());
QCOMPARE(object->property("f_wordSpacing").toDouble(), object->font().wordSpacing());
@@ -922,6 +935,11 @@ void tst_qqmlvaluetypes::color()
QCOMPARE(qRound(object->property("hsl_s").toDouble() * 100), 74);
QCOMPARE(qRound(object->property("hsl_l").toDouble() * 100), 54);
+ QCOMPARE(object->property("valid").userType(), QMetaType::Bool);
+ QVERIFY(object->property("valid").toBool());
+ QCOMPARE(object->property("invalid").userType(), QMetaType::Bool);
+ QVERIFY(!object->property("invalid").toBool());
+
QColor comparison;
comparison.setRedF(0.2);
comparison.setGreenF(0.88);
@@ -1713,7 +1731,7 @@ void tst_qqmlvaluetypes::sequences()
QJSValue value = engine.toScriptValue(qcharVector);
QCOMPARE(value.property("length").toInt(), qcharVector.length());
for (int i = 0; i < qcharVector.length(); ++i)
- QCOMPARE(value.property(i).toInt(), qcharVector.at(i));
+ QCOMPARE(value.property(i).toString(), qcharVector.at(i));
}
{
MyTypeObject a, b, c;
@@ -1832,6 +1850,16 @@ void tst_qqmlvaluetypes::scarceTypes()
QCOMPARE(QByteArray(pixmapValue->vtable()->className), QByteArray("VariantObject"));
}
+#define CHECK_TYPE_IS_NOT_VALUETYPE(Type, typeId, cppType) \
+ QVERIFY(!QQmlValueTypeFactory::isValueType(QMetaType::Type));
+
+void tst_qqmlvaluetypes::nonValueTypes()
+{
+ CHECK_TYPE_IS_NOT_VALUETYPE(UnknownType, 0, void)
+ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(CHECK_TYPE_IS_NOT_VALUETYPE);
+}
+
+#undef CHECK_TYPE_IS_NOT_VALUETYPE
QTEST_MAIN(tst_qqmlvaluetypes)
diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
index 4b2ae45bae..ae99e35467 100644
--- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
+++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
@@ -75,6 +75,7 @@ private slots:
void introspectQrc();
void sortCaseSensitive_data();
void sortCaseSensitive();
+ void updateProperties();
private:
void checkNoErrors(const QQmlComponent& component);
QQmlEngine engine;
@@ -112,6 +113,10 @@ void tst_qquickfolderlistmodel::initTestCase()
void tst_qquickfolderlistmodel::basicProperties()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("[QTBUG-77335] Initial folder of FolderListModel on Android does not work properly,"
+ " and from there on it is unreliable to change the folder");
+#endif
QQmlComponent component(&engine, testFileUrl("basic.qml"));
checkNoErrors(component);
@@ -356,6 +361,9 @@ void tst_qquickfolderlistmodel::showDotAndDotDot()
void tst_qquickfolderlistmodel::showDotAndDotDot_data()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Resource file system does not list '.' and '..' due to QDir::entryList() behavior");
+#endif
QTest::addColumn<QUrl>("folder");
QTest::addColumn<QUrl>("rootFolder");
QTest::addColumn<bool>("showDotAndDotDot");
@@ -411,13 +419,54 @@ void tst_qquickfolderlistmodel::sortCaseSensitive()
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
QVERIFY(flm != 0);
- flm->setProperty("folder", QUrl::fromLocalFile(dataDirectoryUrl().path() + QLatin1String("/sortdir")));
+ flm->setProperty("folder", testFileUrl("sortdir"));
flm->setProperty("sortCaseSensitive", sortCaseSensitive);
QTRY_COMPARE(flm->property("count").toInt(), 2); // wait for refresh
for (int i = 0; i < 2; ++i)
QTRY_COMPARE(flm->data(flm->index(i),FileNameRole).toString(), expectedOrder.at(i));
}
+void tst_qquickfolderlistmodel::updateProperties()
+{
+ QQmlComponent component(&engine, testFileUrl("basic.qml"));
+ checkNoErrors(component);
+
+ QObject *folderListModel = component.create();
+ QVERIFY(folderListModel);
+
+ QVariant caseSensitive = folderListModel->property("caseSensitive");
+ QVERIFY(caseSensitive.isValid());
+ QCOMPARE(caseSensitive.toBool(), true);
+ folderListModel->setProperty("caseSensitive", false);
+ caseSensitive = folderListModel->property("caseSensitive");
+ QVERIFY(caseSensitive.isValid());
+ QCOMPARE(caseSensitive.toBool(), false);
+
+ QVariant showOnlyReadable = folderListModel->property("showOnlyReadable");
+ QVERIFY(showOnlyReadable.isValid());
+ QCOMPARE(showOnlyReadable.toBool(), false);
+ folderListModel->setProperty("showOnlyReadable", true);
+ showOnlyReadable = folderListModel->property("showOnlyReadable");
+ QVERIFY(showOnlyReadable.isValid());
+ QCOMPARE(showOnlyReadable.toBool(), true);
+
+ QVariant showDotAndDotDot = folderListModel->property("showDotAndDotDot");
+ QVERIFY(showDotAndDotDot.isValid());
+ QCOMPARE(showDotAndDotDot.toBool(), false);
+ folderListModel->setProperty("showDotAndDotDot", true);
+ showDotAndDotDot = folderListModel->property("showDotAndDotDot");
+ QVERIFY(showDotAndDotDot.isValid());
+ QCOMPARE(showDotAndDotDot.toBool(), true);
+
+ QVariant showHidden = folderListModel->property("showHidden");
+ QVERIFY(showHidden.isValid());
+ QCOMPARE(showHidden.toBool(), false);
+ folderListModel->setProperty("showHidden", true);
+ showHidden = folderListModel->property("showHidden");
+ QVERIFY(showHidden.isValid());
+ QCOMPARE(showHidden.toBool(), true);
+}
+
QTEST_MAIN(tst_qquickfolderlistmodel)
#include "tst_qquickfolderlistmodel.moc"
diff --git a/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro b/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro
index be8b9089a2..f58fd4543f 100644
--- a/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro
+++ b/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro
@@ -8,4 +8,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private testlib
+QT += core-private gui-private qml-private testlib qmlworkerscript-private
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index 4ad58ba56c..bea9978f0b 100644
--- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
+++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
@@ -30,6 +30,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
+#include <QtCore/qregularexpression.h>
#include <QtQml/qjsengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -91,14 +92,14 @@ void tst_QQuickWorkerScript::source()
QCOMPARE(worker->source(), source);
QVERIFY(QMetaObject::invokeMethod(worker.data(), "testSend", Q_ARG(QVariant, value)));
waitForEchoMessage(worker.data());
- QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), qVariantFromValue(QString("Hello_World")));
+ QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), QVariant::fromValue(QString("Hello_World")));
source = testFileUrl("script_module.mjs");
worker->setSource(source);
QCOMPARE(worker->source(), source);
QVERIFY(QMetaObject::invokeMethod(worker.data(), "testSend", Q_ARG(QVariant, value)));
waitForEchoMessage(worker.data());
- QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), qVariantFromValue(QString("Hello from the module")));
+ QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), QVariant::fromValue(QString("Hello from the module")));
qApp->processEvents();
}
@@ -118,7 +119,18 @@ void tst_QQuickWorkerScript::messaging()
QVariant response = mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>();
if (response.userType() == qMetaTypeId<QJSValue>())
response = response.value<QJSValue>().toVariant();
- QCOMPARE(response, value);
+
+ if (value.type() == QMetaType::QRegExp && response.type() == QMetaType::QRegularExpression) {
+ // toVariant() doesn't know if we want QRegExp or QRegularExpression. It always creates
+ // a QRegularExpression from a JavaScript regular expression.
+ const QRegularExpression responseRegExp = response.toRegularExpression();
+ const QRegExp valueRegExp = value.toRegExp();
+ QCOMPARE(responseRegExp.pattern(), valueRegExp.pattern());
+ QCOMPARE(bool(responseRegExp.patternOptions() & QRegularExpression::CaseInsensitiveOption),
+ bool(valueRegExp.caseSensitivity() == Qt::CaseInsensitive));
+ } else {
+ QCOMPARE(response, value);
+ }
qApp->processEvents();
delete worker;
@@ -129,16 +141,16 @@ void tst_QQuickWorkerScript::messaging_data()
QTest::addColumn<QVariant>("value");
QTest::newRow("invalid") << QVariant();
- QTest::newRow("bool") << qVariantFromValue(true);
- QTest::newRow("int") << qVariantFromValue(1001);
- QTest::newRow("real") << qVariantFromValue(10334.375);
- QTest::newRow("string") << qVariantFromValue(QString("More cheeeese, Gromit!"));
- QTest::newRow("variant list") << qVariantFromValue((QVariantList() << "a" << "b" << "c"));
- QTest::newRow("date time") << qVariantFromValue(QDateTime::currentDateTime());
-#ifndef QT_NO_REGEXP
- // Qt Script's QScriptValue -> QRegExp uses RegExp2 pattern syntax
- QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive, QRegExp::RegExp2));
-#endif
+ QTest::newRow("bool") << QVariant::fromValue(true);
+ QTest::newRow("int") << QVariant::fromValue(1001);
+ QTest::newRow("real") << QVariant::fromValue(10334.375);
+ QTest::newRow("string") << QVariant::fromValue(QString("More cheeeese, Gromit!"));
+ QTest::newRow("variant list") << QVariant::fromValue((QVariantList() << "a" << "b" << "c"));
+ QTest::newRow("date time") << QVariant::fromValue(QDateTime::currentDateTime());
+ QTest::newRow("regexp") << QVariant::fromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive,
+ QRegExp::RegExp2));
+ QTest::newRow("regularexpression") << QVariant::fromValue(QRegularExpression(
+ "^\\d\\d?$", QRegularExpression::CaseInsensitiveOption));
}
void tst_QQuickWorkerScript::messaging_sendQObjectList()
@@ -153,9 +165,9 @@ void tst_QQuickWorkerScript::messaging_sendQObjectList()
QVariantList objects;
for (int i=0; i<3; i++)
- objects << qVariantFromValue(new QObject(this));
+ objects << QVariant::fromValue(new QObject(this));
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(objects))));
+ QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, QVariant::fromValue(objects))));
waitForEchoMessage(worker);
const QMetaObject *mo = worker->metaObject();
@@ -181,10 +193,10 @@ void tst_QQuickWorkerScript::messaging_sendJsObject()
map.insert("name", "zyz");
map.insert("spell power", 3101);
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(map))));
+ QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, QVariant::fromValue(map))));
waitForEchoMessage(worker);
- QVariant result = qVariantFromValue(false);
+ QVariant result = QVariant::fromValue(false);
QVERIFY(QMetaObject::invokeMethod(worker, "compareLiteralResponse", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, jsObject)));
QVERIFY(result.toBool());
diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
index fd50ff5020..5dd8e9dcc0 100644
--- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
+++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
@@ -59,7 +59,7 @@ void tst_QV4Assembler::initTestCase()
void tst_QV4Assembler::perfMapFile()
{
-#if !defined(Q_OS_LINUX)
+#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
QSKIP("perf map files are only generated on linux");
#else
const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
@@ -140,23 +140,17 @@ void tst_QV4Assembler::functionTable()
#endif
}
-#ifdef V4_ENABLE_JIT
-#define JIT_ENABLED 1
-#else
-#define JIT_ENABLED 0
-#endif
-
void tst_QV4Assembler::jitEnabled()
{
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
/* JIT should be disabled on iOS and tvOS. */
- QCOMPARE(JIT_ENABLED, 0);
+ QVERIFY(!QT_CONFIG(qml_jit));
#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM)
/* JIT should be disabled Windows on ARM/ARM64 for now. */
- QCOMPARE(JIT_ENABLED, 0);
+ QVERIFY(!QT_CONFIG(qml_jit));
#else
/* JIT should be enabled on all other architectures/OSes tested in CI. */
- QCOMPARE(JIT_ENABLED, 1);
+ QVERIFY(QT_CONFIG(qml_jit));
#endif
}
diff --git a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp
index 308fba9049..157d0f2a62 100644
--- a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp
+++ b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2016 basysKom GmbH.
** Contact: https://www.qt.io/licensing/
**
@@ -110,8 +111,8 @@ void tst_qv4identifiertable::sweepCenterEntryInBucket()
table.asPropertyKey(entry2);
table.asPropertyKey(entry3);
- QCOMPARE(table.size, 3);
- QCOMPARE(table.alloc, 5);
+ QCOMPARE(table.size, 3u);
+ QCOMPARE(table.alloc, 5u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
@@ -153,8 +154,8 @@ void tst_qv4identifiertable::sweepLastEntryInBucket()
table.asPropertyKey(entry2);
table.asPropertyKey(entry3);
- QCOMPARE(table.size, 3);
- QCOMPARE(table.alloc, 5);
+ QCOMPARE(table.size, 3u);
+ QCOMPARE(table.alloc, 5u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
@@ -193,8 +194,8 @@ void tst_qv4identifiertable::sweepFirstEntryInSameBucketWithDifferingHash()
table.asPropertyKey(entry1);
table.asPropertyKey(entry2);
- QCOMPARE(table.size, 2);
- QCOMPARE(table.alloc, 5);
+ QCOMPARE(table.size, 2u);
+ QCOMPARE(table.alloc, 5u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
@@ -231,8 +232,8 @@ void tst_qv4identifiertable::dontSweepAcrossBucketBoundaries()
table.asPropertyKey(entry1);
table.asPropertyKey(entry2);
- QCOMPARE(table.size, 2);
- QCOMPARE(table.alloc, 5);
+ QCOMPARE(table.size, 2u);
+ QCOMPARE(table.alloc, 5u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
@@ -279,8 +280,8 @@ void tst_qv4identifiertable::sweepAcrossBucketBoundariesIfFirstBucketFull()
table.asPropertyKey(entry3);
table.asPropertyKey(entry4);
- QCOMPARE(table.size, 4);
- QCOMPARE(table.alloc, 11);
+ QCOMPARE(table.size, 4u);
+ QCOMPARE(table.alloc, 11u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
@@ -336,8 +337,8 @@ void tst_qv4identifiertable::sweepBucketGap()
table.asPropertyKey(entry3);
table.asPropertyKey(entry4);
- QCOMPARE(table.size, 4);
- QCOMPARE(table.alloc, 11);
+ QCOMPARE(table.size, 4u);
+ QCOMPARE(table.alloc, 11u);
QCOMPARE(table.entriesByHash[0], entry1);
QCOMPARE(table.entriesByHash[1], entry2);
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 1e34b79954..5d635aa63b 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -136,7 +136,7 @@ void tst_qv4mm::clearICParent()
// to change this test.
for (uint i = 0; i < 16 * 1024; ++i) {
QV4::Scope scope(&engine);
- QV4::ScopedString s(scope, identifiers->getIndexed(i));
+ QV4::ScopedString s(scope, identifiers->get(i));
QV4::Scoped<QV4::InternalClass> ic(scope, object->internalClass());
QVERIFY(ic->d()->parent != nullptr);
object->deleteProperty(s->toPropertyKey());
diff --git a/tests/auto/qml/v4traced/tst_v4traced.cpp b/tests/auto/qml/v4traced/tst_v4traced.cpp
deleted file mode 100644
index f82cc0ed5e..0000000000
--- a/tests/auto/qml/v4traced/tst_v4traced.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/****************************************************************************
-**
-** 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 <QtTest/QtTest>
-#include <QJSEngine>
-#include <private/qjsvalue_p.h>
-#include <private/qv4scopedvalue_p.h>
-#include <private/qv4script_p.h>
-
-class EnvVarSaver
-{
-public:
- EnvVarSaver(const char *name, const QByteArray &newValue)
- : _name(name)
- {
- _wasSet = qEnvironmentVariableIsSet(name);
- if (_wasSet)
- _oldValue = qgetenv(name);
- qputenv(name, newValue);
- }
-
- ~EnvVarSaver()
- {
- if (_wasSet)
- qputenv(_name, _oldValue);
- else
- qunsetenv(_name);
- }
-
-private:
- const char *_name;
- bool _wasSet;
- QByteArray _oldValue;
-};
-
-class tst_v4traced : public QObject
-{
- Q_OBJECT
-
-private slots:
- void collectTraces_data();
- void collectTraces();
-
- void binopI32deopt_data();
- void binopI32deopt();
-
- void calls_data();
- void calls();
-
- void setLookup();
- void construct();
-};
-
-void tst_v4traced::collectTraces_data()
-{
- QTest::addColumn<QString>("code");
- QTest::addColumn<int>("tracePointCount");
- QTest::addColumn<int>("interestingTracePoint");
- QTest::addColumn<quint8>("expectedBits");
-
- QTest::newRow("int+") << "var a = 4; a + 2" << 2 << 1 << quint8(QV4::ObservedTraceValues::Integer);
- QTest::newRow("double+") << "var a = 4.1; a + 1.9" << 2 << 1 << quint8(QV4::ObservedTraceValues::Double);
- QTest::newRow("object+") << "var a = '4'; a + '2'" << 2 << 1 << quint8(QV4::ObservedTraceValues::Other);
-}
-
-void tst_v4traced::collectTraces()
-{
- QFETCH(QString, code);
- QFETCH(int, tracePointCount);
- QFETCH(int, interestingTracePoint);
- QFETCH(quint8, expectedBits);
-
- EnvVarSaver forceInterpreter("QV4_FORCE_INTERPRETER", "1");
- EnvVarSaver forceTracing("QV4_FORCE_TRACING", "1");
-
- QV4::ExecutionEngine vm;
- QV4::Scope scope(&vm);
- QV4::ScopedContext ctx(scope, vm.rootContext());
- QV4::ScopedValue result(scope);
- QScopedPointer<QV4::Script> script;
- script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, "collectTraces"));
- script->parseAsBinding = false;
-
- QVERIFY(!scope.engine->hasException);
- script->parse();
- QVERIFY(!scope.engine->hasException);
-
- QVERIFY(script->function()->tracingEnabled());
- result = script->run();
- QVERIFY(!scope.engine->hasException);
-
- QCOMPARE(int(script->function()->compiledFunction->nTraceInfos), tracePointCount);
- QCOMPARE(*script->function()->traceInfo(interestingTracePoint), expectedBits);
-}
-
-void tst_v4traced::binopI32deopt_data()
-{
- QTest::addColumn<QString>("operand");
- QTest::addColumn<int>("int_arg1");
- QTest::addColumn<int>("int_arg2");
- QTest::addColumn<int>("int_result");
- QTest::addColumn<QString>("other_arg1");
- QTest::addColumn<QString>("other_arg2");
- QTest::addColumn<double>("other_result");
-
- QTest::newRow("+") << "+" << 1 << 2 << 3 << "1.1" << "1.9" << 3.0;
- QTest::newRow("-") << "-" << 3 << 2 << 1 << "3.1" << "2.1" << 1.0;
- QTest::newRow("*") << "*" << 2 << 3 << 6 << "2.1" << "1.9" << 3.99;
- QTest::newRow("/") << "/" << 6 << 3 << 2 << "6.6" << "3.3" << 2.0;
-
- QTest::newRow("&") << "&" << 6 << 3 << 2 << "'6'" << "'3'" << 2.0;
- QTest::newRow("|") << "|" << 6 << 3 << 7 << "'6'" << "'3'" << 7.0;
- QTest::newRow("^") << "^" << 6 << 3 << 5 << "'6'" << "'3'" << 5.0;
-
- QTest::newRow("<<") << "<<" << 5 << 1 << 10 << "'5'" << "'1'" << 10.0;
- QTest::newRow(">>") << ">>" << -1 << 1 << -1 << "'-1'" << "'1'" << -1.0;
- QTest::newRow(">>>") << ">>>" << -1 << 1 << 0x7FFFFFFF << "'-1'" << "'1'" << 2147483647.0;
-
- QTest::newRow("==") << "==" << 2 << 1 << 0 << "'2'" << "'1'" << 0.0;
- QTest::newRow("!=") << "!=" << 2 << 1 << 1 << "'2'" << "'1'" << 1.0;
- QTest::newRow("<" ) << "<" << 2 << 1 << 0 << "'2'" << "'1'" << 0.0;
- QTest::newRow("<=") << "<=" << 2 << 1 << 0 << "'2'" << "'1'" << 0.0;
- QTest::newRow(">" ) << ">" << 2 << 1 << 1 << "'2'" << "'1'" << 1.0;
- QTest::newRow(">=") << ">=" << 2 << 1 << 1 << "'2'" << "'1'" << 1.0;
-}
-
-void tst_v4traced::binopI32deopt()
-{
- QFETCH(QString, operand);
- QFETCH(int, int_arg1);
- QFETCH(int, int_arg2);
- QFETCH(int, int_result);
- QFETCH(QString, other_arg1);
- QFETCH(QString, other_arg2);
- QFETCH(double, other_result);
-
- QString func = QStringLiteral("function binopI32(a, b) { return a %1 b }").arg(operand);
- QString intCall = QStringLiteral("binopI32(%1, %2)").arg(int_arg1).arg(int_arg2);
- QString otherCall = QStringLiteral("binopI32(%1, %2)").arg(other_arg1).arg(other_arg2);
-
- QJSEngine engine;
- engine.evaluate(func);
-
- QCOMPARE(engine.evaluate(intCall).toInt(), int_result); // interpret + trace
- QCOMPARE(engine.evaluate(intCall).toInt(), int_result); // jit
- QCOMPARE(engine.evaluate(otherCall).toNumber(), other_result); // deopt
- QCOMPARE(engine.evaluate(otherCall).toNumber(), other_result); // retrace
- QCOMPARE(engine.evaluate(otherCall).toNumber(), other_result); // rejit
-}
-
-void tst_v4traced::calls_data()
-{
- QTest::addColumn<QString>("call");
-
- QTest::newRow("callGlobalLookup") << "globalLookup";
- QTest::newRow("callPropertyLookup") << "obj.propertyLookup";
-}
-
-class Calls
-{
-public:
- static int callCount;
-
- static QV4::ReturnedValue doSomething(const QV4::FunctionObject */*o*/,
- const QV4::Value */*thiz*/,
- const QV4::Value *argv, int argc)
- {
- ++callCount;
-
- if (argc == 0)
- return QV4::Encode(42);
-
- int prod = 1;
- for (int i = 0; i < argc; ++i) {
- Q_ASSERT(argv[i].isInteger());
- prod *= argv[i].int_32();
- }
- return QV4::Encode(prod);
- }
-};
-
-int Calls::callCount = 0;
-
-void tst_v4traced::calls()
-{
- QFETCH(QString, call);
-
- EnvVarSaver forceTracing("QV4_FORCE_TRACING", "1");
- EnvVarSaver jitCallThreshold("QV4_JIT_CALL_THRESHOLD", "1");
-
- QV4::ExecutionEngine vm;
- QV4::Scope scope(&vm);
- QV4::ScopedContext ctx(scope, vm.rootContext());
- vm.globalObject->defineDefaultProperty(QLatin1String("globalLookup"),
- Calls::doSomething);
- QV4::ScopedObject obj(scope, vm.newObject());
- vm.globalObject->defineDefaultProperty(QLatin1String("obj"), obj);
- obj->defineDefaultProperty("propertyLookup", Calls::doSomething);
-
- QString code = QStringLiteral(
- "function doCalls() {\n"
- " if (%1() != 42) return false\n"
- " if (%1(21, 2) != 42) return false\n"
- " if (%1(2, 3, 7) != 42) return false\n"
- " return true\n"
- "}\n"
- "var result = true\n"
- "for (var i = 0; i < 10; ++i) {\n"
- " if (!doCalls()) { result = false; break }"
- "}\n"
- "result\n").arg(call);
- QScopedPointer<QV4::Script> script;
- script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, "call"));
- script->parseAsBinding = false;
-
- QVERIFY(!scope.engine->hasException);
- script->parse();
- QVERIFY(!scope.engine->hasException);
-
- Calls::callCount = 0;
- QV4::ScopedValue result(scope, script->run());
- QVERIFY(!scope.engine->hasException);
-
- QVERIFY(result->isBoolean());
- QVERIFY(result->booleanValue());
- QCOMPARE(Calls::callCount, 30);
-}
-
-void tst_v4traced::setLookup()
-{
- EnvVarSaver forceTracing("QV4_FORCE_TRACING", "1");
- EnvVarSaver jitCallThreshold("QV4_JIT_CALL_THRESHOLD", "1");
-
- QV4::ExecutionEngine vm;
- QV4::Scope scope(&vm);
- QV4::ScopedContext ctx(scope, vm.rootContext());
- QV4::ScopedObject obj(scope, vm.newObject());
- vm.globalObject->defineDefaultProperty(QLatin1String("oracle"), obj);
- obj->defineDefaultProperty("answer", QV4::Primitive::fromInt32(32));
-
- QString code = QStringLiteral(
- "function doit() {\n"
- " ++oracle.answer\n"
- "}\n"
- "for (var i = 0; i < 10; ++i) doit()\n"
- "oracle.answer\n");
- QScopedPointer<QV4::Script> script;
- script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, "setLookup"));
- script->parseAsBinding = false;
-
- QVERIFY(!scope.engine->hasException);
- script->parse();
- QVERIFY(!scope.engine->hasException);
-
- QV4::ScopedValue result(scope, script->run());
- QVERIFY(!scope.engine->hasException);
-
- QVERIFY(result->isInteger());
- QCOMPARE(result->int_32(), 42);
-}
-
-void tst_v4traced::construct()
-{
- EnvVarSaver forceTracing("QV4_FORCE_TRACING", "1");
- EnvVarSaver jitCallThreshold("QV4_JIT_CALL_THRESHOLD", "1");
-
- QV4::ExecutionEngine vm;
- QV4::Scope scope(&vm);
- QV4::ScopedContext ctx(scope, vm.rootContext());
- QV4::ScopedObject obj(scope, vm.newObject());
- vm.globalObject->defineDefaultProperty(QLatin1String("oracle"), obj);
- obj->defineDefaultProperty("answer", QV4::Primitive::fromInt32(32));
-
- QString code = QStringLiteral(
- "function doit() {\n"
- " this.arr = new Array()\n"
- " this.arr[0] = 0\n"
- " this.arr[1] = 1\n"
- " this.arr[2] = 2\n"
- "}\n"
- "var o\n"
- "for (var i = 0; i < 10; ++i) o = new doit()\n"
- "o.arr\n");
- QScopedPointer<QV4::Script> script;
- script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, "setLookup"));
- script->parseAsBinding = false;
-
- QVERIFY(!scope.engine->hasException);
- script->parse();
- QVERIFY(!scope.engine->hasException);
-
- QV4::ScopedValue result(scope, script->run());
- QVERIFY(!scope.engine->hasException);
-
- QVERIFY(result->as<QV4::ArrayObject>());
-}
-
-QTEST_MAIN(tst_v4traced)
-
-#include "tst_v4traced.moc"
diff --git a/tests/auto/qml/v4traced/v4traced.pro b/tests/auto/qml/v4traced/v4traced.pro
deleted file mode 100644
index cbc8f38046..0000000000
--- a/tests/auto/qml/v4traced/v4traced.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase
-TARGET = tst_v4traced
-macos:CONFIG -= app_bundle
-QT += core-private qml-private testlib
-SOURCES += tst_v4traced.cpp