aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml')
-rw-r--r--tests/auto/qml/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp4
-rw-r--r--tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp14
-rw-r--r--tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp13
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp7
-rw-r--r--tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST2
-rw-r--r--tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp10
-rw-r--r--tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro11
-rw-r--r--tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp360
-rw-r--r--tests/auto/qml/debugger/debugger.pro9
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro4
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp93
-rw-r--r--tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro3
-rw-r--r--tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro1
-rw-r--r--tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp10
-rw-r--r--tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro2
-rw-r--r--tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp161
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml49
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/condition.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml19
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/exception.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/quit.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.js (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/timer.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro26
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro25
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp1552
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro12
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp1008
-rw-r--r--tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.cpp (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.pro9
-rw-r--r--tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro1
-rw-r--r--tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp8
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro4
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro14
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp126
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp39
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro11
-rw-r--r--tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro2
-rw-r--r--tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp40
-rw-r--r--tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro4
-rw-r--r--tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp81
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro6
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp130
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro5
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp330
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro5
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp85
-rw-r--r--tests/auto/qml/debugger/qqmlnativeconnector/tst_qqmlnativeconnector.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/broken.qml31
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/i18n/qml_fr_FR.qm0
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/qtquick2.qml71
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/window.qml44
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/window1.qml43
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/window2.qml43
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/data/zoom.qml51
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/qqmlpreview.pro25
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp365
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/batchOverflow.qml20
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml7
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml2
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml17
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml9
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/quit.qml40
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro9
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp860
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp168
-rw-r--r--tests/auto/qml/debugger/shared/debugutil.cpp281
-rw-r--r--tests/auto/qml/debugger/shared/debugutil.pri11
-rw-r--r--tests/auto/qml/debugger/shared/debugutil_p.h115
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugprocess.cpp249
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugprocess_p.h101
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp1
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugtestservice.h3
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp508
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.h233
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.pri3
-rw-r--r--tests/auto/qml/debugger/shared/qqmlinspectorclient.cpp124
-rw-r--r--tests/auto/qml/debugger/shared/qqmlinspectorclient.pri3
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations892
-rw-r--r--tests/auto/qml/ecmascripttests/ecmascripttests.pro15
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/main.cpp114
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/qjstest.pro13
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp852
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.h132
m---------tests/auto/qml/ecmascripttests/test2620
-rwxr-xr-xtests/auto/qml/ecmascripttests/test262.py141
-rw-r--r--tests/auto/qml/ecmascripttests/testcase.pro15
-rw-r--r--tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp46
-rw-r--r--tests/auto/qml/qjsengine/exporterror1.mjs2
-rw-r--r--tests/auto/qml/qjsengine/importerror1.mjs2
-rw-r--r--tests/auto/qml/qjsengine/modulewithlexicals.mjs9
-rw-r--r--tests/auto/qml/qjsengine/qjsengine.pro1
-rw-r--r--tests/auto/qml/qjsengine/testmodule.mjs6
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp845
-rw-r--r--tests/auto/qml/qjsonbinding/qjsonbinding.pro1
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp96
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.h1
-rw-r--r--tests/auto/qml/qml.pro32
-rw-r--r--tests/auto/qml/qmlcachegen/Enums.qml9
-rw-r--r--tests/auto/qml/qmlcachegen/Retain.qml2
-rw-r--r--tests/auto/qml/qmlcachegen/jsimport.qml6
-rw-r--r--tests/auto/qml/qmlcachegen/jsmoduleimport.qml6
-rw-r--r--tests/auto/qml/qmlcachegen/library.js4
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro22
-rw-r--r--tests/auto/qml/qmlcachegen/retain.qrc5
-rw-r--r--tests/auto/qml/qmlcachegen/script.js6
-rw-r--r--tests/auto/qml/qmlcachegen/script.mjs4
-rw-r--r--tests/auto/qml/qmlcachegen/trickypaths.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/trickypaths.qrc7
-rw-r--r--tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc5
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp465
-rw-r--r--tests/auto/qml/qmlcachegen/umlaut.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/versionchecks.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/worker.js3
-rw-r--r--tests/auto/qml/qmlcachegen/worker.qml12
-rw-r--r--tests/auto/qml/qmldiskcache/importmodule.qml5
-rw-r--r--tests/auto/qml/qmldiskcache/module.mjs2
-rw-r--r--tests/auto/qml/qmldiskcache/qmldiskcache.pro2
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp287
-rw-r--r--tests/auto/qml/qmlmin/qmlmin.pro6
-rw-r--r--tests/auto/qml/qmlmin/tst_qmlmin.cpp5
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/Singleton.qml (renamed from tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/Singleton.qml)0
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/qmldir (renamed from tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/qmldir)2
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml5
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml6
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir4
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.cpp39
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.h44
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.pro23
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.cpp40
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.h44
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/plugins.qmltypes17
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Dummy/qmldir3
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/extendedtype.pro22
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.cpp40
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.h43
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugins.qmltypes35
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/qmldir3
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/types.h86
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/CompositeImports.qml5
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.cpp39
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.h44
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro24
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.cpp40
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.h44
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes17
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir3
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Singleton/CompositeSingleton.qml6
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Singleton/qmldir2
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/plugin.qmltypes23
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/plugins.qmltypes23
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/qmldir3
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.cpp39
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.h (renamed from tests/auto/qml/debugger/shared/qqmlinspectorclient.h)46
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.pro23
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.cpp41
-rw-r--r--tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.h44
-rw-r--r--tests/auto/qml/qmlplugindump/qmlplugindump.pro12
-rw-r--r--tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp61
-rw-r--r--tests/auto/qml/qmlplugindump/tst_qmlplugindump.pro9
-rw-r--r--tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro6
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/delayedExit.qml11
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/delayedQuit.qml (renamed from tests/auto/qml/qqmlapplicationengine/testapp/main.qml)0
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/immediateExit.qml8
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/immediateQuit.qml8
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/main.cpp2
-rw-r--r--tests/auto/qml/qqmlapplicationengine/testapp/main.qrc5
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp44
-rw-r--r--tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp26
-rw-r--r--tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp29
-rw-r--r--tests/auto/qml/qqmlcomponent/data/InitialPropertyTest.qml4
-rw-r--r--tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml3
-rw-r--r--tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml3
-rw-r--r--tests/auto/qml/qqmlcomponent/data/nonExistentInitialProperty.qml9
-rw-r--r--tests/auto/qml/qqmlcomponent/qqmlcomponent.pro3
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp195
-rw-r--r--tests/auto/qml/qqmlconnections/data/override-proxy-type.qml13
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp57
-rw-r--r--tests/auto/qml/qqmlconsole/data/categorized_logging.qml14
-rw-r--r--tests/auto/qml/qqmlconsole/data/logging.qml4
-rw-r--r--tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp51
-rw-r--r--tests/auto/qml/qqmlcontext/data/ContextLeak.js1
-rw-r--r--tests/auto/qml/qqmlcontext/data/Drawer.qml6
-rw-r--r--tests/auto/qml/qqmlcontext/data/MyItem.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/Singleton.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextLeak.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextObjectHierarchy.qml6
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml14
-rw-r--r--tests/auto/qml/qqmlcontext/data/outerContextObject.qml18
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp211
-rw-r--r--tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.1.qml25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.2.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.3.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.4.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.5.qml37
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.6.qml33
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignDate.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml34
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicString.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs31
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_callback.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/js/include2.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js (renamed from tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir (renamed from tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nans.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qmlVarNullBinding.qml7
-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/remote/com/qt/JsRemoteModule/ScriptAPI.js (renamed from tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/ScriptAPI.js)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir (renamed from tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalHandlers.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/singletonTest.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/singletonTest2.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/qqmlecmascript.pro1
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp25
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h26
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp1638
-rw-r--r--tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml10
-rw-r--r--tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml10
-rw-r--r--tests/auto/qml/qqmlengine/data/qrcurls.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/qrcurls.qml4
-rw-r--r--tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml7
-rw-r--r--tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml7
-rw-r--r--tests/auto/qml/qqmlengine/qqmlengine.pro9
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp263
-rw-r--r--tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro2
-rw-r--r--tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp65
-rw-r--r--tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp14
-rw-r--r--tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp7
-rw-r--r--tests/auto/qml/qqmlfile/qqmlfile.pro5
-rw-r--r--tests/auto/qml/qqmlfile/tst_qqmlfile.cpp (renamed from tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp)40
-rw-r--r--tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp27
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp6
-rw-r--r--tests/auto/qml/qqmlincubator/data/garbageCollection.qml19
-rw-r--r--tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt2
-rw-r--r--tests/auto/qml/qqmlincubator/testtypes.cpp28
-rw-r--r--tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp114
-rw-r--r--tests/auto/qml/qqmlinfo/data/Component.qml8
-rw-r--r--tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp62
-rw-r--r--tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro1
-rw-r--r--tests/auto/qml/qqmlinstantiator/stringmodel.h14
-rw-r--r--tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp18
-rw-r--r--tests/auto/qml/qqmlitemmodels/qtestmodel.h2
-rw-r--r--tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml19
-rw-r--r--tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml28
-rw-r--r--tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.15.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.16.qml15
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml1
-rw-r--r--tests/auto/qml/qqmllanguage/data/circularSingleton.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/deferredProperties.qml19
-rw-r--r--tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/empty.errors.txt3
-rw-r--r--tests/auto/qml/qqmllanguage/data/groupPropertyInPropertyValueSource.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.1.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.2.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/importJsModule.3.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.1.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.3.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidID.10.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidID.10.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir4
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js1
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs4
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml2
-rw-r--r--tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir3
-rw-r--r--tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/data/property.4.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/scopedEnumsWithNameClash.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/scopedEnumsWithResolvedNameClash.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/js/jspragma.js14
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest17.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest18.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml15
-rw-r--r--tests/auto/qml/qqmllanguage/data/wrongType.16.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/qqmllanguage.pro1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp30
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h75
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp1436
-rw-r--r--tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp122
-rw-r--r--tests/auto/qml/qqmllistmodel/data/dynamicroles.qml21
-rw-r--r--tests/auto/qml/qqmllistmodel/data/qtbug38907.qml25
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp215
-rw-r--r--tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp31
-rw-r--r--tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp36
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp18
-rw-r--r--tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp8
-rw-r--r--tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml6
-rw-r--r--tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml6
-rw-r--r--tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml8
-rw-r--r--tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml8
-rw-r--r--tests/auto/qml/qqmlmetatype/qqmlmetatype.pro4
-rw-r--r--tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp424
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro12
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp4
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2.2/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro1
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp173
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro8
-rw-r--r--tests/auto/qml/qqmlnotifier/data/objectRenamer.qml9
-rw-r--r--tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp88
-rw-r--r--tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp44
-rw-r--r--tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp4
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp92
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml58
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml83
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml83
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml86
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml56
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml64
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml67
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-get-length.qml43
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml52
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml62
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml57
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml75
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml57
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml43
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml54
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml55
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml93
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml63
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml72
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml59
-rw-r--r--tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml65
-rw-r--r--tests/auto/qml/qqmlpromise/qqmlpromise.pro46
-rw-r--r--tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp276
-rw-r--r--tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml9
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp282
-rw-r--r--tests/auto/qml/qqmlpropertycache/data/foreignEnums.qml17
-rw-r--r--tests/auto/qml/qqmlpropertycache/data/passQGadget.qml12
-rw-r--r--tests/auto/qml/qqmlpropertycache/qqmlpropertycache.pro4
-rw-r--r--tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp179
-rw-r--r--tests/auto/qml/qqmlpropertymap/data/PropertyMapSubType.qml9
-rw-r--r--tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp31
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp91
-rw-r--r--tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp49
-rw-r--r--tests/auto/qml/qqmlsqldatabase/data/changeVersion.qml67
-rw-r--r--tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp19
-rw-r--r--tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp9
-rw-r--r--tests/auto/qml/qqmltablemodel/data/TestModel.qml47
-rw-r--r--tests/auto/qml/qqmltablemodel/data/TestUtils.js45
-rw-r--r--tests/auto/qml/qqmltablemodel/data/builtInRoles.qml47
-rw-r--r--tests/auto/qml/qqmltablemodel/data/common.qml128
-rw-r--r--tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml66
-rw-r--r--tests/auto/qml/qqmltablemodel/data/empty.qml68
-rw-r--r--tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml41
-rw-r--r--tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml65
-rw-r--r--tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml99
-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.cpp947
-rw-r--r--tests/auto/qml/qqmltimer/tst_qqmltimer.cpp34
-rw-r--r--tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml5
-rw-r--r--tests/auto/qml/qqmltranslation/data/translationChange.qml32
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp68
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Base.qml3
-rw-r--r--tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml9
-rw-r--r--tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml6
-rw-r--r--tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Fast/Fast.qml4
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Fast/qmldir1
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Intercept.qml41
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Load.qml11
-rw-r--r--tests/auto/qml/qqmltypeloader/data/Singleton.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/ValueSource.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/implicitcomponent.qml10
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml7
-rw-r--r--tests/auto/qml/qqmltypeloader/data/redirected/Imported.qml5
-rw-r--r--tests/auto/qml/qqmltypeloader/data/redirected/Redirected.qml5
-rw-r--r--tests/auto/qml/qqmltypeloader/data/redirected/qmldir1
-rw-r--r--tests/auto/qml/qqmltypeloader/data/singletonuser.qml6
-rw-r--r--tests/auto/qml/qqmltypeloader/data/test_intercept.qml53
-rw-r--r--tests/auto/qml/qqmltypeloader/data/trim_cache3.qml14
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp391
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro7
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp18
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp250
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js11
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expectbin0 -> 223 bytes
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml23
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/status.qml13
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro1
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp32
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/data/sortdir/Uppercase.txt0
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/data/sortdir/lowercase.txt0
-rw-r--r--tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp85
-rw-r--r--tests/auto/qml/qquickworkerscript/data/messagehandler.mjs4
-rw-r--r--tests/auto/qml/qquickworkerscript/data/script_global.js5
-rw-r--r--tests/auto/qml/qquickworkerscript/data/script_global2.js6
-rw-r--r--tests/auto/qml/qquickworkerscript/data/script_module.mjs5
-rw-r--r--tests/auto/qml/qquickworkerscript/data/worker_global.qml5
-rw-r--r--tests/auto/qml/qquickworkerscript/data/worker_global2.qml5
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp106
-rw-r--r--tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp6
-rw-r--r--tests/auto/qml/qv4assembler/data/crash.qml53
-rw-r--r--tests/auto/qml/qv4assembler/qv4assembler.pro12
-rw-r--r--tests/auto/qml/qv4assembler/tst_qv4assembler.cpp143
-rw-r--r--tests/auto/qml/qv4identifiertable/qv4identifiertable.pro8
-rw-r--r--tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp363
-rw-r--r--tests/auto/qml/qv4mm/data/createdestroy.qml60
-rw-r--r--tests/auto/qml/qv4mm/qv4mm.pro6
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp67
-rw-r--r--tests/auto/qml/qv4regexp/qv4regexp.pro8
-rw-r--r--tests/auto/qml/qv4regexp/tst_qv4regexp.cpp53
-rw-r--r--tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro7
-rw-r--r--tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp283
-rw-r--r--tests/auto/qml/v4misc/tst_v4misc.cpp314
-rw-r--r--tests/auto/qml/v4traced/tst_v4traced.cpp325
-rw-r--r--tests/auto/qml/v4traced/v4traced.pro5
510 files changed, 20971 insertions, 6644 deletions
diff --git a/tests/auto/qml/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp b/tests/auto/qml/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp
index c81fd37f07..7e19e925b6 100644
--- a/tests/auto/qml/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp
+++ b/tests/auto/qml/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp
@@ -53,7 +53,7 @@ private slots:
class TestableQAbstractAnimation : public QAbstractAnimationJob
{
public:
- TestableQAbstractAnimation() : m_duration(10) {}
+ TestableQAbstractAnimation() {}
virtual ~TestableQAbstractAnimation() {};
int duration() const { return m_duration; }
@@ -61,7 +61,7 @@ public:
void setDuration(int duration) { m_duration = duration; }
private:
- int m_duration;
+ int m_duration = 10;
};
class DummyQAnimationGroup : public QAnimationGroupJob
diff --git a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
index b7f8280c5b..6bd8c2a2e0 100644
--- a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
@@ -71,10 +71,7 @@ class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
{
Q_OBJECT
public:
- UncontrolledAnimation()
- : id(0)
- {
- }
+ UncontrolledAnimation() { }
int duration() const { return -1; /* not time driven */ }
@@ -96,7 +93,7 @@ protected:
}
private:
- int id;
+ int id = 0;
};
class StateChangeListener: public QAnimationJobChangeListener
@@ -264,15 +261,18 @@ void tst_QAnimationGroupJob::addChildTwice()
{
QAbstractAnimationJob *subGroup;
QAbstractAnimationJob *subGroup2;
- QAnimationGroupJob *parent = new QSequentialAnimationGroupJob();
+ auto *parent = new QSequentialAnimationGroupJob();
subGroup = new QAbstractAnimationJob;
parent->appendAnimation(subGroup);
parent->appendAnimation(subGroup);
- QVERIFY(parent->firstChild() && !parent->firstChild()->nextSibling());
+ QVERIFY(parent->firstChild());
+ QVERIFY(!parent->firstChild()->nextSibling());
+ QVERIFY(!parent->firstChild()->previousSibling());
parent->clear();
+ QCOMPARE(parent->currentAnimation(), nullptr);
QVERIFY(!parent->firstChild());
// adding the same item twice to a group will remove the item from its current position
diff --git a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
index 476ad2e955..a8bcadbc84 100644
--- a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
@@ -89,7 +89,6 @@ class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
Q_OBJECT
public:
UncontrolledAnimation()
- : id(0)
{
}
@@ -113,7 +112,7 @@ protected:
}
private:
- int id;
+ int id = 0;
};
class StateChangeListener: public QAnimationJobChangeListener
@@ -133,14 +132,14 @@ public:
class FinishedListener: public QAnimationJobChangeListener
{
public:
- FinishedListener() : m_count(0) {}
+ FinishedListener() {}
virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; }
void clear() { m_count = 0; }
int count() { return m_count; }
private:
- int m_count;
+ int m_count = 0;
};
void tst_QParallelAnimationGroupJob::setCurrentTime()
@@ -685,10 +684,10 @@ void tst_QParallelAnimationGroupJob::stopUncontrolledAnimations()
}
struct AnimState {
- AnimState(int time = -1) : time(time), state(-1) {}
+ AnimState(int time = -1) : time(time) {}
AnimState(int time, int state) : time(time), state(state) {}
int time;
- int state;
+ int state = -1;
};
#define Running QAbstractAnimationJob::Running
@@ -848,7 +847,7 @@ void tst_QParallelAnimationGroupJob::addAndRemoveDuration()
QCOMPARE(group.duration(), 250);
group.removeAnimation(test); // remove the last one (with duration = 250)
- QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(0));
+ QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(nullptr));
QCOMPARE(group.duration(), 0);
delete test;
}
diff --git a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
index ff295c5409..8f6b6a2ab7 100644
--- a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
+++ b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -39,17 +39,14 @@ static const char winTimerError[] = "On windows, consistent timing is not workin
class TestablePauseAnimation : public QPauseAnimationJob
{
public:
- TestablePauseAnimation()
- : m_updateCurrentTimeCount(0)
- {
- }
+ TestablePauseAnimation() { }
TestablePauseAnimation(int duration)
: QPauseAnimationJob(duration), m_updateCurrentTimeCount(0)
{
}
- int m_updateCurrentTimeCount;
+ int m_updateCurrentTimeCount = 0;
protected:
void updateCurrentTime(int currentTime)
{
diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST b/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST
deleted file mode 100644
index 2afe6074d7..0000000000
--- a/tests/auto/qml/animation/qsequentialanimationgroupjob/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[finishWithUncontrolledAnimation]
-*
diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
index ee5db3e75a..57b0905a8a 100644
--- a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
@@ -95,7 +95,7 @@ class TestValueAnimation : public TestAnimation
{
public:
TestValueAnimation(int duration = 250)
- : TestAnimation(duration), start(0), end(0), value(0) {}
+ : TestAnimation(duration) {}
void updateCurrentTime(int msecs)
{
@@ -105,8 +105,8 @@ public:
value = start + (end - start) * (qreal(msecs) / duration());
}
- qreal start, end;
- qreal value;
+ qreal start = 0, end = 0;
+ qreal value = 0;
};
class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
@@ -140,14 +140,14 @@ public:
class FinishedListener: public QAnimationJobChangeListener
{
public:
- FinishedListener() : m_count(0) {}
+ FinishedListener() {}
virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; }
void clear() { m_count = 0; }
int count() { return m_count; }
private:
- int m_count;
+ int m_count = 0;
};
void tst_QSequentialAnimationGroupJob::setCurrentTime()
diff --git a/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro b/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro
new file mode 100644
index 0000000000..430d87ab5b
--- /dev/null
+++ b/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_bindingdependencyapi
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_bindingdependencyapi.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core-private gui-private qml-private quick-private testlib
diff --git a/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp
new file mode 100644
index 0000000000..82c997a5b8
--- /dev/null
+++ b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlbinding_p.h>
+#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
+#include "../../shared/util.h"
+#include <qqmlcontext.h>
+
+class tst_bindingdependencyapi : public QObject
+{
+ Q_OBJECT
+public:
+ tst_bindingdependencyapi();
+
+private slots:
+ void testSingleDep_data();
+ void testSingleDep();
+ void testManyDeps_data();
+ void testManyDeps();
+ void testConditionalDependencies_data();
+ void testConditionalDependencies();
+ void testBindingLoop();
+
+private:
+ bool findProperties(const QVector<QQmlProperty> &properties, QObject *obj, const QString &propertyName, const QVariant &value);
+};
+
+tst_bindingdependencyapi::tst_bindingdependencyapi()
+{
+}
+
+
+void tst_bindingdependencyapi::testSingleDep_data()
+{
+ QTest::addColumn<QByteArray>("code");
+ QTest::addColumn<QString>("referencedObjectName");
+
+ QTest::addRow("context property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "objectName: \"rect\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { text: labelText }\n"
+ "}") << "rect";
+
+ QTest::addRow("scope property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "property string labelText: \"I am wrong!\"\n"
+ "Text {\n"
+ "objectName: \"text\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "text: labelText\n"
+ "}\n"
+ "}") << "text";
+
+ QTest::addRow("id object property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: \"rect\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { text: rect.labelText }\n"
+ "}") << "rect";
+
+ QTest::addRow("dynamic context property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "objectName: \"rect\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { Component.onCompleted: text = Qt.binding(function() { return labelText; }); }\n"
+ "}") << "rect";
+
+ QTest::addRow("dynamic scope property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "property string labelText: \"I am wrong!\"\n"
+ "Text {\n"
+ "objectName: \"text\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Component.onCompleted: text = Qt.binding(function() { return labelText; });\n"
+ "}\n"
+ "}") << "text";
+
+ QTest::addRow("dynamic id object property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: \"rect\"\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { Component.onCompleted: text = Qt.binding(function() { return rect.labelText; }); }\n"
+ "}") << "rect";
+}
+
+void tst_bindingdependencyapi::testSingleDep()
+{
+ QFETCH(QByteArray, code);
+ QFETCH(QString, referencedObjectName);
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(code, QUrl());
+ QObject *rect = c.create();
+ QTest::qWait(10);
+ QVERIFY(rect != nullptr);
+ QObject *text = rect->findChildren<QQuickText *>().front();
+
+ QObject *referencedObject = rect->objectName() == referencedObjectName ? rect : rect->findChild<QObject *>(referencedObjectName);
+
+ auto data = QQmlData::get(text);
+ QVERIFY(data);
+ auto b = data->bindings;
+ QVERIFY(b);
+ auto binding = dynamic_cast<QQmlBinding*>(b);
+ QVERIFY(binding);
+ auto dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 1);
+ auto dependency = dependencies.front();
+ QVERIFY(dependency.isValid());
+ QCOMPARE(quintptr(dependency.object()), quintptr(referencedObject));
+ QCOMPARE(dependency.property().name(), "labelText");
+ QCOMPARE(dependency.read().toString(), QStringLiteral("Hello world!"));
+ QCOMPARE(dependency, QQmlProperty(referencedObject, "labelText"));
+
+ delete rect;
+}
+
+bool tst_bindingdependencyapi::findProperties(const QVector<QQmlProperty> &properties, QObject *obj, const QString &propertyName, const QVariant &value)
+{
+ auto dep = std::find_if(properties.cbegin(), properties.cend(), [&](const QQmlProperty &dep) {
+ return dep.object() == obj
+ && dep.property().name() == propertyName
+ && dep.read() == value;
+ });
+ if (dep == properties.cend()) {
+ qWarning() << "Searched for property with:" << "{ object:" << obj << ", propertyName:" << propertyName << ", value:" << value << "}" << "but only found:";
+ for (auto dep : properties) {
+ qWarning() << "{ object:" << dep.object() << ", propertyName:" << dep.property().name() << ", value:" << dep.read() << "}";
+ }
+ return false;
+ }
+ return true;
+}
+
+void tst_bindingdependencyapi::testManyDeps_data()
+{
+ QTest::addColumn<QByteArray>("code");
+
+ QTest::addRow("permanent binding")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: 'rect'\n"
+ "property string name: 'world'\n"
+ "Text {\n"
+ "text: config.helloWorldTemplate.arg(greeting).arg(rect.name) \n"
+ "property string greeting: 'Hello'\n"
+ "}\n"
+ "QtObject { id: config; objectName: 'config'; property string helloWorldTemplate: '%1 %2!' }\n"
+ "}");
+
+ QTest::addRow("dynamic binding")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: 'rect'\n"
+ "property string name: 'world'\n"
+ "Text {\n"
+ "Component.onCompleted: text = Qt.binding(function() { return config.helloWorldTemplate.arg(greeting).arg(rect.name); }); \n"
+ "property string greeting: 'Hello'\n"
+ "}\n"
+ "QtObject { id: config; objectName: 'config'; property string helloWorldTemplate: '%1 %2!' }\n"
+ "}");
+}
+
+void tst_bindingdependencyapi::testManyDeps()
+{
+ QFETCH(QByteArray, code);
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(code, QUrl());
+ QObject *rect = c.create();
+ if (c.isError()) {
+ qWarning() << c.errorString();
+ }
+ QTest::qWait(100);
+ QVERIFY(rect != nullptr);
+ QObject *text = rect->findChildren<QQuickText *>().front();
+ QObject *configObj = rect->findChild<QObject *>("config");
+
+ auto data = QQmlData::get(text);
+ QVERIFY(data);
+ auto b = data->bindings;
+ QVERIFY(b);
+ auto binding = dynamic_cast<QQmlBinding*>(b);
+ QVERIFY(binding);
+ auto dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 3);
+
+ QVERIFY(findProperties(dependencies, rect, "name", "world"));
+ QVERIFY(findProperties(dependencies, text, "greeting", "Hello"));
+ QVERIFY(findProperties(dependencies, configObj, "helloWorldTemplate", "%1 %2!"));
+
+ delete rect;
+}
+
+void tst_bindingdependencyapi::testConditionalDependencies_data()
+{
+ QTest::addColumn<QByteArray>("code");
+ QTest::addColumn<QString>("referencedObjectName");
+
+ QTest::addRow("id object property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: \"rect\"\n"
+ "property bool haveDep: false\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { text: rect.haveDep ? rect.labelText : '' }\n"
+ "}") << "rect";
+
+ QTest::addRow("dynamic context property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "objectName: \"rect\"\n"
+ "property bool haveDep: false\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { Component.onCompleted: text = Qt.binding(function() { return haveDep ? labelText : ''; }); }\n"
+ "}") << "rect";
+
+ QTest::addRow("dynamic scope property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "property string labelText: \"I am wrong!\"\n"
+ "Text {\n"
+ "objectName: \"text\"\n"
+ "property bool haveDep: false\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Component.onCompleted: text = Qt.binding(function() { return haveDep ? labelText : ''; });\n"
+ "}\n"
+ "}") << "text";
+
+ QTest::addRow("dynamic id object property")
+ << QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id: rect\n"
+ "objectName: \"rect\"\n"
+ "property bool haveDep: false\n"
+ "property string labelText: \"Hello world!\"\n"
+ "Text { Component.onCompleted: text = Qt.binding(function() { return rect.haveDep ? rect.labelText : ''; }); }\n"
+ "}") << "rect";
+}
+
+void tst_bindingdependencyapi::testConditionalDependencies()
+{
+ QFETCH(QByteArray, code);
+ QFETCH(QString, referencedObjectName);
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(code, QUrl());
+ QObject *rect = c.create();
+ QTest::qWait(10);
+ QVERIFY(rect != nullptr);
+ QObject *text = rect->findChildren<QQuickText *>().front();
+
+ QObject *referencedObject = rect->objectName() == referencedObjectName ? rect : rect->findChild<QObject *>(referencedObjectName);
+
+ auto data = QQmlData::get(text);
+ QVERIFY(data);
+ auto b = data->bindings;
+ QVERIFY(b);
+ auto binding = dynamic_cast<QQmlBinding*>(b);
+ QVERIFY(binding);
+ auto dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 1);
+ QVERIFY(findProperties(dependencies, referencedObject, "haveDep", false));
+
+ referencedObject->setProperty("haveDep", true);
+ dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 2);
+ QVERIFY(findProperties(dependencies, referencedObject, "haveDep", true));
+ QVERIFY(findProperties(dependencies, referencedObject, "labelText", "Hello world!"));
+
+ referencedObject->setProperty("haveDep", false);
+ dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 1);
+ QVERIFY(findProperties(dependencies, referencedObject, "haveDep", false));
+
+ delete rect;
+}
+
+void tst_bindingdependencyapi::testBindingLoop()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine);
+ c.setData(QByteArray("import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "property string labelText: label.text\n"
+ "Text {\n"
+ "id: label\n"
+ "text: labelText\n"
+ "}\n"
+ "}"), QUrl());
+ QObject *rect = c.create();
+ if (c.isError()) {
+ qWarning() << c.errorString();
+ }
+ QTest::qWait(100);
+ QVERIFY(rect != nullptr);
+ QObject *text = rect->findChildren<QQuickText *>().front();
+
+ auto data = QQmlData::get(text);
+ QVERIFY(data);
+ auto b = data->bindings;
+ QVERIFY(b);
+ auto binding = dynamic_cast<QQmlBinding*>(b);
+ QVERIFY(binding);
+ auto dependencies = binding->dependencies();
+ QCOMPARE(dependencies.size(), 1);
+ auto dependency = dependencies.front();
+ QVERIFY(dependency.isValid());
+ QCOMPARE(quintptr(dependency.object()), quintptr(rect));
+ QCOMPARE(dependency.property().name(), "labelText");
+
+ delete rect;
+}
+
+QTEST_MAIN(tst_bindingdependencyapi)
+
+#include "tst_bindingdependencyapi.moc"
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
index a50411e18b..5c328fbfcc 100644
--- a/tests/auto/qml/debugger/debugger.pro
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -1,5 +1,7 @@
TEMPLATE = subdirs
+SUBDIRS += qqmldebugjsserver
+
PUBLICTESTS += \
qdebugmessageservice \
qqmlenginedebugservice \
@@ -10,7 +12,9 @@ PUBLICTESTS += \
qqmlenginedebuginspectorintegrationtest \
qqmlenginecontrol \
qqmldebuggingenabler \
- qqmlnativeconnector
+ qqmlnativeconnector \
+ qqmldebugprocess \
+ qqmlpreview
PRIVATETESTS += \
qqmldebugclient \
@@ -20,6 +24,9 @@ PRIVATETESTS += \
SUBDIRS += $$PUBLICTESTS
+qqmldebugjs.depends = qqmldebugjsserver
+qqmlprofilerservice.depends = qqmldebugjsserver
+
qtConfig(private_tests): \
SUBDIRS += $$PRIVATETESTS
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro
index 6c729ab235..3f2c0ca390 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro
+++ b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro
@@ -1,12 +1,10 @@
CONFIG += testcase
TARGET = tst_qdebugmessageservice
-QT += qml network testlib gui-private core-private
+QT += network testlib gui-private core-private
osx:CONFIG -= app_bundle
SOURCES += tst_qdebugmessageservice.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index f193d3928a..d2cfd3897a 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -28,7 +28,6 @@
//QQmlDebugTest
#include "debugutil_p.h"
-#include "../../../shared/util.h"
#include <private/qqmldebugclient_p.h>
#include <private/qqmldebugconnection_p.h>
@@ -38,31 +37,19 @@
#include <QtCore/qlibraryinfo.h>
#include <QtTest/qtest.h>
-const char *NORMALMODE = "-qmljsdebugger=port:3777,3787,block";
const char *QMLFILE = "test.qml";
class QQmlDebugMsgClient;
-class tst_QDebugMessageService : public QQmlDataTest
+class tst_QDebugMessageService : public QQmlDebugTest
{
Q_OBJECT
-public:
- tst_QDebugMessageService();
-
- void init();
-
private slots:
- void initTestCase();
- void cleanupTestCase();
-
- void cleanup();
-
void retrieveDebugOutput();
private:
- QQmlDebugProcess *m_process;
- QQmlDebugMsgClient *m_client;
- QQmlDebugConnection *m_connection;
+ QList<QQmlDebugClient *> createClients() override;
+ QPointer<QQmlDebugMsgClient> m_client;
};
struct LogEntry {
@@ -102,21 +89,12 @@ public:
protected:
//inherited from QQmlDebugClient
- void stateChanged(State state);
void messageReceived(const QByteArray &data);
signals:
- void enabled();
void debugOutput();
};
-void QQmlDebugMsgClient::stateChanged(State state)
-{
- if (state == Enabled) {
- emit enabled();
- }
-}
-
void QQmlDebugMsgClient::messageReceived(const QByteArray &data)
{
QPacket ds(connection()->currentDataStreamVersion(), data);
@@ -150,73 +128,16 @@ void QQmlDebugMsgClient::messageReceived(const QByteArray &data)
}
}
-tst_QDebugMessageService::tst_QDebugMessageService()
-{
-}
-
-void tst_QDebugMessageService::initTestCase()
+QList<QQmlDebugClient *> tst_QDebugMessageService::createClients()
{
- QQmlDataTest::initTestCase();
- m_process = 0;
- m_client = 0;
- m_connection = 0;
-}
-
-void tst_QDebugMessageService::cleanupTestCase()
-{
- if (m_process)
- delete m_process;
-
- if (m_client)
- delete m_client;
-
- if (m_connection)
- delete m_connection;
-}
-
-void tst_QDebugMessageService::init()
-{
- m_connection = new QQmlDebugConnection();
- m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", this);
m_client = new QQmlDebugMsgClient(m_connection);
-
- m_process->start(QStringList() << QLatin1String(NORMALMODE) << QQmlDataTest::instance()->testFile(QMLFILE));
- QVERIFY2(m_process->waitForSessionStart(),
- "Could not launch application, or did not get 'Waiting for connection'.");
-
- const int port = m_process->debugPort();
- m_connection->connectToHost("127.0.0.1", port);
- QVERIFY(m_connection->waitForConnected());
-
- if (m_client->state() != QQmlDebugClient::Enabled)
- QQmlDebugTest::waitForSignal(m_client, SIGNAL(enabled()));
-
- QCOMPARE(m_client->state(), QQmlDebugClient::Enabled);
-}
-
-void tst_QDebugMessageService::cleanup()
-{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << m_process->state();
- qDebug() << "Application Output:" << m_process->output();
- }
- if (m_process)
- delete m_process;
-
- if (m_client)
- delete m_client;
-
- if (m_connection)
- delete m_connection;
-
- m_process = 0;
- m_client = 0;
- m_connection = 0;
+ return QList<QQmlDebugClient *>({m_client});
}
void tst_QDebugMessageService::retrieveDebugOutput()
{
- init();
+ QCOMPARE(QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ QString(), testFile(QMLFILE), true), ConnectSuccess);
QTRY_VERIFY(m_client->logBuffer.size() >= 2);
diff --git a/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro
index a7c0fa7f8e..dc0120cd87 100644
--- a/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro
+++ b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro
@@ -4,7 +4,6 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qpacketprotocol.cpp
-INCLUDEPATH += ../shared
include(../shared/debugutil.pri)
-QT += qml network testlib gui-private core-private
+QT += network testlib gui-private core-private
diff --git a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp
index cadc2a7cc4..21ca921304 100644
--- a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp
+++ b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp
@@ -60,7 +60,7 @@ private slots:
void tst_QPacketProtocol::init()
{
m_server = new QTcpServer(this);
- m_serverConn = 0;
+ m_serverConn = nullptr;
QVERIFY(m_server->listen(QHostAddress("127.0.0.1")));
m_client = new QTcpSocket(this);
diff --git a/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro
index 622b373692..673330a3cf 100644
--- a/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro
+++ b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro
@@ -7,7 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h
SOURCES += tst_qqmldebugclient.cpp \
../shared/qqmldebugtestservice.cpp
-INCLUDEPATH += ../shared
include(../shared/debugutil.pri)
DEFINES += QT_QML_DEBUG_NO_WARNING
diff --git a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
index 04bc5c3c1a..ffdbf72ded 100644
--- a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
+++ b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
@@ -66,17 +66,15 @@ void tst_QQmlDebugClient::initTestCase()
QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer"));
QQmlDebugConnector::setServices(QStringList()
<< QStringLiteral("tst_QQmlDebugClient::handshake()"));
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugClient::handshake()");
foreach (const QString &service, QQmlDebuggingEnabler::debuggerServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
foreach (const QString &service, QQmlDebuggingEnabler::inspectorServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
foreach (const QString &service, QQmlDebuggingEnabler::profilerServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
const QString waitingMsg = QString("QML Debugger: Waiting for connection on port %1...").arg(PORT);
QTest::ignoreMessage(QtDebugMsg, waitingMsg.toLatin1().constData());
@@ -126,7 +124,7 @@ void tst_QQmlDebugClient::state()
QQmlDebugClient client2("tst_QQmlDebugClient::state()", m_conn);
QCOMPARE(client2.state(), QQmlDebugClient::NotConnected);
- QQmlDebugClient client3("tst_QQmlDebugClient::state3()", 0);
+ QQmlDebugClient client3("tst_QQmlDebugClient::state3()", nullptr);
QCOMPARE(client3.state(), QQmlDebugClient::NotConnected);
}
diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro
index f8014f04f4..bd382ebaab 100644
--- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro
+++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro
@@ -6,8 +6,6 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qqmldebuggingenabler.cpp
-INCLUDEPATH += ../../shared
-include(../../../../shared/util.pri)
include(../../shared/debugutil.pri)
OTHER_FILES += data/test.qml
diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
index 3aa3a5c87e..37118f4bd0 100644
--- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
+++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
@@ -27,11 +27,14 @@
****************************************************************************/
#include "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
#include "../../../shared/util.h"
#include <private/qqmldebugclient_p.h>
#include <private/qqmldebugconnection_p.h>
+#include <QtQml/qqmldebug.h>
+
#include <QtTest/qtest.h>
#include <QtCore/qprocess.h>
#include <QtCore/qtimer.h>
@@ -40,17 +43,11 @@
#include <QtCore/qmutex.h>
#include <QtCore/qlibraryinfo.h>
-class tst_QQmlDebuggingEnabler : public QQmlDataTest
+class tst_QQmlDebuggingEnabler : public QQmlDebugTest
{
Q_OBJECT
- bool init(bool blockMode, bool qmlscene, int portFrom, int portTo);
-
private slots:
- void initTestCase();
- void cleanupTestCase();
- void cleanup();
-
void qmlscene_data();
void qmlscene();
void custom_data();
@@ -58,88 +55,8 @@ private slots:
private:
void data();
- QQmlDebugProcess *process;
- QQmlDebugConnection *connection;
- QTime t;
};
-void tst_QQmlDebuggingEnabler::initTestCase()
-{
- QQmlDataTest::initTestCase();
- t.start();
- process = 0;
- connection = 0;
-}
-
-void tst_QQmlDebuggingEnabler::cleanupTestCase()
-{
- if (process) {
- process->stop();
- delete process;
- }
-
- if (connection)
- delete connection;
-}
-
-bool tst_QQmlDebuggingEnabler::init(bool blockMode, bool qmlscene, int portFrom, int portTo)
-{
- connection = new QQmlDebugConnection();
-
- if (qmlscene) {
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
- process->setMaximumBindErrors(1);
- } else {
- process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() + QLatin1String("/qqmldebuggingenablerserver"), this);
- process->setMaximumBindErrors(portTo - portFrom);
- }
-
- if (qmlscene) {
- process->start(QStringList() << QLatin1String("-qmljsdebugger=port:") +
- QString::number(portFrom) + QLatin1Char(',') + QString::number(portTo) +
- QLatin1String(blockMode ? ",block": "") <<
- testFile(QLatin1String("test.qml")));
- } else {
- QStringList args;
- if (blockMode)
- args << QLatin1String("-block");
- args << QString::number(portFrom) << QString::number(portTo);
- process->start(args);
- }
-
- if (!process->waitForSessionStart()) {
- return false;
- }
-
- const int port = process->debugPort();
- connection->connectToHost("127.0.0.1", port);
- if (!connection->waitForConnected()) {
- qDebug() << "could not connect to host!";
- return false;
- }
- return true;
-}
-
-void tst_QQmlDebuggingEnabler::cleanup()
-{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << process->state();
- qDebug() << "Application Output:" << process->output();
- }
-
- if (process) {
- process->stop();
- delete process;
- }
-
-
- if (connection)
- delete connection;
-
- process = 0;
- connection = 0;
-}
-
void tst_QQmlDebuggingEnabler::data()
{
QTest::addColumn<QString>("connector");
@@ -185,32 +102,34 @@ void tst_QQmlDebuggingEnabler::qmlscene()
QFETCH(bool, blockMode);
QFETCH(QStringList, services);
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene",
- this);
- process->setMaximumBindErrors(1);
- process->start(QStringList()
- << QString::fromLatin1("-qmljsdebugger=connector:%1%2%3%4")
- .arg(connector + (connector == QLatin1String("QQmlDebugServer") ?
- QLatin1String(",port:5555,5565") : QString()))
- .arg(blockMode ? QLatin1String(",block") : QString())
- .arg(services.isEmpty() ? QString() : QString::fromLatin1(",services:"))
- .arg(services.isEmpty() ? QString() : services.join(","))
- << testFile(QLatin1String("test.qml")));
+ m_process = new QQmlDebugProcess(
+ QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
+ m_process->setMaximumBindErrors(1);
+ m_process->start(QStringList()
+ << QString::fromLatin1("-qmljsdebugger=connector:%1%2%3%4")
+ .arg(connector + (connector == QLatin1String("QQmlDebugServer")
+ ? QLatin1String(",port:5555,5565") : QString()))
+ .arg(blockMode ? QLatin1String(",block") : QString())
+ .arg(services.isEmpty() ? QString() : QString::fromLatin1(",services:"))
+ .arg(services.isEmpty() ? QString() : services.join(","))
+ << testFile(QLatin1String("test.qml")));
if (connector == QLatin1String("QQmlDebugServer")) {
- QVERIFY(process->waitForSessionStart());
- connection = new QQmlDebugConnection();
- QList<QQmlDebugClient *> clients = QQmlDebugTest::createOtherClients(connection);
- connection->connectToHost("127.0.0.1", process->debugPort());
- QVERIFY(connection->waitForConnected());
- foreach (QQmlDebugClient *client, clients)
+ QVERIFY(m_process->waitForSessionStart());
+ m_connection = new QQmlDebugConnection();
+ m_clients = QQmlDebugTest::createOtherClients(m_connection);
+ m_connection->connectToHost("127.0.0.1", m_process->debugPort());
+ QVERIFY(m_connection->waitForConnected());
+ foreach (QQmlDebugClient *client, m_clients)
QCOMPARE(client->state(), (services.isEmpty() || services.contains(client->name())) ?
QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
}
- QCOMPARE(process->state(), QLatin1String("running"));
- if (!blockMode)
- QTRY_VERIFY(process->output().contains(QLatin1String("qml: Component.onCompleted")));
+ QCOMPARE(m_process->state(), QProcess::Running);
+ if (!blockMode) {
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(
+ QLatin1String("Component.onCompleted")), 15000);
+ }
}
void tst_QQmlDebuggingEnabler::custom_data()
@@ -226,9 +145,9 @@ void tst_QQmlDebuggingEnabler::custom()
const int portFrom = 5555;
const int portTo = 5565;
- process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() +
- QLatin1String("/qqmldebuggingenablerserver"), this);
- process->setMaximumBindErrors(portTo - portFrom);
+ m_process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() +
+ QLatin1String("/qqmldebuggingenablerserver"), this);
+ m_process->setMaximumBindErrors(portTo - portFrom);
QStringList args;
if (blockMode)
@@ -240,22 +159,24 @@ void tst_QQmlDebuggingEnabler::custom()
if (!services.isEmpty())
args << QLatin1String("-services") << services;
- process->start(args);
+ m_process->start(args);
if (connector == QLatin1String("QQmlDebugServer")) {
- QVERIFY(process->waitForSessionStart());
- connection = new QQmlDebugConnection();
- QList<QQmlDebugClient *> clients = QQmlDebugTest::createOtherClients(connection);
- connection->connectToHost("127.0.0.1", process->debugPort());
- QVERIFY(connection->waitForConnected());
- foreach (QQmlDebugClient *client, clients)
+ QVERIFY(m_process->waitForSessionStart());
+ m_connection = new QQmlDebugConnection();
+ m_clients = QQmlDebugTest::createOtherClients(m_connection);
+ m_connection->connectToHost("127.0.0.1", m_process->debugPort());
+ QVERIFY(m_connection->waitForConnected());
+ for (QQmlDebugClient *client : qAsConst(m_clients))
QCOMPARE(client->state(), (services.isEmpty() || services.contains(client->name())) ?
QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
}
- QCOMPARE(process->state(), QLatin1String("running"));
- if (!blockMode)
- QTRY_VERIFY(process->output().contains(QLatin1String("QQmlEngine created")));
+ QCOMPARE(m_process->state(), QProcess::Running);
+ if (!blockMode) {
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(QLatin1String("QQmlEngine created")),
+ 15000);
+ }
}
QTEST_MAIN(tst_QQmlDebuggingEnabler)
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml
new file mode 100644
index 0000000000..72a8c9559c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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.11
+
+
+Item {
+ visible: true
+ Text {
+ anchors.centerIn: parent
+ text: "bla"
+ MouseArea {
+ anchors.fill: parent
+ }
+ }
+
+ Timer {
+ interval: 100;
+ running: true;
+ onTriggered: {
+ Qt.quit();
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
index 06aabc94f9..06aabc94f9 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
index 00a85e56ac..00a85e56ac 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
index 3a50ba2eb7..3a50ba2eb7 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
index 089cc03733..089cc03733 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml b/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml
new file mode 100644
index 0000000000..7ea048044f
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ property int a: 0
+ property int b: 0
+ onAChanged: console.log("inline")
+ onBChanged: {
+ console.log("extra braces");
+ }
+
+ Timer {
+ interval: 10
+ running: true
+ onTriggered: {
+ parent.a += 10;
+ parent.b -= 10;
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
index 06f11fa016..06f11fa016 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
index 088c1b19fd..088c1b19fd 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
index deba24cf91..deba24cf91 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml
index bc8c2b90ae..bc8c2b90ae 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
index fb0b6c401c..fb0b6c401c 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
index 92e61d103c..92e61d103c 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
index a36d0cae91..a36d0cae91 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
index 66e6b96e18..66e6b96e18 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
index bd6debcea1..acd5546a02 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
@@ -1,4 +1,24 @@
-TEMPLATE = subdirs
-SUBDIRS = qqmldebugjs qqmldebugjsserver
+CONFIG += testcase
+TARGET = tst_qqmldebugjs
+QT += testlib gui-private core-private
+macos:CONFIG -= app_bundle
-qqmldebugjs.depends = qqmldebugjsserver
+SOURCES += tst_qqmldebugjs.cpp
+
+INCLUDEPATH += ../shared
+include(../shared/debugutil.pri)
+
+TESTDATA = data/*
+
+OTHER_FILES += data/test.qml data/test.js \
+ data/timer.qml \
+ data/exception.qml \
+ data/oncompleted.qml \
+ data/loadjsfile.qml \
+ data/condition.qml \
+ data/changeBreakpoint.qml \
+ data/stepAction.qml \
+ data/breakpointRelocation.qml \
+ data/createComponent.qml \
+ data/encodeQmlScope.qml \
+ data/breakOnAnchor.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro
deleted file mode 100644
index cbaf3b5309..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro
+++ /dev/null
@@ -1,25 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qqmldebugjs
-QT += qml testlib gui-private core-private
-CONFIG -= debug_and_release_target
-osx:CONFIG -= app_bundle
-
-SOURCES += tst_qqmldebugjs.cpp
-
-INCLUDEPATH += ../../shared
-include(../../../../shared/util.pri)
-include(../../shared/debugutil.pri)
-include(../../shared/qqmlenginedebugclient.pri)
-
-TESTDATA = data/*
-
-OTHER_FILES += data/test.qml data/test.js \
- data/timer.qml \
- data/exception.qml \
- data/oncompleted.qml \
- data/loadjsfile.qml \
- data/condition.qml \
- data/changeBreakpoint.qml \
- data/stepAction.qml \
- data/breakpointRelocation.qml \
- data/createComponent.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
deleted file mode 100644
index d248cf9708..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
+++ /dev/null
@@ -1,1552 +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 "debugutil_p.h"
-#include "../../shared/qqmlenginedebugclient.h"
-#include "../../../../shared/util.h"
-
-#include <private/qqmldebugclient_p.h>
-#include <private/qqmldebugconnection_p.h>
-#include <private/qpacket_p.h>
-
-#include <QtTest/qtest.h>
-#include <QtCore/qprocess.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qlibraryinfo.h>
-#include <QtQml/qjsengine.h>
-
-const char *V8REQUEST = "v8request";
-const char *V8MESSAGE = "v8message";
-const char *SEQ = "seq";
-const char *TYPE = "type";
-const char *COMMAND = "command";
-const char *ARGUMENTS = "arguments";
-const char *STEPACTION = "stepaction";
-const char *STEPCOUNT = "stepcount";
-const char *EXPRESSION = "expression";
-const char *FRAME = "frame";
-const char *CONTEXT = "context";
-const char *GLOBAL = "global";
-const char *DISABLEBREAK = "disable_break";
-const char *HANDLES = "handles";
-const char *INCLUDESOURCE = "includeSource";
-const char *FROMFRAME = "fromFrame";
-const char *TOFRAME = "toFrame";
-const char *BOTTOM = "bottom";
-const char *NUMBER = "number";
-const char *FRAMENUMBER = "frameNumber";
-const char *TYPES = "types";
-const char *IDS = "ids";
-const char *FILTER = "filter";
-const char *FROMLINE = "fromLine";
-const char *TOLINE = "toLine";
-const char *TARGET = "target";
-const char *LINE = "line";
-const char *COLUMN = "column";
-const char *ENABLED = "enabled";
-const char *CONDITION = "condition";
-const char *IGNORECOUNT = "ignoreCount";
-const char *BREAKPOINT = "breakpoint";
-const char *FLAGS = "flags";
-
-const char *CONTINEDEBUGGING = "continue";
-const char *EVALUATE = "evaluate";
-const char *LOOKUP = "lookup";
-const char *BACKTRACE = "backtrace";
-const char *SCOPE = "scope";
-const char *SCOPES = "scopes";
-const char *SCRIPTS = "scripts";
-const char *SOURCE = "source";
-const char *SETBREAKPOINT = "setbreakpoint";
-const char *CLEARBREAKPOINT = "clearbreakpoint";
-const char *SETEXCEPTIONBREAK = "setexceptionbreak";
-const char *VERSION = "version";
-const char *DISCONNECT = "disconnect";
-const char *GARBAGECOLLECTOR = "gc";
-
-const char *CONNECT = "connect";
-const char *INTERRUPT = "interrupt";
-
-const char *REQUEST = "request";
-const char *IN = "in";
-const char *NEXT = "next";
-const char *OUT = "out";
-
-const char *SCRIPT = "script";
-const char *SCRIPTREGEXP = "scriptRegExp";
-const char *EVENT = "event";
-
-const char *ALL = "all";
-const char *UNCAUGHT = "uncaught";
-
-const char *BLOCKMODE = "-qmljsdebugger=port:3771,3800,block";
-const char *NORMALMODE = "-qmljsdebugger=port:3771,3800";
-const char *BLOCKRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,block,services:V8Debugger";
-const char *NORMALRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,services:V8Debugger";
-const char *TEST_QMLFILE = "test.qml";
-const char *TEST_JSFILE = "test.js";
-const char *TIMER_QMLFILE = "timer.qml";
-const char *LOADJSFILE_QMLFILE = "loadjsfile.qml";
-const char *EXCEPTION_QMLFILE = "exception.qml";
-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 *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml";
-const char *STEPACTION_QMLFILE = "stepAction.qml";
-const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml";
-
-#define VARIANTMAPINIT \
- QString obj("{}"); \
- QJSValue jsonVal = parser.call(QJSValueList() << obj); \
- jsonVal.setProperty(SEQ,QJSValue(seq++)); \
- jsonVal.setProperty(TYPE,REQUEST);
-
-
-#undef QVERIFY
-#define QVERIFY(statement) \
-do {\
- if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
- if (QTest::currentTestFailed()) \
- qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << process->output();\
- return;\
- }\
-} while (0)
-
-
-class QJSDebugClient;
-
-class tst_QQmlDebugJS : public QQmlDataTest
-{
- Q_OBJECT
-
- void init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), bool blockMode = true,
- bool restrictServices = false);
-
-private slots:
- void initTestCase();
- void cleanupTestCase();
-
- void cleanup();
-
- void connect_data();
- void connect();
- void interrupt_data() { targetData(); }
- void interrupt();
- void getVersion_data() { targetData(); }
- void getVersion();
- void getVersionWhenAttaching_data() { targetData(); }
- void getVersionWhenAttaching();
-
- void disconnect_data() { targetData(); }
- void disconnect();
-
- void setBreakpointInScriptOnCompleted_data() { targetData(); }
- void setBreakpointInScriptOnCompleted();
- void setBreakpointInScriptOnComponentCreated_data() { targetData(); }
- void setBreakpointInScriptOnComponentCreated();
- void setBreakpointInScriptOnTimerCallback_data() { targetData(); }
- void setBreakpointInScriptOnTimerCallback();
- void setBreakpointInScriptInDifferentFile_data() { targetData(); }
- void setBreakpointInScriptInDifferentFile();
- void setBreakpointInScriptOnComment_data() { targetData(); }
- void setBreakpointInScriptOnComment();
- void setBreakpointInScriptOnEmptyLine_data() { targetData(); }
- void setBreakpointInScriptOnEmptyLine();
- void setBreakpointInScriptOnOptimizedBinding_data() { targetData(); }
- void setBreakpointInScriptOnOptimizedBinding();
- void setBreakpointInScriptWithCondition_data() { targetData(); }
- void setBreakpointInScriptWithCondition();
- void setBreakpointInScriptThatQuits_data() { targetData(); }
- void setBreakpointInScriptThatQuits();
- void setBreakpointWhenAttaching();
-
- void clearBreakpoint_data() { targetData(); }
- void clearBreakpoint();
-
- void setExceptionBreak_data() { targetData(); }
- void setExceptionBreak();
-
- void stepNext_data() { targetData(); }
- void stepNext();
- void stepIn_data() { targetData(); }
- void stepIn();
- void stepOut_data() { targetData(); }
- void stepOut();
- void continueDebugging_data() { targetData(); }
- void continueDebugging();
-
- void backtrace_data() { targetData(); }
- void backtrace();
-
- void getFrameDetails_data() { targetData(); }
- void getFrameDetails();
-
- void getScopeDetails_data() { targetData(); }
- void getScopeDetails();
-
- void evaluateInGlobalScope();
- void evaluateInLocalScope_data() { targetData(); }
- void evaluateInLocalScope();
-
- void evaluateInContext();
-
- void getScripts_data() { targetData(); }
- void getScripts();
-
-private:
- void targetData();
-
- QQmlDebugProcess *process;
- QJSDebugClient *client;
- QQmlDebugConnection *connection;
- QTime t;
-};
-
-class QJSDebugClient : public QQmlDebugClient
-{
- Q_OBJECT
-public:
- enum StepAction
- {
- Continue,
- In,
- Out,
- Next
- };
-
- enum Exception
- {
- All,
- Uncaught
- };
-
- QJSDebugClient(QQmlDebugConnection *connection)
- : QQmlDebugClient(QLatin1String("V8Debugger"), connection),
- seq(0)
- {
- parser = jsEngine.evaluate(QLatin1String("JSON.parse"));
- stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
- }
-
- void connect(bool redundantRefs = false, bool namesAsObjects = false);
- void interrupt();
-
- void continueDebugging(StepAction stepAction);
- void evaluate(QString expr, int frame = -1, int context = -1);
- void lookup(QList<int> handles, bool includeSource = false);
- void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
- void frame(int number = -1);
- void scope(int number = -1, int frameNumber = -1);
- void scripts(int types = 4, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
- void setBreakpoint(QString target, int line = -1, int column = -1, bool enabled = true,
- QString condition = QString(), int ignoreCount = -1);
- void clearBreakpoint(int breakpoint);
- void setExceptionBreak(Exception type, bool enabled = false);
- void version();
- void disconnect();
-
-protected:
- //inherited from QQmlDebugClient
- void stateChanged(State state);
- void messageReceived(const QByteArray &data);
-
-signals:
- void enabled();
- void connected();
- void interruptRequested();
- void result();
- void failure();
- void stopped();
-
-private:
- void sendMessage(const QByteArray &);
- void flushSendBuffer();
- QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray());
-
-private:
- QJSEngine jsEngine;
- int seq;
-
- QList<QByteArray> sendBuffer;
-public:
- QJSValue parser;
- QJSValue stringify;
- QByteArray response;
-
-};
-
-void QJSDebugClient::connect(bool redundantRefs, bool namesAsObjects)
-{
- QJSValue jsonVal = parser.call(QJSValueList() << QLatin1String("{}"));
- jsonVal.setProperty("redundantRefs", QJSValue(redundantRefs));
- jsonVal.setProperty("namesAsObjects", QJSValue(namesAsObjects));
- sendMessage(packMessage(CONNECT,
- stringify.call(QJSValueList() << jsonVal).toString().toUtf8()));
-}
-
-void QJSDebugClient::interrupt()
-{
- sendMessage(packMessage(INTERRUPT));
-}
-
-void QJSDebugClient::continueDebugging(StepAction action)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "continue",
- // "arguments" : { "stepaction" : <"in", "next" or "out">,
- // "stepcount" : <number of steps (default 1)>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CONTINEDEBUGGING)));
-
- if (action != Continue) {
- QJSValue args = parser.call(QJSValueList() << obj);
- switch (action) {
- case In: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(IN)));
- break;
- case Out: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(OUT)));
- break;
- case Next: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(NEXT)));
- break;
- default:break;
- }
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
- }
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::evaluate(QString expr, int frame, int context)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "evaluate",
- // "arguments" : { "expression" : <expression to evaluate>,
- // "frame" : <number>,
- // "context" : <object ID>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(EVALUATE)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
- args.setProperty(QLatin1String(EXPRESSION),QJSValue(expr));
-
- if (frame != -1)
- args.setProperty(QLatin1String(FRAME),QJSValue(frame));
-
- if (context != -1)
- args.setProperty(QLatin1String(CONTEXT), QJSValue(context));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::lookup(QList<int> handles, bool includeSource)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "lookup",
- // "arguments" : { "handles" : <array of handles>,
- // "includeSource" : <boolean indicating whether the source will be included when script objects are returned>,
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(LOOKUP)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- QString arr("[]");
- QJSValue array = parser.call(QJSValueList() << arr);
- int index = 0;
- foreach (int handle, handles) {
- array.setProperty(index++,QJSValue(handle));
- }
- args.setProperty(QLatin1String(HANDLES),array);
-
- if (includeSource)
- args.setProperty(QLatin1String(INCLUDESOURCE),QJSValue(includeSource));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::backtrace(int fromFrame, int toFrame, bool bottom)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "backtrace",
- // "arguments" : { "fromFrame" : <number>
- // "toFrame" : <number>
- // "bottom" : <boolean, set to true if the bottom of the stack is requested>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(BACKTRACE)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- if (fromFrame != -1)
- args.setProperty(QLatin1String(FROMFRAME),QJSValue(fromFrame));
-
- if (toFrame != -1)
- args.setProperty(QLatin1String(TOFRAME),QJSValue(toFrame));
-
- if (bottom)
- args.setProperty(QLatin1String(BOTTOM),QJSValue(bottom));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::frame(int number)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "frame",
- // "arguments" : { "number" : <frame number>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(FRAME)));
-
- if (number != -1) {
- QJSValue args = parser.call(QJSValueList() << obj);
- args.setProperty(QLatin1String(NUMBER),QJSValue(number));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::scope(int number, int frameNumber)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "scope",
- // "arguments" : { "number" : <scope number>
- // "frameNumber" : <frame number, optional uses selected frame if missing>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCOPE)));
-
- if (number != -1) {
- QJSValue args = parser.call(QJSValueList() << obj);
- args.setProperty(QLatin1String(NUMBER),QJSValue(number));
-
- if (frameNumber != -1)
- args.setProperty(QLatin1String(FRAMENUMBER),QJSValue(frameNumber));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::scripts(int types, QList<int> ids, bool includeSource, QVariant /*filter*/)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "scripts",
- // "arguments" : { "types" : <types of scripts to retrieve
- // set bit 0 for native scripts
- // set bit 1 for extension scripts
- // set bit 2 for normal scripts
- // (default is 4 for normal scripts)>
- // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned>
- // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned>
- // "filter" : <string or number: filter string or script id.
- // If a number is specified, then only the script with the same number as its script id will be retrieved.
- // If a string is specified, then only scripts whose names contain the filter string will be retrieved.>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCRIPTS)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
- args.setProperty(QLatin1String(TYPES),QJSValue(types));
-
- if (ids.count()) {
- QString arr("[]");
- QJSValue array = parser.call(QJSValueList() << arr);
- int index = 0;
- foreach (int id, ids) {
- array.setProperty(index++,QJSValue(id));
- }
- args.setProperty(QLatin1String(IDS),array);
- }
-
- if (includeSource)
- args.setProperty(QLatin1String(INCLUDESOURCE),QJSValue(includeSource));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::setBreakpoint(QString target, int line, int column, bool enabled,
- QString condition, int ignoreCount)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "setbreakpoint",
- // "arguments" : { "type" : "scriptRegExp"
- // "target" : <function expression or script identification>
- // "line" : <line in script or function>
- // "column" : <character position within the line>
- // "enabled" : <initial enabled state. True or false, default is true>
- // "condition" : <string with break point condition>
- // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0>
- // }
- // }
-
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SETBREAKPOINT)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(SCRIPTREGEXP)));
- args.setProperty(QLatin1String(TARGET),QJSValue(target));
-
- if (line != -1)
- args.setProperty(QLatin1String(LINE),QJSValue(line));
-
- if (column != -1)
- args.setProperty(QLatin1String(COLUMN),QJSValue(column));
-
- args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
-
- if (!condition.isEmpty())
- args.setProperty(QLatin1String(CONDITION),QJSValue(condition));
-
- if (ignoreCount != -1)
- args.setProperty(QLatin1String(IGNORECOUNT),QJSValue(ignoreCount));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::clearBreakpoint(int breakpoint)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "clearbreakpoint",
- // "arguments" : { "breakpoint" : <number of the break point to clear>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CLEARBREAKPOINT)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(BREAKPOINT),QJSValue(breakpoint));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::setExceptionBreak(Exception type, bool enabled)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "setexceptionbreak",
- // "arguments" : { "type" : <string: "all", or "uncaught">,
- // "enabled" : <optional bool: enables the break type if true>
- // }
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SETEXCEPTIONBREAK)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- if (type == All)
- args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(ALL)));
- else if (type == Uncaught)
- args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(UNCAUGHT)));
-
- if (enabled)
- args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
-
- if (!args.isUndefined()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::version()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "version",
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(VERSION)));
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::disconnect()
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "disconnect",
- // }
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(DISCONNECT)));
-
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(DISCONNECT, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::stateChanged(State state)
-{
- if (state == Enabled) {
- flushSendBuffer();
- emit enabled();
- }
-}
-
-void QJSDebugClient::messageReceived(const QByteArray &data)
-{
- QPacket ds(connection()->currentDataStreamVersion(), data);
- QByteArray command;
- ds >> command;
-
- if (command == "V8DEBUG") {
- QByteArray type;
- ds >> type >> response;
-
- if (type == CONNECT) {
- emit connected();
-
- } else if (type == INTERRUPT) {
- emit interruptRequested();
-
- } else if (type == V8MESSAGE) {
- QString jsonString(response);
- QVariantMap value = parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
- QString type = value.value("type").toString();
-
- if (type == "response") {
-
- if (!value.value("success").toBool()) {
- emit failure();
- qDebug() << "Received success == false response from application";
- return;
- }
-
- QString debugCommand(value.value("command").toString());
- if (debugCommand == "backtrace" ||
- debugCommand == "lookup" ||
- debugCommand == "setbreakpoint" ||
- debugCommand == "evaluate" ||
- debugCommand == "version" ||
- debugCommand == "disconnect" ||
- debugCommand == "gc" ||
- debugCommand == "changebreakpoint" ||
- debugCommand == "clearbreakpoint" ||
- debugCommand == "frame" ||
- debugCommand == "scope" ||
- debugCommand == "scopes" ||
- debugCommand == "scripts" ||
- debugCommand == "source" ||
- debugCommand == "setexceptionbreak" /*||
- debugCommand == "profile"*/) {
- emit result();
-
- } else {
- // DO NOTHING
- }
-
- } else if (type == QLatin1String(EVENT)) {
- QString event(value.value(QLatin1String(EVENT)).toString());
-
- if (event == "break" ||
- event == "exception")
- emit stopped();
- }
-
- }
- }
-}
-
-void QJSDebugClient::sendMessage(const QByteArray &msg)
-{
- if (state() == Enabled) {
- QQmlDebugClient::sendMessage(msg);
- } else {
- sendBuffer.append(msg);
- }
-}
-
-void QJSDebugClient::flushSendBuffer()
-{
- foreach (const QByteArray &msg, sendBuffer)
- QQmlDebugClient::sendMessage(msg);
- sendBuffer.clear();
-}
-
-QByteArray QJSDebugClient::packMessage(const QByteArray &type, const QByteArray &message)
-{
- QPacket rs(connection()->currentDataStreamVersion());
- QByteArray cmd = "V8DEBUG";
- rs << cmd << type << message;
- return rs.data();
-}
-
-void tst_QQmlDebugJS::initTestCase()
-{
- QQmlDataTest::initTestCase();
- t.start();
- process = 0;
- client = 0;
- connection = 0;
-}
-
-void tst_QQmlDebugJS::cleanupTestCase()
-{
- if (process) {
- process->stop();
- delete process;
- }
-
- if (client)
- delete client;
-
- if (connection)
- delete connection;
-}
-
-void tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile, bool blockMode,
- bool restrictServices)
-{
- connection = new QQmlDebugConnection();
- if (qmlscene)
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) +
- "/qmlscene", this);
- else
- process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() +
- QLatin1String("/qqmldebugjsserver"), this);
- client = new QJSDebugClient(connection);
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(connection);
-
- const char *args = 0;
- if (blockMode)
- args = restrictServices ? BLOCKRESTRICTEDMODE : BLOCKMODE;
- else
- args = restrictServices ? NORMALRESTRICTEDMODE : NORMALMODE;
-
- process->start(QStringList() << QLatin1String(args) << testFile(qmlFile));
-
- QVERIFY(process->waitForSessionStart());
-
- const int port = process->debugPort();
- connection->connectToHost("127.0.0.1", port);
- QVERIFY(connection->waitForConnected());
-
-
- if (client->state() != QQmlDebugClient::Enabled)
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(enabled())));
-
- foreach (QQmlDebugClient *otherClient, others)
- QCOMPARE(otherClient->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
-}
-
-void tst_QQmlDebugJS::cleanup()
-{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << process->state();
- qDebug() << "Application Output:" << process->output();
- }
-
- if (process) {
- process->stop();
- delete process;
- }
-
- if (client)
- delete client;
-
- if (connection)
- delete connection;
-
- process = 0;
- client = 0;
- connection = 0;
-}
-
-void tst_QQmlDebugJS::connect_data()
-{
- QTest::addColumn<bool>("blockMode");
- QTest::addColumn<bool>("restrictMode");
- QTest::addColumn<bool>("qmlscene");
- QTest::newRow("normal / unrestricted / custom") << false << false << false;
- QTest::newRow("block / unrestricted / custom") << true << false << false;
- QTest::newRow("normal / restricted / custom") << false << true << false;
- QTest::newRow("block / restricted / custom") << true << true << false;
- QTest::newRow("normal / unrestricted / qmlscene") << false << false << true;
- QTest::newRow("block / unrestricted / qmlscene") << true << false << true;
- QTest::newRow("normal / restricted / qmlscene") << false << true << true;
- QTest::newRow("block / restricted / qmlscene") << true << true << true;
-}
-
-void tst_QQmlDebugJS::connect()
-{
- QFETCH(bool, blockMode);
- QFETCH(bool, restrictMode);
- QFETCH(bool, qmlscene);
- init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode);
- client->connect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
-}
-
-void tst_QQmlDebugJS::interrupt()
-{
- //void connect()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
-
- client->interrupt();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
-}
-
-void tst_QQmlDebugJS::getVersion()
-{
- //void version()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
-
- client->version();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::getVersionWhenAttaching()
-{
- //void version()
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
- client->connect(redundantRefs, namesAsObjects);
-
- client->version();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::disconnect()
-{
- //void disconnect()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
-
- client->disconnect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, CREATECOMPONENT_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int sourceLine = 35;
- init(qmlscene, TIMER_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //We can set the breakpoint after connect() here because the timer is repeating and if we miss
- //its first iteration we can still catch the second one.
- client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TIMER_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 31;
- init(qmlscene, LOADJSFILE_QMLFILE);
-
- client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TEST_JSFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnComment()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- int actualLine = 36;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), actualLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 35;
- int actualLine = 36;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), actualLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 39;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int out = 10;
- int sourceLine = 37;
- init(qmlscene, CONDITION_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //The breakpoint is in a timer loop so we can set it after connect().
- client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Get the frame index
- QString jsonString = client->response;
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- {
- QVariantMap body = value.value("body").toMap();
- int frameIndex = body.value("index").toInt();
-
- //Verify the value of 'result'
- client->evaluate(QLatin1String("a"),frameIndex);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
- }
-
- jsonString = client->response;
- QJSValue val = client->parser.call(QJSValueList() << QJSValue(jsonString));
- QVERIFY(val.isObject());
- QJSValue body = val.property(QStringLiteral("body"));
- QVERIFY(body.isObject());
- val = body.property("value");
- QVERIFY(val.isNumber());
-
- const int a = val.toInt();
- QVERIFY(a > out);
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene, QUIT_QMLFILE);
-
- int sourceLine = 36;
-
- client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(QUIT_QMLFILE));
-
- client->continueDebugging(QJSDebugClient::Continue);
- QVERIFY(process->waitForFinished());
- QCOMPARE(process->exitStatus(), QProcess::NormalExit);
-}
-
-void tst_QQmlDebugJS::setBreakpointWhenAttaching()
-{
- int sourceLine = 35;
- init(true, QLatin1String(TIMER_QMLFILE), false);
-
- client->connect();
-
- QSKIP("\nThe breakpoint may not hit because the engine may run in JIT mode or not have debug\n"
- "instructions, as we've connected in non-blocking mode above. That means we may have\n"
- "connected after the engine was already running, with all the QML already compiled.");
-
- //The breakpoint is in a timer loop so we can set it after connect().
- client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-}
-
-void tst_QQmlDebugJS::clearBreakpoint()
-{
- //void clearBreakpoint(int breakpoint);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine1 = 37;
- int sourceLine2 = 38;
- init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //The breakpoints are in a timer loop so we can set them after connect().
- //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
- //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
- client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
- client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Will hit 1st brakpoint, change this breakpoint enable = false
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
- QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
-
- int breakpoint = breakpointsHit.at(0).toInt();
- client->clearBreakpoint(breakpoint);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Hit 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- //Continue with debugging
- client->continueDebugging(QJSDebugClient::Continue);
- //Should stop at 2nd breakpoint
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- jsonString = client->response;
- value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
-}
-
-void tst_QQmlDebugJS::setExceptionBreak()
-{
- //void setExceptionBreak(QString type, bool enabled = false);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- init(qmlscene, EXCEPTION_QMLFILE);
- client->setExceptionBreak(QJSDebugClient::All,true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-}
-
-void tst_QQmlDebugJS::stepNext()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 37;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->continueDebugging(QJSDebugClient::Next);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 1);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::stepIn()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 41;
- int actualLine = 37;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->continueDebugging(QJSDebugClient::In);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), actualLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::stepOut()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 37;
- int actualLine = 41;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->continueDebugging(QJSDebugClient::Out);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), actualLine);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::continueDebugging()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine1 = 41;
- int sourceLine2 = 38;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->continueDebugging(QJSDebugClient::Continue);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
- QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::backtrace()
-{
- //void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->backtrace();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::getFrameDetails()
-{
- //void frame(int number = -1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->frame();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::getScopeDetails()
-{
- //void scope(int number = -1, int frameNumber = -1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->scope();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::evaluateInGlobalScope()
-{
- //void evaluate(QString expr, int frame = -1);
- init(true);
-
- client->connect();
-
- do {
- // The engine might not be initialized, yet. We just try until it shows up.
- client->evaluate(QLatin1String("console.log('Hello World')"));
- } while (!QQmlDebugTest::waitForSignal(client, SIGNAL(result()), 500));
-
- //Verify the return value of 'console.log()', which is "undefined"
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
- QVariantMap body = value.value("body").toMap();
- QCOMPARE(body.value("type").toString(),QLatin1String("undefined"));
-}
-
-void tst_QQmlDebugJS::evaluateInLocalScope()
-{
- //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->frame();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- //Get the frame index
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
-
- int frameIndex = body.value("index").toInt();
-
- client->evaluate(QLatin1String("root.a"), frameIndex);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- //Verify the value of 'timer.interval'
- jsonString = client->response;
- value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- body = value.value("body").toMap();
-
- QCOMPARE(body.value("value").toInt(),10);
-}
-
-void tst_QQmlDebugJS::evaluateInContext()
-{
- connection = new QQmlDebugConnection();
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath)
- + "/qmlscene", this);
- client = new QJSDebugClient(connection);
- QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(connection));
- process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE));
-
- QVERIFY(process->waitForSessionStart());
-
- connection->connectToHost("127.0.0.1", process->debugPort());
- QVERIFY(connection->waitForConnected());
-
- QTRY_COMPARE(client->state(), QQmlEngineDebugClient::Enabled);
- QTRY_COMPARE(engineClient->state(), QQmlEngineDebugClient::Enabled);
- client->connect();
-
- // "a" not accessible without extra context
- client->evaluate(QLatin1String("a + 10"), -1, -1);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(failure())));
-
- bool success = false;
- engineClient->queryAvailableEngines(&success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
-
- QVERIFY(engineClient->engines().count());
- engineClient->queryRootContexts(engineClient->engines()[0].debugId, &success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
-
- auto contexts = engineClient->rootContext().contexts;
- QCOMPARE(contexts.count(), 1);
- auto objects = contexts[0].objects;
- QCOMPARE(objects.count(), 1);
- engineClient->queryObjectRecursive(objects[0], &success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
- auto object = engineClient->object();
-
- // "a" accessible in context of surrounding object
- client->evaluate(QLatin1String("a + 10"), -1, object.debugId);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- QString jsonString = client->response;
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
- QTRY_COMPARE(body.value("value").toInt(), 20);
-}
-
-void tst_QQmlDebugJS::getScripts()
-{
- //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
-
- client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->scripts();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList()
- << QJSValue(jsonString)).toVariant().toMap();
-
- QList<QVariant> scripts = value.value("body").toList();
-
- QCOMPARE(scripts.count(), 1);
- QVERIFY(scripts.first().toMap()[QStringLiteral("name")].toString().endsWith(QStringLiteral("data/test.qml")));
-}
-
-void tst_QQmlDebugJS::targetData()
-{
- QTest::addColumn<bool>("qmlscene");
- QTest::addColumn<bool>("redundantRefs");
- QTest::addColumn<bool>("namesAsObjects");
- QTest::newRow("custom / redundant / objects") << false << true << true;
- QTest::newRow("qmlscene / redundant / objects") << true << true << true;
- QTest::newRow("custom / redundant / strings") << false << true << false;
- QTest::newRow("qmlscene / redundant / strings") << true << true << false;
- QTest::newRow("custom / sparse / objects") << false << false << true;
- QTest::newRow("qmlscene / sparse / objects") << true << false << true;
- QTest::newRow("custom / sparse / strings") << false << false << false;
- QTest::newRow("qmlscene / sparse / strings") << true << false << false;
-}
-
-QTEST_MAIN(tst_QQmlDebugJS)
-
-#include "tst_qqmldebugjs.moc"
-
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro
deleted file mode 100644
index 837eaed9f1..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-QT += qml testlib
-osx:CONFIG -= app_bundle
-CONFIG -= debug_and_release_target
-INCLUDEPATH += ../../shared
-SOURCES += qqmldebugjsserver.cpp
-DEFINES += QT_QML_DEBUG_NO_WARNING
-
-DESTDIR = ../qqmldebugjs
-
-target.path = $$[QT_INSTALL_TESTS]/tst_qqmldebugjs
-INSTALLS += target
-
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
new file mode 100644
index 0000000000..1ac28c473b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -0,0 +1,1008 @@
+/****************************************************************************
+**
+** 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 "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
+#include "../../../shared/util.h"
+
+#include <private/qqmlenginedebugclient_p.h>
+#include <private/qv4debugclient_p.h>
+#include <private/qqmldebugconnection_p.h>
+#include <private/qpacket_p.h>
+
+#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>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonarray.h>
+
+const char *BLOCKMODE = "-qmljsdebugger=port:3771,3800,block";
+const char *NORMALMODE = "-qmljsdebugger=port:3771,3800";
+const char *BLOCKRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,block,services:V8Debugger";
+const char *NORMALRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,services:V8Debugger";
+const char *TEST_QMLFILE = "test.qml";
+const char *TEST_JSFILE = "test.js";
+const char *TIMER_QMLFILE = "timer.qml";
+const char *LOADJSFILE_QMLFILE = "loadjsfile.qml";
+const char *EXCEPTION_QMLFILE = "exception.qml";
+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 *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml";
+const char *STEPACTION_QMLFILE = "stepAction.qml";
+const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml";
+const char *ENCODEQMLSCOPE_QMLFILE = "encodeQmlScope.qml";
+const char *BREAKONANCHOR_QMLFILE = "breakOnAnchor.qml";
+
+#undef QVERIFY
+#define QVERIFY(statement) \
+do {\
+ if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
+ if (QTest::currentTestFailed()) \
+ qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << m_process->output();\
+ return;\
+ }\
+} while (0)
+
+class tst_QQmlDebugJS : public QQmlDebugTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() override;
+
+ void connect_data();
+ void connect();
+ void interrupt_data() { targetData(); }
+ void interrupt();
+ void getVersion_data() { targetData(); }
+ void getVersion();
+ void getVersionWhenAttaching_data() { targetData(); }
+ void getVersionWhenAttaching();
+
+ void disconnect_data() { targetData(); }
+ void disconnect();
+
+ void setBreakpointInScriptOnCompleted_data() { targetData(); }
+ void setBreakpointInScriptOnCompleted();
+ void setBreakpointInScriptOnComponentCreated_data() { targetData(); }
+ void setBreakpointInScriptOnComponentCreated();
+ void setBreakpointInScriptOnTimerCallback_data() { targetData(); }
+ void setBreakpointInScriptOnTimerCallback();
+ void setBreakpointInScriptInDifferentFile_data() { targetData(); }
+ void setBreakpointInScriptInDifferentFile();
+ void setBreakpointInScriptOnComment_data() { targetData(); }
+ void setBreakpointInScriptOnComment();
+ void setBreakpointInScriptOnEmptyLine_data() { targetData(); }
+ void setBreakpointInScriptOnEmptyLine();
+ void setBreakpointInScriptOnOptimizedBinding_data() { targetData(); }
+ void setBreakpointInScriptOnOptimizedBinding();
+ void setBreakpointInScriptWithCondition_data() { targetData(); }
+ void setBreakpointInScriptWithCondition();
+ void setBreakpointInScriptThatQuits_data() { targetData(); }
+ void setBreakpointInScriptThatQuits();
+ void setBreakpointWhenAttaching();
+
+ void clearBreakpoint_data() { targetData(); }
+ void clearBreakpoint();
+
+ void changeBreakpoint_data() { targetData(); }
+ void changeBreakpoint();
+
+ void setExceptionBreak_data() { targetData(); }
+ void setExceptionBreak();
+
+ void stepNext_data() { targetData(); }
+ void stepNext();
+ void stepIn_data() { targetData(); }
+ void stepIn();
+ void stepOut_data() { targetData(); }
+ void stepOut();
+ void continueDebugging_data() { targetData(); }
+ void continueDebugging();
+
+ void backtrace_data() { targetData(); }
+ void backtrace();
+
+ void getFrameDetails_data() { targetData(); }
+ void getFrameDetails();
+
+ void getScopeDetails_data() { targetData(); }
+ void getScopeDetails();
+
+ void evaluateInGlobalScope();
+ void evaluateInLocalScope_data() { targetData(); }
+ void evaluateInLocalScope();
+
+ void evaluateInContext();
+
+ void getScripts_data() { targetData(); }
+ void getScripts();
+
+ void encodeQmlScope();
+ void breakOnAnchor();
+
+private:
+ ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE),
+ bool blockMode = true, bool restrictServices = false);
+ QList<QQmlDebugClient *> createClients() override;
+ QPointer<QV4DebugClient> m_client;
+
+ void targetData();
+ bool waitForClientSignal(const char *signal, int timeout = 30000);
+ void checkVersionParameters();
+
+ QTime t;
+};
+
+
+
+void tst_QQmlDebugJS::initTestCase()
+{
+ QQmlDebugTest::initTestCase();
+ t.start();
+}
+
+QQmlDebugTest::ConnectResult tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile,
+ bool blockMode, bool restrictServices)
+{
+ const QString executable = qmlscene
+ ? QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"
+ : debugJsServerPath("qqmldebugjs");
+ return QQmlDebugTest::connect(
+ executable, restrictServices ? QStringLiteral("V8Debugger") : QString(),
+ testFile(qmlFile), blockMode);
+}
+
+void tst_QQmlDebugJS::connect_data()
+{
+ QTest::addColumn<bool>("blockMode");
+ QTest::addColumn<bool>("restrictMode");
+ QTest::addColumn<bool>("qmlscene");
+ QTest::newRow("normal / unrestricted / custom") << false << false << false;
+ QTest::newRow("block / unrestricted / custom") << true << false << false;
+ QTest::newRow("normal / restricted / custom") << false << true << false;
+ QTest::newRow("block / restricted / custom") << true << true << false;
+ QTest::newRow("normal / unrestricted / qmlscene") << false << false << true;
+ QTest::newRow("block / unrestricted / qmlscene") << true << false << true;
+ QTest::newRow("normal / restricted / qmlscene") << false << true << true;
+ QTest::newRow("block / restricted / qmlscene") << true << true << true;
+}
+
+void tst_QQmlDebugJS::connect()
+{
+ QFETCH(bool, blockMode);
+ QFETCH(bool, restrictMode);
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode), ConnectSuccess);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(connected())));
+}
+
+void tst_QQmlDebugJS::interrupt()
+{
+ //void connect()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+
+ m_client->interrupt();
+ QVERIFY(waitForClientSignal(SIGNAL(interrupted())));
+}
+
+void tst_QQmlDebugJS::getVersion()
+{
+ //void version()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(connected())));
+
+ m_client->version();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ checkVersionParameters();
+}
+
+void tst_QQmlDebugJS::getVersionWhenAttaching()
+{
+ //void version()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess);
+ m_client->connect();
+
+ m_client->version();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ checkVersionParameters();
+}
+
+void tst_QQmlDebugJS::disconnect()
+{
+ //void disconnect()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+
+ m_client->disconnect();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), 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(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, CREATECOMPONENT_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), 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(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
+{
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 35;
+ QCOMPARE(init(qmlscene, TIMER_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //We can set the breakpoint after connect() here because the timer is repeating and if we miss
+ //its first iteration we can still catch the second one.
+ m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
+ 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(TIMER_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 31;
+ QCOMPARE(init(qmlscene, LOADJSFILE_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(TEST_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(TEST_JSFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnComment()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped()), 1));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 35;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped()), 1));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 39;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), 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(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
+{
+ QFETCH(bool, qmlscene);
+
+ int out = 10;
+ int sourceLine = 37;
+ QCOMPARE(init(qmlscene, CONDITION_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //The breakpoint is in a timer loop so we can set it after connect().
+ m_client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ //Get the frame index
+ {
+ const QJsonObject body = m_client->response().body.toObject();
+ int frameIndex = body.value("index").toInt();
+
+ //Verify the value of 'result'
+ m_client->evaluate(QLatin1String("a"),frameIndex);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ }
+
+ const QJsonObject body = m_client->response().body.toObject();
+ QVERIFY(!body.isEmpty());
+ QJsonValue val = body.value("value");
+ QVERIFY(val.isDouble());
+
+ const int a = val.toInt();
+ QVERIFY(a > out);
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
+{
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QUIT_QMLFILE), ConnectSuccess);
+
+ int sourceLine = 36;
+
+ m_client->setBreakpoint(QLatin1String(QUIT_QMLFILE), 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_QMLFILE));
+
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ QVERIFY(m_process->waitForFinished());
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+}
+
+void tst_QQmlDebugJS::setBreakpointWhenAttaching()
+{
+ int sourceLine = 35;
+ QCOMPARE(init(true, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess);
+
+ m_client->connect();
+
+ QSKIP("\nThe breakpoint may not hit because the engine may run in JIT mode or not have debug\n"
+ "instructions, as we've connected in non-blocking mode above. That means we may have\n"
+ "connected after the engine was already running, with all the QML already compiled.");
+
+ //The breakpoint is in a timer loop so we can set it after connect().
+ m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine);
+
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::clearBreakpoint()
+{
+ //void clearBreakpoint(int breakpoint);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine1 = 37;
+ int sourceLine2 = 38;
+ QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //The breakpoints are in a timer loop so we can set them after connect().
+ //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
+ //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
+
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ {
+ //Will hit 1st brakpoint, change this breakpoint enable = false
+ const QJsonObject body = m_client->response().body.toObject();
+ const QJsonArray breakpointsHit = body.value("breakpoints").toArray();
+
+ int breakpoint = breakpointsHit.at(0).toInt();
+ m_client->clearBreakpoint(breakpoint);
+
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ //Continue with debugging
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ //Hit 2nd breakpoint
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ //Continue with debugging
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ }
+
+ //Should stop at 2nd breakpoint
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ {
+ const QJsonObject body = m_client->response().body.toObject();
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+ }
+}
+
+void tst_QQmlDebugJS::changeBreakpoint()
+{
+ //void clearBreakpoint(int breakpoint);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine2 = 37;
+ int sourceLine1 = 38;
+ QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess);
+
+ bool isStopped = false;
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() { isStopped = true; });
+
+ auto continueDebugging = [&]() {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ isStopped = false;
+ };
+
+ m_client->connect();
+
+ auto extractBody = [&]() {
+ return m_client->response().body.toObject();
+ };
+
+ auto extractBreakPointId = [&](const QJsonObject &body) {
+ const QJsonArray breakpointsHit = body.value("breakpoints").toArray();
+ if (breakpointsHit.size() != 1)
+ return -1;
+ return breakpointsHit[0].toInt();
+ };
+
+ auto setBreakPoint = [&](int sourceLine, bool enabled) {
+ int id = -1;
+ auto connection = QObject::connect(m_client.data(), &QV4DebugClient::result, [&]() {
+ id = extractBody().value("breakpoint").toInt();
+ });
+
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine, -1, enabled);
+ bool success = QTest::qWaitFor([&]() { return id >= 0; });
+ Q_UNUSED(success);
+
+ QObject::disconnect(connection);
+ return id;
+ };
+
+ //The breakpoints are in a timer loop so we can set them after connect().
+ //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
+ //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
+ const int breakpoint1 = setBreakPoint(sourceLine1, false);
+ QVERIFY(breakpoint1 >= 0);
+
+ const int breakpoint2 = setBreakPoint(sourceLine2, true);
+ QVERIFY(breakpoint2 >= 0);
+
+ auto verifyBreakpoint = [&](int sourceLine, int breakpointId) {
+ QTRY_VERIFY_WITH_TIMEOUT(isStopped, 30000);
+ const QJsonObject body = extractBody();
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(extractBreakPointId(body), breakpointId);
+ };
+
+ verifyBreakpoint(sourceLine2, breakpoint2);
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine2, breakpoint2);
+
+ m_client->changeBreakpoint(breakpoint2, false);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ m_client->changeBreakpoint(breakpoint1, true);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine1, breakpoint1);
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine1, breakpoint1);
+
+ m_client->changeBreakpoint(breakpoint2, true);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ m_client->changeBreakpoint(breakpoint1, false);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ for (int i = 0; i < 3; ++i) {
+ continueDebugging();
+ verifyBreakpoint(sourceLine2, breakpoint2);
+ }
+}
+
+void tst_QQmlDebugJS::setExceptionBreak()
+{
+ //void setExceptionBreak(QString type, bool enabled = false);
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, EXCEPTION_QMLFILE), ConnectSuccess);
+ m_client->setExceptionBreak(QV4DebugClient::All,true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::stepNext()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 37;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->continueDebugging(QV4DebugClient::Next);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 1);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(STEPACTION_QMLFILE));
+}
+
+static QJsonObject responseBody(QV4DebugClient *client)
+{
+ return client->response().body.toObject();
+}
+
+void tst_QQmlDebugJS::stepIn()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 41;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+ QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine);
+
+ m_client->continueDebugging(QV4DebugClient::In);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepOut()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 37;
+ int actualLine = 41;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+ QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine);
+
+ m_client->continueDebugging(QV4DebugClient::Out);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::continueDebugging()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine1 = 41;
+ int sourceLine2 = 38;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::backtrace()
+{
+ //void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->backtrace();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getFrameDetails()
+{
+ //void frame(int number = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->frame();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getScopeDetails()
+{
+ //void scope(int number = -1, int frameNumber = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->scope();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::evaluateInGlobalScope()
+{
+ //void evaluate(QString expr, int frame = -1);
+ QCOMPARE(init(true), ConnectSuccess);
+
+ m_client->connect();
+
+ for (int i = 0; i < 10; ++i) {
+ // The engine might not be initialized, yet. We just try until it shows up.
+ m_client->evaluate(QLatin1String("console.log('Hello World')"));
+ if (waitForClientSignal(SIGNAL(result()), 500))
+ break;
+ }
+
+ //Verify the return value of 'console.log()', which is "undefined"
+ QCOMPARE(responseBody(m_client).value("type").toString(), QLatin1String("undefined"));
+}
+
+void tst_QQmlDebugJS::evaluateInLocalScope()
+{
+ //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->frame();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ {
+ //Get the frame index
+ const QJsonObject body = responseBody(m_client);
+ int frameIndex = body.value("index").toInt();
+ m_client->evaluate(QLatin1String("root.a"), frameIndex);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ }
+
+ {
+ //Verify the value of 'timer.interval'
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("value").toInt(),10);
+ }
+}
+
+void tst_QQmlDebugJS::evaluateInContext()
+{
+ m_connection = new QQmlDebugConnection();
+ m_process = new QQmlDebugProcess(
+ QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
+ m_client = new QV4DebugClient(m_connection);
+ QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(m_connection));
+ m_process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE));
+
+ QVERIFY(m_process->waitForSessionStart());
+
+ m_connection->connectToHost("127.0.0.1", m_process->debugPort());
+ QVERIFY(m_connection->waitForConnected());
+
+ QTRY_COMPARE(m_client->state(), QQmlEngineDebugClient::Enabled);
+ QTRY_COMPARE(engineClient->state(), QQmlEngineDebugClient::Enabled);
+ m_client->connect();
+
+ // "a" not accessible without extra context
+ m_client->evaluate(QLatin1String("a + 10"), -1, -1);
+ QVERIFY(waitForClientSignal(SIGNAL(failure())));
+
+ bool success = false;
+ engineClient->queryAvailableEngines(&success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+
+ QVERIFY(engineClient->engines().count());
+ engineClient->queryRootContexts(engineClient->engines()[0], &success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+
+ auto contexts = engineClient->rootContext().contexts;
+ QCOMPARE(contexts.count(), 1);
+ auto objects = contexts[0].objects;
+ QCOMPARE(objects.count(), 1);
+ engineClient->queryObjectRecursive(objects[0], &success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+ auto object = engineClient->object();
+
+ // "a" accessible in context of surrounding object
+ m_client->evaluate(QLatin1String("a + 10"), -1, object.debugId);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 20);
+}
+
+void tst_QQmlDebugJS::getScripts()
+{
+ //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+
+ m_client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->scripts();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ const QJsonArray scripts = m_client->response().body.toArray();
+
+ QCOMPARE(scripts.count(), 1);
+ QVERIFY(scripts.first().toObject()[QStringLiteral("name")].toString()
+ .endsWith(QStringLiteral("data/test.qml")));
+}
+
+void tst_QQmlDebugJS::encodeQmlScope()
+{
+ QString file(ENCODEQMLSCOPE_QMLFILE);
+ QCOMPARE(init(true, file), ConnectSuccess);
+
+ int numFrames = 0;
+ int numExpectedScopes = 0;
+ int numReceivedScopes = 0;
+ bool isStopped = false;
+ bool scopesFailed = false;
+
+ QObject::connect(m_client.data(), &QV4DebugClient::failure, this, [&]() {
+ qWarning() << "received failure" << m_client->response().body;
+ scopesFailed = true;
+ m_process->stop();
+ numFrames = 2;
+ isStopped = false;
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() {
+ m_client->frame();
+ isStopped = true;
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::result, this, [&]() {
+ const QV4DebugClient::Response value = m_client->response();
+
+ if (value.command == QString("scope")) {
+ // If the scope commands fail we get a failure() signal above.
+ if (++numReceivedScopes == numExpectedScopes) {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ isStopped = false;
+ }
+ } else if (value.command == QString("frame")) {
+
+ // We want at least a global scope and some kind of local scope here.
+ const QJsonArray scopes = value.body.toObject().value("scopes").toArray();
+ if (scopes.count() < 2)
+ scopesFailed = true;
+
+ for (const QJsonValue &scope : scopes) {
+ ++numExpectedScopes;
+ m_client->scope(scope.toObject().value("index").toInt());
+ }
+
+ ++numFrames;
+ }
+ });
+
+ m_client->setBreakpoint(file, 6);
+ m_client->setBreakpoint(file, 8);
+ m_client->connect();
+
+ QTRY_COMPARE(numFrames, 2);
+ QVERIFY(numExpectedScopes > 3);
+ QVERIFY(!scopesFailed);
+ QTRY_VERIFY(!isStopped);
+ QCOMPARE(numReceivedScopes, numExpectedScopes);
+}
+
+void tst_QQmlDebugJS::breakOnAnchor()
+{
+ QString file(BREAKONANCHOR_QMLFILE);
+ QCOMPARE(init(true, file), ConnectSuccess);
+
+ int breaks = 0;
+ bool stopped = false;
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() {
+ stopped = true;
+ ++breaks;
+ m_client->evaluate("this", 0, -1);
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::result, this, [&]() {
+ if (stopped) {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ stopped = false;
+ }
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::failure, this, [&]() {
+ qWarning() << "received failure" << m_client->response().body;
+ });
+
+ m_client->setBreakpoint(file, 34);
+ m_client->setBreakpoint(file, 37);
+
+ QTRY_COMPARE(m_process->state(), QProcess::Running);
+
+ m_client->connect();
+
+ QTRY_COMPARE(m_process->state(), QProcess::NotRunning);
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+
+ QCOMPARE(breaks, 2);
+}
+
+QList<QQmlDebugClient *> tst_QQmlDebugJS::createClients()
+{
+ m_client = new QV4DebugClient(m_connection);
+ return QList<QQmlDebugClient *>({m_client});
+}
+
+void tst_QQmlDebugJS::targetData()
+{
+ QTest::addColumn<bool>("qmlscene");
+ QTest::newRow("custom") << false;
+ QTest::newRow("qmlscene") << true;
+}
+
+bool tst_QQmlDebugJS::waitForClientSignal(const char *signal, int timeout)
+{
+ return QQmlDebugTest::waitForSignal(m_client.data(), signal, timeout);
+}
+
+void tst_QQmlDebugJS::checkVersionParameters()
+{
+ const QV4DebugClient::Response value = m_client->response();
+ QCOMPARE(value.command, QString("version"));
+ const QJsonObject body = value.body.toObject();
+ QCOMPARE(body.value("UnpausedEvaluate").toBool(), true);
+ QCOMPARE(body.value("ContextEvaluate").toBool(), true);
+ QCOMPARE(body.value("ChangeBreakpoint").toBool(), true);
+}
+
+QTEST_MAIN(tst_QQmlDebugJS)
+
+#include "tst_qqmldebugjs.moc"
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp b/tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.cpp
index 6a4ec5cc75..6a4ec5cc75 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.cpp
diff --git a/tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.pro b/tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.pro
new file mode 100644
index 0000000000..a31da57054
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjsserver/qqmldebugjsserver.pro
@@ -0,0 +1,9 @@
+QT += qml testlib
+macos:CONFIG -= app_bundle
+INCLUDEPATH += ../shared
+SOURCES += qqmldebugjsserver.cpp
+DEFINES += QT_QML_DEBUG_NO_WARNING
+
+target.path = $$[QT_INSTALL_TESTS]/qqmldebugjsserver
+INSTALLS += target
+
diff --git a/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro
index 860d39cca4..1dc9de8f34 100644
--- a/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro
+++ b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro
@@ -7,7 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h
SOURCES += tst_qqmldebuglocal.cpp \
../shared/qqmldebugtestservice.cpp
-INCLUDEPATH += ../shared
include(../shared/debugutil.pri)
QT += qml-private testlib gui-private core-private
diff --git a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
index 8d21a8a45a..4e47c92c2a 100644
--- a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
+++ b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
@@ -32,6 +32,8 @@
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugconnection_p.h>
+#include <QtQml/qqmlengine.h>
+
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
#include <QtNetwork/qhostaddress.h>
@@ -61,10 +63,8 @@ private slots:
void tst_QQmlDebugLocal::initTestCase()
{
- fileName = QString::fromLatin1("tst_QQmlDebugLocal%1").arg(std::time(0));
+ fileName = QString::fromLatin1("tst_QQmlDebugLocal%1").arg(std::time(nullptr));
QQmlDebugConnector::setPluginKey("QQmlDebugServer");
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugLocal::handshake()");
const QString waitingMsg = QString("QML Debugger: Connecting to socket %1...").arg(fileName);
@@ -116,7 +116,7 @@ void tst_QQmlDebugLocal::state()
QQmlDebugClient client2("tst_QQmlDebugLocal::state()", m_conn);
QCOMPARE(client2.state(), QQmlDebugClient::NotConnected);
- QQmlDebugClient client3("tst_QQmlDebugLocal::state3()", 0);
+ QQmlDebugClient client3("tst_QQmlDebugLocal::state3()", nullptr);
QCOMPARE(client3.state(), QQmlDebugClient::NotConnected);
}
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro
new file mode 100644
index 0000000000..331d87b9f1
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = qqmldebugprocess qqmldebugprocessprocess
+
+qqmldebugprocess.depends = qqmldebugprocessprocess
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro
new file mode 100644
index 0000000000..9bea2d222c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+TARGET = tst_qqmldebugprocess
+QT = core testlib
+CONFIG -= debug_and_release_target
+macos:CONFIG -= app_bundle
+
+SOURCES += \
+ ../../shared/qqmldebugprocess.cpp \
+ tst_qqmldebugprocess.cpp
+
+HEADERS += \
+ ../../shared/qqmldebugprocess_p.h
+
+INCLUDEPATH += ../../shared
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp
new file mode 100644
index 0000000000..35bd912d9b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <qqmldebugprocess_p.h>
+#include <QtTest>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qscopedpointer.h>
+
+class tst_QQmlDebugProcess : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void sessionStart_data();
+ void sessionStart();
+};
+
+void tst_QQmlDebugProcess::sessionStart_data()
+{
+ QTest::addColumn<int>("delay");
+ QTest::addColumn<QString>("arg");
+ QTest::addColumn<bool>("sessionExpected");
+ QTest::addColumn<bool>("outputExpected");
+
+ QTest::addRow("synchronous / waiting") << -1
+ << "QML Debugger: Waiting for connection on port 2423..."
+ << true << false;
+ QTest::addRow("synchronous / failed") << -1 << "QML Debugger: Unable to listen to port 242."
+ << false << false;
+ QTest::addRow("synchronous / unknown") << -1 << "QML Debugger: You don't know this string."
+ << false << true;
+ QTest::addRow("synchronous / appout") << -1 << "Output from app itself."
+ << false << true;
+
+ QTest::addRow("no delay / waiting") << 0
+ << "QML Debugger: Waiting for connection on port 2423..."
+ << true << false;
+ QTest::addRow("no delay / failed") << 0 << "QML Debugger: Unable to listen to port 242."
+ << false << false;
+ QTest::addRow("no delay / unknown") << 0 << "QML Debugger: You don't know this string."
+ << false << true;
+ QTest::addRow("no delay / appout") << 0 << "Output from app itself."
+ << false << true;
+
+ QTest::addRow("delay / waiting") << 1000
+ << "QML Debugger: Waiting for connection on port 2423..."
+ << true << false;
+ QTest::addRow("delay / failed") << 1000 << "QML Debugger: Unable to listen to port 242."
+ << false << false;
+ QTest::addRow("delay / unknown") << 1000 << "QML Debugger: You don't know this string."
+ << false << true;
+ QTest::addRow("delay / appout") << 1000 << "Output from app itself."
+ << false << true;
+}
+
+void tst_QQmlDebugProcess::sessionStart()
+{
+ QFETCH(int, delay);
+ QFETCH(QString, arg);
+ QFETCH(bool, sessionExpected);
+ QFETCH(bool, outputExpected);
+
+ QScopedPointer<QQmlDebugProcess> process(
+ new QQmlDebugProcess(QCoreApplication::applicationDirPath()
+ + QLatin1String("/qqmldebugprocessprocess"), this));
+ QVERIFY(process);
+
+ bool outputReceived = false;
+ connect(process.data(), &QQmlDebugProcess::readyReadStandardOutput, this, [&]() {
+ QVERIFY(outputExpected);
+ QVERIFY(!outputReceived);
+ QCOMPARE(process->output().trimmed(), arg);
+ outputReceived = true;
+ QTimer::singleShot(qMax(delay, 0), process.data(), &QQmlDebugProcess::stop);
+ });
+
+ if (!outputExpected && !sessionExpected)
+ QTest::ignoreMessage(QtWarningMsg, "App was unable to bind to port!");
+ process->start(QStringList({arg}));
+
+ bool done = false;
+ auto wait = [&](){
+ QCOMPARE(process->waitForSessionStart(), sessionExpected);
+ QCOMPARE(outputReceived, outputExpected);
+ process->stop();
+ done = true;
+ };
+
+ if (delay < 0)
+ wait();
+ else
+ QTimer::singleShot(delay, process.data(), wait);
+
+ QTRY_VERIFY(done);
+ QCOMPARE(process->state(), QProcess::NotRunning);
+}
+
+QTEST_MAIN(tst_QQmlDebugProcess)
+
+#include "tst_qqmldebugprocess.moc"
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp
new file mode 100644
index 0000000000..21cce53fc3
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtCore/qdebug.h>
+#include <QtCore/qcoreapplication.h>
+
+// Process that just outputs a fake "Waiting" message.
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ if (argc > 1)
+ qDebug() << argv[1];
+ return app.exec();
+}
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro
new file mode 100644
index 0000000000..a8eb4885d4
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro
@@ -0,0 +1,11 @@
+QT = core
+macos:CONFIG -= app_bundle
+CONFIG -= debug_and_release_target
+CONFIG += console
+SOURCES += qqmldebugprocessprocess.cpp
+
+DESTDIR = ../qqmldebugprocess
+
+target.path = $$[QT_INSTALL_TESTS]/tst_qqmldebugprocess
+INSTALLS += target
+
diff --git a/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro
index 79cbe52331..3101d09ea5 100644
--- a/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro
+++ b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro
@@ -7,8 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h
SOURCES += tst_qqmldebugservice.cpp \
../shared/qqmldebugtestservice.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
index 8092faba04..3557940386 100644
--- a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
@@ -29,6 +29,7 @@
#include "qqmldebugtestservice.h"
#include "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
#include "../../../shared/util.h"
#include <private/qqmldebugclient_p.h>
@@ -74,16 +75,14 @@ void tst_QQmlDebugService::initTestCase()
QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer"));
QQmlDebugConnector::setServices(QStringList()
<< QStringLiteral("tst_QQmlDebugService"));
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugService", 2);
foreach (const QString &service, QQmlDebuggingEnabler::debuggerServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
foreach (const QString &service, QQmlDebuggingEnabler::inspectorServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
foreach (const QString &service, QQmlDebuggingEnabler::profilerServices())
- QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)0);
+ QCOMPARE(QQmlDebugConnector::instance()->service(service), (QQmlDebugService *)nullptr);
const QString waitingMsg = QString("QML Debugger: Waiting for connection on port %1...").arg(PORT);
QTest::ignoreMessage(QtDebugMsg, waitingMsg.toLatin1().constData());
@@ -105,10 +104,13 @@ void tst_QQmlDebugService::initTestCase()
void tst_QQmlDebugService::checkPortRange()
{
- QQmlDebugConnection *connection1 = new QQmlDebugConnection();
- QQmlDebugProcess *process1 = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
+ QScopedPointer<QQmlDebugConnection> connection1(new QQmlDebugConnection());
+ QScopedPointer<QQmlDebugProcess> process1(
+ new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath)
+ + "/qmlscene", this));
- process1->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") << testFile("test.qml"));
+ process1->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792")
+ << testFile("test.qml"));
if (!process1->waitForSessionStart())
QFAIL("could not launch application, or did not get 'Waiting for connection'.");
@@ -119,10 +121,13 @@ void tst_QQmlDebugService::checkPortRange()
QFAIL("could not connect to host!");
// Second instance
- QQmlDebugConnection *connection2 = new QQmlDebugConnection();
- QQmlDebugProcess *process2 = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
+ QScopedPointer<QQmlDebugConnection> connection2(new QQmlDebugConnection());
+ QScopedPointer<QQmlDebugProcess> process2(
+ new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath)
+ + "/qmlscene", this));
- process2->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") << testFile("test.qml"));
+ process2->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792")
+ << testFile("test.qml"));
if (!process2->waitForSessionStart())
QFAIL("could not launch application, or did not get 'Waiting for connection'.");
@@ -131,11 +136,6 @@ void tst_QQmlDebugService::checkPortRange()
connection2->connectToHost("127.0.0.1", port2);
if (!connection2->waitForConnected())
QFAIL("could not connect to host!");
-
- delete connection1;
- delete process1;
- delete connection2;
- delete process2;
}
void tst_QQmlDebugService::name()
@@ -207,7 +207,7 @@ void tst_QQmlDebugService::checkSupportForDataStreamVersion()
void tst_QQmlDebugService::idForObject()
{
- QCOMPARE(QQmlDebugService::idForObject(0), -1);
+ QCOMPARE(QQmlDebugService::idForObject(nullptr), -1);
QObject *objA = new QObject;
@@ -229,15 +229,15 @@ void tst_QQmlDebugService::idForObject()
void tst_QQmlDebugService::objectForId()
{
- QCOMPARE(QQmlDebugService::objectForId(-1), static_cast<QObject*>(0));
- QCOMPARE(QQmlDebugService::objectForId(1), static_cast<QObject*>(0));
+ QCOMPARE(QQmlDebugService::objectForId(-1), static_cast<QObject*>(nullptr));
+ QCOMPARE(QQmlDebugService::objectForId(1), static_cast<QObject*>(nullptr));
QObject *obj = new QObject;
int id = QQmlDebugService::idForObject(obj);
QCOMPARE(QQmlDebugService::objectForId(id), obj);
delete obj;
- QCOMPARE(QQmlDebugService::objectForId(id), static_cast<QObject*>(0));
+ QCOMPARE(QQmlDebugService::objectForId(id), static_cast<QObject*>(nullptr));
}
void tst_QQmlDebugService::checkSupportForOldDataStreamVersion()
diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro b/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro
index 2518650493..36957628b2 100644
--- a/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro
+++ b/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro
@@ -4,13 +4,11 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qqmlenginecontrol.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
-QT += core qml testlib gui-private core-private
+QT += core testlib gui-private core-private
OTHER_FILES += \
data/test.qml \
diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
index 3f8731ce6b..a8c43b1c75 100644
--- a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
+++ b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp
@@ -37,9 +37,6 @@
#include <QtTest/qtest.h>
#include <QtCore/qlibraryinfo.h>
-#define STR_PORT_FROM "13773"
-#define STR_PORT_TO "13783"
-
class QQmlEngineBlocker : public QObject
{
Q_OBJECT
@@ -64,77 +61,37 @@ void QQmlEngineBlocker::blockEngine(int engineId, const QString &name)
static_cast<QQmlEngineControlClient *>(parent())->blockEngine(engineId);
}
-class tst_QQmlEngineControl : public QQmlDataTest
+class tst_QQmlEngineControl : public QQmlDebugTest
{
Q_OBJECT
-public:
- tst_QQmlEngineControl()
- : m_process(0)
- , m_connection(0)
- , m_client(0)
- {}
-
private:
- QQmlDebugProcess *m_process;
- QQmlDebugConnection *m_connection;
- QQmlEngineControlClient *m_client;
+ ConnectResult connect(const QString &testFile, bool restrictServices);
+ QList<QQmlDebugClient *> createClients() override;
- void connect(const QString &testFile, bool restrictServices);
void engine_data();
+ QPointer<QQmlEngineControlClient> m_client;
private slots:
- void cleanup();
-
void startEngine_data();
void startEngine();
void stopEngine_data();
void stopEngine();
};
-void tst_QQmlEngineControl::connect(const QString &testFile, bool restrictServices)
+QQmlDebugTest::ConnectResult tst_QQmlEngineControl::connect(const QString &file,
+ bool restrictServices)
{
- const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene";
- QStringList arguments;
- arguments << QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3")
- .arg(STR_PORT_FROM).arg(STR_PORT_TO)
- .arg(restrictServices ? QStringLiteral(",services:EngineControl") : QString());
-
- arguments << QQmlDataTest::instance()->testFile(testFile);
-
- m_process = new QQmlDebugProcess(executable, this);
- m_process->start(QStringList() << arguments);
- QVERIFY2(m_process->waitForSessionStart(), "Could not launch application, or did not get 'Waiting for connection'.");
-
- m_connection = new QQmlDebugConnection();
- m_client = new QQmlEngineControlClient(m_connection);
- new QQmlEngineBlocker(m_client);
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection);
-
- const int port = m_process->debugPort();
- m_connection->connectToHost(QLatin1String("127.0.0.1"), port);
-
- QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
- foreach (QQmlDebugClient *other, others)
- QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
+ return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene",
+ restrictServices ? QStringLiteral("EngineControl") : QString(),
+ testFile(file), true);
}
-void tst_QQmlEngineControl::cleanup()
+QList<QQmlDebugClient *> tst_QQmlEngineControl::createClients()
{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null"));
- qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null"));
- qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection);
- qDebug() << "Client State:" << QQmlDebugTest::clientStateString(m_client);
- }
- delete m_process;
- m_process = 0;
- delete m_client;
- m_client = 0;
- delete m_connection;
- m_connection = 0;
+ m_client = new QQmlEngineControlClient(m_connection);
+ new QQmlEngineBlocker(m_client);
+ return QList<QQmlDebugClient *>({m_client});
}
void tst_QQmlEngineControl::engine_data()
@@ -152,14 +109,16 @@ void tst_QQmlEngineControl::startEngine_data()
void tst_QQmlEngineControl::startEngine()
{
QFETCH(bool, restrictMode);
-
- connect("test.qml", restrictMode);
+ QCOMPARE(connect("test.qml", restrictMode), ConnectSuccess);
QTRY_VERIFY(!m_client->blockedEngines().empty());
m_client->releaseEngine(m_client->blockedEngines().last());
+ QVERIFY(m_client->blockedEngines().isEmpty());
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAdded(int,QString))),
"No engine start message received in time.");
+
+ QVERIFY(m_client->blockedEngines().isEmpty());
}
void tst_QQmlEngineControl::stopEngine_data()
@@ -171,19 +130,23 @@ void tst_QQmlEngineControl::stopEngine()
{
QFETCH(bool, restrictMode);
- connect("exit.qml", restrictMode);
+ QCOMPARE(connect("exit.qml", restrictMode), ConnectSuccess);
QTRY_VERIFY(!m_client->blockedEngines().empty());
m_client->releaseEngine(m_client->blockedEngines().last());
+ QVERIFY(m_client->blockedEngines().isEmpty());
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAdded(int,QString))),
"No engine start message received in time.");
+ QVERIFY(m_client->blockedEngines().isEmpty());
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAboutToBeRemoved(int,QString))),
"No engine about to stop message received in time.");
m_client->releaseEngine(m_client->blockedEngines().last());
+ QVERIFY(m_client->blockedEngines().isEmpty());
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineRemoved(int,QString))),
"No engine stop message received in time.");
+ QVERIFY(m_client->blockedEngines().isEmpty());
}
QTEST_MAIN(tst_QQmlEngineControl)
diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro
index e11ccdc6ca..454a1e3ab0 100644
--- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro
+++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro
@@ -1,15 +1,11 @@
CONFIG += testcase
TARGET = tst_qqmlenginedebuginspectorintegration
-QT += qml testlib gui-private core-private
+QT += testlib gui-private core-private
osx:CONFIG -= app_bundle
SOURCES += tst_qqmlenginedebuginspectorintegration.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
-include(../shared/qqmlinspectorclient.pri)
-include(../shared/qqmlenginedebugclient.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
index 940f89e936..980e2be1f1 100644
--- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp
@@ -26,12 +26,12 @@
**
****************************************************************************/
-#include "qqmlinspectorclient.h"
-#include "qqmlenginedebugclient.h"
#include "../shared/debugutil_p.h"
#include "../../../shared/util.h"
#include <private/qqmldebugconnection_p.h>
+#include <private/qqmlenginedebugclient_p.h>
+#include <private/qqmlinspectorclient_p.h>
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
@@ -41,35 +41,21 @@
#include <QtCore/qthread.h>
#include <QtCore/qlibraryinfo.h>
-#define STR_PORT_FROM "3776"
-#define STR_PORT_TO "3786"
-
-class tst_QQmlEngineDebugInspectorIntegration : public QQmlDataTest
+class tst_QQmlEngineDebugInspectorIntegration : public QQmlDebugTest
{
Q_OBJECT
-public:
- tst_QQmlEngineDebugInspectorIntegration()
- : m_process(0)
- , m_inspectorClient(0)
- , m_engineDebugClient(0)
- , m_recipient(0)
- {
- }
-
-
private:
- void init(bool restrictServices);
- QmlDebugObjectReference findRootObject();
+ ConnectResult init(bool restrictServices);
+ QList<QQmlDebugClient *> createClients() override;
- QQmlDebugProcess *m_process;
- QQmlInspectorClient *m_inspectorClient;
- QQmlEngineDebugClient *m_engineDebugClient;
- QQmlInspectorResultRecipient *m_recipient;
+ QQmlEngineDebugObjectReference findRootObject();
-private slots:
- void cleanup();
+ QPointer<QQmlInspectorClient> m_inspectorClient;
+ QPointer<QQmlEngineDebugClient> m_engineDebugClient;
+ QPointer<QQmlInspectorResultRecipient> m_recipient;
+private slots:
void connect_data();
void connect();
void objectLocationLookup();
@@ -79,73 +65,42 @@ private slots:
void destroyObject();
};
-QmlDebugObjectReference tst_QQmlEngineDebugInspectorIntegration::findRootObject()
+QQmlEngineDebugObjectReference tst_QQmlEngineDebugInspectorIntegration::findRootObject()
{
bool success = false;
m_engineDebugClient->queryAvailableEngines(&success);
if (!QQmlDebugTest::waitForSignal(m_engineDebugClient, SIGNAL(result())))
- return QmlDebugObjectReference();
+ return QQmlEngineDebugObjectReference();
- m_engineDebugClient->queryRootContexts(m_engineDebugClient->engines()[0].debugId, &success);
+ m_engineDebugClient->queryRootContexts(m_engineDebugClient->engines()[0], &success);
if (!QQmlDebugTest::waitForSignal(m_engineDebugClient, SIGNAL(result())))
- return QmlDebugObjectReference();
+ return QQmlEngineDebugObjectReference();
int count = m_engineDebugClient->rootContext().contexts.count();
m_engineDebugClient->queryObject(
m_engineDebugClient->rootContext().contexts[count - 1].objects[0], &success);
if (!QQmlDebugTest::waitForSignal(m_engineDebugClient, SIGNAL(result())))
- return QmlDebugObjectReference();
+ return QQmlEngineDebugObjectReference();
return m_engineDebugClient->object();
}
-void tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices)
+QQmlDebugTest::ConnectResult tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices)
{
- const QString argument = QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3")
- .arg(STR_PORT_FROM).arg(STR_PORT_TO)
- .arg(restrictServices ? QStringLiteral(",services:QmlDebugger,QmlInspector") :
- QString());
-
- m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
- this);
- m_process->start(QStringList() << argument << testFile("qtquick2.qml"));
- QVERIFY2(m_process->waitForSessionStart(),
- "Could not launch application, or did not get 'Waiting for connection'.");
-
- QQmlDebugConnection *m_connection = new QQmlDebugConnection(this);
- m_inspectorClient = new QQmlInspectorClient(m_connection);
- m_engineDebugClient = new QQmlEngineDebugClient(m_connection);
- m_recipient = new QQmlInspectorResultRecipient(this);
- QObject::connect(m_inspectorClient, &QQmlInspectorClient::responseReceived,
- m_recipient, &QQmlInspectorResultRecipient::recordResponse);
-
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection);
-
- m_connection->connectToHost(QLatin1String("127.0.0.1"), m_process->debugPort());
- QVERIFY(m_connection->waitForConnected());
- foreach (QQmlDebugClient *other, others)
- QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
-
- QTRY_COMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled);
- QTRY_COMPARE(m_engineDebugClient->state(), QQmlDebugClient::Enabled);
+ return QQmlDebugTest::connect(
+ QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ restrictServices ? QStringLiteral("QmlDebugger,QmlInspector") : QString(),
+ testFile("qtquick2.qml"), true);
}
-void tst_QQmlEngineDebugInspectorIntegration::cleanup()
+QList<QQmlDebugClient *> tst_QQmlEngineDebugInspectorIntegration::createClients()
{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << m_process->state();
- qDebug() << "Application Output:" << m_process->output();
- }
- delete m_process;
- m_process = 0;
- delete m_engineDebugClient;
- m_engineDebugClient = 0;
- delete m_inspectorClient;
- m_inspectorClient = 0;
- delete m_recipient;
- m_recipient = 0;
+ m_inspectorClient = new QQmlInspectorClient(m_connection);
+ m_engineDebugClient = new QQmlEngineDebugClient(m_connection);
+ m_recipient = new QQmlInspectorResultRecipient(m_inspectorClient);
+ QObject::connect(m_inspectorClient.data(), &QQmlInspectorClient::responseReceived,
+ m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse);
+ return QList<QQmlDebugClient *>({m_inspectorClient, m_engineDebugClient});
}
void tst_QQmlEngineDebugInspectorIntegration::connect_data()
@@ -158,15 +113,15 @@ void tst_QQmlEngineDebugInspectorIntegration::connect_data()
void tst_QQmlEngineDebugInspectorIntegration::connect()
{
QFETCH(bool, restrictMode);
- init(restrictMode);
+ QCOMPARE(init(restrictMode), ConnectSuccess);
}
void tst_QQmlEngineDebugInspectorIntegration::objectLocationLookup()
{
- init(true);
+ QCOMPARE(init(true), ConnectSuccess);
bool success = false;
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(rootObject.debugId != -1);
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
@@ -176,7 +131,7 @@ void tst_QQmlEngineDebugInspectorIntegration::objectLocationLookup()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_engineDebugClient, SIGNAL(result())));
- foreach (QmlDebugObjectReference child, rootObject.children) {
+ foreach (QQmlEngineDebugObjectReference child, rootObject.children) {
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@@ -189,11 +144,12 @@ void tst_QQmlEngineDebugInspectorIntegration::objectLocationLookup()
void tst_QQmlEngineDebugInspectorIntegration::select()
{
- init(true);
- QmlDebugObjectReference rootObject = findRootObject();
+ QCOMPARE(init(true), ConnectSuccess);
+
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QList<int> childIds;
int requestId = 0;
- foreach (const QmlDebugObjectReference &child, rootObject.children) {
+ foreach (const QQmlEngineDebugObjectReference &child, rootObject.children) {
requestId = m_inspectorClient->select(QList<int>() << child.debugId);
QTRY_COMPARE(m_recipient->lastResponseId, requestId);
QVERIFY(m_recipient->lastResult);
@@ -206,7 +162,7 @@ void tst_QQmlEngineDebugInspectorIntegration::select()
void tst_QQmlEngineDebugInspectorIntegration::createObject()
{
- init(true);
+ QCOMPARE(init(true), ConnectSuccess);
QString qml = QLatin1String("Rectangle {\n"
" id: xxxyxxx\n"
@@ -215,7 +171,7 @@ void tst_QQmlEngineDebugInspectorIntegration::createObject()
" color: \"blue\"\n"
"}");
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(rootObject.debugId != -1);
QCOMPARE(rootObject.children.length(), 2);
@@ -233,8 +189,10 @@ void tst_QQmlEngineDebugInspectorIntegration::createObject()
void tst_QQmlEngineDebugInspectorIntegration::moveObject()
{
- init(true);
- QmlDebugObjectReference rootObject = findRootObject();
+ QCOMPARE(init(true), ConnectSuccess);
+
+ QCOMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled);
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(rootObject.debugId != -1);
QCOMPARE(rootObject.children.length(), 2);
@@ -256,8 +214,10 @@ void tst_QQmlEngineDebugInspectorIntegration::moveObject()
void tst_QQmlEngineDebugInspectorIntegration::destroyObject()
{
- init(true);
- QmlDebugObjectReference rootObject = findRootObject();
+ QCOMPARE(init(true), ConnectSuccess);
+
+ QCOMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled);
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(rootObject.debugId != -1);
QCOMPARE(rootObject.children.length(), 2);
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro b/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro
index 06250d9940..5ff65ba276 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro
@@ -5,11 +5,8 @@ osx:CONFIG -= app_bundle
SOURCES += \
tst_qqmlenginedebugservice.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
-include(../shared/qqmlenginedebugclient.pri)
include(../shared/debugutil.pri)
DEFINES += QT_QML_DEBUG_NO_WARNING
-QT += core-private qml-private quick-private testlib gui-private
+QT += quick qml-private testlib
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index d9a4777115..99c90c142f 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -26,7 +26,6 @@
**
****************************************************************************/
-#include "qqmlenginedebugclient.h"
#include "debugutil_p.h"
#include "../../../shared/util.h"
@@ -36,6 +35,7 @@
#include <private/qqmlmetatype_p.h>
#include <private/qqmlproperty_p.h>
#include <private/qqmldebugconnection_p.h>
+#include <private/qqmlenginedebugclient_p.h>
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
@@ -53,11 +53,14 @@
#include <QtCore/qdebug.h>
#include <QtCore/qthread.h>
#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
#define QVERIFYOBJECT(statement) \
do {\
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
- return QmlDebugObjectReference();\
+ return QQmlEngineDebugObjectReference();\
}\
} while (0)
@@ -77,28 +80,64 @@ class CustomTypes : public QObject
Q_OBJECT
Q_PROPERTY(QModelIndex modelIndex READ modelIndex)
public:
- CustomTypes(QObject *parent = 0) : QObject(parent) {}
+ CustomTypes(QObject *parent = nullptr) : QObject(parent) {}
QModelIndex modelIndex() { return QModelIndex(); }
};
+class JsonTest : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QJsonObject data READ data WRITE setData NOTIFY dataChanged)
+
+public:
+ JsonTest(QObject *parent = 0) : QObject(parent)
+ {
+ m_data["foo"] = QJsonValue(12);
+ m_data["ttt"] = QJsonArray({4, 5, 4, 3, 2});
+ m_data["a"] = QJsonValue(QJsonValue::Null);
+ m_data["b"] = QJsonValue(QJsonValue::Undefined);
+ m_data["c"] = QJsonValue("fffff");
+ }
+
+ QJsonObject data() const { return m_data; }
+
+signals:
+ void dataChanged(const QJsonObject &data);
+
+public slots:
+ void setData(const QJsonObject &data)
+ {
+ if (data != m_data) {
+ m_data = data;
+ emit dataChanged(data);
+ }
+ }
+
+private:
+ QJsonObject m_data;
+};
+
+
class tst_QQmlEngineDebugService : public QObject
{
Q_OBJECT
public:
- tst_QQmlEngineDebugService() : m_conn(0), m_dbg(0), m_engine(0), m_rootItem(0) {}
+ tst_QQmlEngineDebugService() : m_conn(nullptr), m_dbg(nullptr), m_engine(nullptr), m_rootItem(nullptr) {}
private:
- QmlDebugObjectReference findRootObject(int context = 0,
+ QQmlEngineDebugObjectReference findRootObject(int context = 0,
bool recursive = false);
- QmlDebugPropertyReference findProperty(
- const QList<QmlDebugPropertyReference> &props,
+ QQmlEngineDebugPropertyReference findProperty(
+ const QList<QQmlEngineDebugPropertyReference> &props,
const QString &name) const;
void recursiveObjectTest(QObject *o,
- const QmlDebugObjectReference &oref,
+ const QQmlEngineDebugObjectReference &oref,
bool recursive) const;
+ void getContexts();
+
QQmlDebugConnection *m_conn;
QQmlEngineDebugClient *m_dbg;
QQmlEngine *m_engine;
@@ -137,10 +176,13 @@ private slots:
void regression_QTCREATORBUG_7451();
void queryObjectWithNonStreamableTypes();
+ void jsonData();
void asynchronousCreate();
+ void invalidContexts();
+ void createObjectOnDestruction();
};
-QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
+QQmlEngineDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
int context, bool recursive)
{
bool success = false;
@@ -149,7 +191,7 @@ QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFYOBJECT(m_dbg->engines().count());
- m_dbg->queryRootContexts(m_dbg->engines()[0].debugId, &success);
+ m_dbg->queryRootContexts(m_dbg->engines()[0], &success);
QVERIFYOBJECT(success);
QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
@@ -165,18 +207,18 @@ QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
return m_dbg->object();
}
-QmlDebugPropertyReference tst_QQmlEngineDebugService::findProperty(
- const QList<QmlDebugPropertyReference> &props, const QString &name) const
+QQmlEngineDebugPropertyReference tst_QQmlEngineDebugService::findProperty(
+ const QList<QQmlEngineDebugPropertyReference> &props, const QString &name) const
{
- foreach (const QmlDebugPropertyReference &p, props) {
+ foreach (const QQmlEngineDebugPropertyReference &p, props) {
if (p.name == name)
return p;
}
- return QmlDebugPropertyReference();
+ return QQmlEngineDebugPropertyReference();
}
void tst_QQmlEngineDebugService::recursiveObjectTest(
- QObject *o, const QmlDebugObjectReference &oref, bool recursive) const
+ QObject *o, const QQmlEngineDebugObjectReference &oref, bool recursive) const
{
const QMetaObject *meta = o->metaObject();
@@ -194,8 +236,8 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
int debugId = QQmlDebugService::idForObject(child);
QVERIFY(debugId >= 0);
- QmlDebugObjectReference cref;
- foreach (const QmlDebugObjectReference &ref, oref.children) {
+ QQmlEngineDebugObjectReference cref;
+ foreach (const QQmlEngineDebugObjectReference &ref, oref.children) {
QVERIFY(!ref.className.isEmpty());
if (ref.debugId == debugId) {
cref = ref;
@@ -208,7 +250,7 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
recursiveObjectTest(child, cref, true);
}
- foreach (const QmlDebugPropertyReference &p, oref.properties) {
+ foreach (const QQmlEngineDebugPropertyReference &p, oref.properties) {
QCOMPARE(p.objectDebugId, QQmlDebugService::idForObject(o));
// signal properties are fake - they are generated from QQmlAbstractBoundSignal children
@@ -226,9 +268,24 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
QCOMPARE(p.name, QString::fromUtf8(pmeta.name()));
- if (pmeta.type() < QVariant::UserType && pmeta.userType() !=
- QMetaType::QVariant) // TODO test complex types
- QCOMPARE(p.value , pmeta.read(o));
+ if (pmeta.userType() == QMetaType::QObjectStar) {
+ const QQmlEngineDebugObjectReference ref
+ = qvariant_cast<QQmlEngineDebugObjectReference>(p.value);
+ QObject *pobj = qvariant_cast<QObject *>(pmeta.read(o));
+ if (pobj) {
+ if (pobj->objectName().isEmpty())
+ QCOMPARE(ref.name, QString("<unnamed object>"));
+ else
+ QCOMPARE(ref.name, pobj->objectName());
+ } else {
+ QCOMPARE(ref.name, QString("<unknown value>"));
+ }
+ } else if (pmeta.type() < QVariant::UserType && pmeta.userType() != QMetaType::QVariant) {
+ const QVariant expected = pmeta.read(o);
+ QVERIFY2(p.value == expected, QString::fromLatin1("%1 != %2. Details: %3/%4/%5/%6")
+ .arg(QTest::toString(p.value)).arg(QTest::toString(expected)).arg(p.name)
+ .arg(p.valueTypeName).arg(pmeta.type()).arg(pmeta.userType()).toUtf8());
+ }
if (p.name == "parent")
QVERIFY(p.valueTypeName == "QGraphicsObject*" ||
@@ -248,6 +305,22 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
}
}
+void tst_QQmlEngineDebugService::getContexts()
+{
+ bool success = false;
+
+ m_dbg->queryAvailableEngines(&success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
+
+ QList<QQmlEngineDebugEngineReference> engines = m_dbg->engines();
+ QCOMPARE(engines.count(), 1);
+ m_dbg->queryRootContexts(engines.first(), &success);
+
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
+}
+
void tst_QQmlEngineDebugService::initTestCase()
{
qmlRegisterType<NonScriptProperty>("Test", 1, 0, "NonScriptPropertyElement");
@@ -329,6 +402,11 @@ void tst_QQmlEngineDebugService::initTestCase()
"CustomTypes {}"
;
+ qmlRegisterType<JsonTest>("JsonTest", 1, 0, "JsonTest");
+ qml << "import JsonTest 1.0\n"
+ "JsonTest {}"
+ ;
+
for (int i=0; i<qml.count(); i++) {
QQmlComponent component(m_engine);
component.setData(qml[i], QUrl::fromLocalFile(""));
@@ -364,7 +442,7 @@ void tst_QQmlEngineDebugService::cleanupTestCase()
void tst_QQmlEngineDebugService::setMethodBody()
{
bool success;
- QmlDebugObjectReference obj = findRootObject(2);
+ QQmlEngineDebugObjectReference obj = findRootObject(2);
QVERIFY(!obj.className.isEmpty());
QObject *root = m_components.at(2);
@@ -406,18 +484,18 @@ void tst_QQmlEngineDebugService::setMethodBody()
void tst_QQmlEngineDebugService::watch_property()
{
- QmlDebugObjectReference obj = findRootObject();
+ QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
- QmlDebugPropertyReference prop = findProperty(obj.properties, "width");
+ QQmlEngineDebugPropertyReference prop = findProperty(obj.properties, "width");
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(prop, &success);
QVERIFY(!success);
delete unconnected;
- m_dbg->addWatch(QmlDebugPropertyReference(), &success);
+ m_dbg->addWatch(QQmlEngineDebugPropertyReference(), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
@@ -451,17 +529,17 @@ void tst_QQmlEngineDebugService::watch_property()
void tst_QQmlEngineDebugService::watch_object()
{
- QmlDebugObjectReference obj = findRootObject();
+ QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(obj, &success);
QVERIFY(!success);
delete unconnected;
- m_dbg->addWatch(QmlDebugObjectReference(), &success);
+ m_dbg->addWatch(QQmlEngineDebugObjectReference(), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
@@ -517,17 +595,17 @@ void tst_QQmlEngineDebugService::watch_expression()
int origWidth = m_rootItem->property("width").toInt();
- QmlDebugObjectReference obj = findRootObject();
+ QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(obj, expr, &success);
QVERIFY(!success);
delete unconnected;
- m_dbg->addWatch(QmlDebugObjectReference(), expr, &success);
+ m_dbg->addWatch(QQmlEngineDebugObjectReference(), expr, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
@@ -577,7 +655,7 @@ void tst_QQmlEngineDebugService::watch_expression_data()
void tst_QQmlEngineDebugService::watch_context()
{
- QmlDebugContextReference c;
+ QQmlEngineDebugContextReference c;
QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
bool success;
m_dbg->addWatch(c, QString(), &success);
@@ -586,7 +664,7 @@ void tst_QQmlEngineDebugService::watch_context()
void tst_QQmlEngineDebugService::watch_file()
{
- QmlDebugFileReference f;
+ QQmlEngineDebugFileReference f;
QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
bool success;
m_dbg->addWatch(f, &success);
@@ -597,7 +675,7 @@ void tst_QQmlEngineDebugService::queryAvailableEngines()
{
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryAvailableEngines(&success);
QVERIFY(!success);
delete unconnected;
@@ -607,10 +685,10 @@ void tst_QQmlEngineDebugService::queryAvailableEngines()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
// TODO test multiple engines
- QList<QmlDebugEngineReference> engines = m_dbg->engines();
+ QList<QQmlEngineDebugEngineReference> engines = m_dbg->engines();
QCOMPARE(engines.count(), 1);
- foreach (const QmlDebugEngineReference &e, engines) {
+ foreach (const QQmlEngineDebugEngineReference &e, engines) {
QCOMPARE(e.debugId, QQmlDebugService::idForObject(m_engine));
QCOMPARE(e.name, m_engine->objectName());
}
@@ -623,26 +701,26 @@ void tst_QQmlEngineDebugService::queryRootContexts()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(m_dbg->engines().count());
- int engineId = m_dbg->engines()[0].debugId;
+ const QQmlEngineDebugEngineReference engine = m_dbg->engines()[0];
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
- unconnected->queryRootContexts(engineId, &success);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
+ unconnected->queryRootContexts(engine, &success);
QVERIFY(!success);
delete unconnected;
- m_dbg->queryRootContexts(engineId, &success);
+ m_dbg->queryRootContexts(engine, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QQmlContext *actualContext = m_engine->rootContext();
- QmlDebugContextReference context = m_dbg->rootContext();
+ QQmlEngineDebugContextReference context = m_dbg->rootContext();
QCOMPARE(context.debugId, QQmlDebugService::idForObject(actualContext));
QCOMPARE(context.name, actualContext->objectName());
// root context query sends only root object data - it doesn't fill in
// the children or property info
QCOMPARE(context.objects.count(), 0);
- QCOMPARE(context.contexts.count(), 6);
+ QCOMPARE(context.contexts.count(), 7);
QVERIFY(context.contexts[0].debugId >= 0);
QCOMPARE(context.contexts[0].name, QString("tst_QQmlDebug_childContext"));
}
@@ -653,10 +731,10 @@ void tst_QQmlEngineDebugService::queryObject()
bool success;
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
QVERIFY(!success);
delete unconnected;
@@ -665,11 +743,11 @@ void tst_QQmlEngineDebugService::queryObject()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
- QmlDebugObjectReference obj = m_dbg->object();
+ QQmlEngineDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
- QmlDebugFileReference source = obj.source;
+ QQmlEngineDebugFileReference source = obj.source;
QCOMPARE(source.url, QUrl::fromLocalFile(""));
QCOMPARE(source.lineNumber, 3);
QCOMPARE(source.columnNumber, 1);
@@ -678,14 +756,14 @@ void tst_QQmlEngineDebugService::queryObject()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
}
- QmlDebugObjectReference rect;
- QmlDebugObjectReference text;
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ QQmlEngineDebugObjectReference rect;
+ QQmlEngineDebugObjectReference text;
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
@@ -700,7 +778,7 @@ void tst_QQmlEngineDebugService::queryObject()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
}
@@ -721,14 +799,14 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
bool success;
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
int columnNumber = rootObject.source.columnNumber;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
recursive ? unconnected->queryObjectsForLocationRecursive(fileName, lineNumber,
columnNumber, &success)
: unconnected->queryObjectsForLocation(fileName, lineNumber,
@@ -744,11 +822,11 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->objects().count(), 1);
- QmlDebugObjectReference obj = m_dbg->objects().first();
+ QQmlEngineDebugObjectReference obj = m_dbg->objects().first();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
- QmlDebugFileReference source = obj.source;
+ QQmlEngineDebugFileReference source = obj.source;
QCOMPARE(source.url, QUrl(fileName));
QCOMPARE(source.lineNumber, lineNumber);
QCOMPARE(source.columnNumber, columnNumber);
@@ -757,14 +835,14 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
}
- QmlDebugObjectReference rect;
- QmlDebugObjectReference text;
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ QQmlEngineDebugObjectReference rect;
+ QQmlEngineDebugObjectReference text;
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
@@ -779,7 +857,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children) {
+ foreach (const QQmlEngineDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
}
@@ -796,7 +874,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
{
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
int contextId = rootObject.contextDebugId;
QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
@@ -823,7 +901,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
- foreach (QmlDebugObjectReference child, rootObject.children) {
+ foreach (QQmlEngineDebugObjectReference child, rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
@@ -846,7 +924,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
- foreach (QmlDebugObjectReference child, rootObject.children) {
+ foreach (QQmlEngineDebugObjectReference child, rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
@@ -862,10 +940,10 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
{
bool success;
- QmlDebugObjectReference rootObject = findRootObject(4, true);
+ QQmlEngineDebugObjectReference rootObject = findRootObject(4, true);
QVERIFY(!rootObject.className.isEmpty());
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryObject(rootObject, &success);
QVERIFY(!success);
delete unconnected;
@@ -874,12 +952,31 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
- QmlDebugObjectReference obj = m_dbg->object();
+ QQmlEngineDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
- QCOMPARE(findProperty(obj.properties, "modelIndex").value, QVariant());
+ QCOMPARE(findProperty(obj.properties, "modelIndex").value,
+ QVariant(QLatin1String("QModelIndex()")));
}
+void tst_QQmlEngineDebugService::jsonData()
+{
+ bool success;
+
+ QQmlEngineDebugObjectReference rootObject = findRootObject(5, true);
+ QVERIFY(!rootObject.className.isEmpty());
+
+ m_dbg->queryObject(rootObject, &success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
+
+ QQmlEngineDebugObjectReference obj = m_dbg->object();
+ QVERIFY(!obj.className.isEmpty());
+
+ QCOMPARE(findProperty(obj.properties, "data").value,
+ QJsonDocument::fromJson("{\"a\":null,\"c\":\"fffff\",\"foo\":12,\"ttt\":[4,5,4,3,2]}")
+ .toVariant());
+}
void tst_QQmlEngineDebugService::queryExpressionResult()
{
@@ -890,7 +987,7 @@ void tst_QQmlEngineDebugService::queryExpressionResult()
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryExpressionResult(objectId, expr, &success);
QVERIFY(!success);
delete unconnected;
@@ -938,7 +1035,7 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC()
bool success;
- QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
+ QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryExpressionResultBC(objectId, expr, &success);
QVERIFY(!success);
delete unconnected;
@@ -968,10 +1065,10 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
void tst_QQmlEngineDebugService::setBindingForObject()
{
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
- QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
+ QQmlEngineDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(10));
QCOMPARE(widthPropertyRef.binding, QString());
@@ -1016,7 +1113,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
- QmlDebugObjectReference mouseAreaObject = rootObject.children.at(2);
+ QQmlEngineDebugObjectReference mouseAreaObject = rootObject.children.at(2);
QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
@@ -1024,11 +1121,11 @@ void tst_QQmlEngineDebugService::setBindingForObject()
mouseAreaObject = m_dbg->object();
QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
- QmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
+ QQmlEngineDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
// Sorry, can't do that anymore: QCOMPARE(onEnteredRef.value, QVariant("{ console.log('hello') }"));
- QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }"));
+ QCOMPARE(onEnteredRef.value, QVariant("function() { [native code] }"));
m_dbg->setBindingForObject(mouseAreaObject.debugId, "onEntered",
"{console.log('hello, world') }", false,
@@ -1048,15 +1145,15 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QVERIFY(!mouseAreaObject.className.isEmpty());
onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
- QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }"));
+ QCOMPARE(onEnteredRef.value, QVariant("function() { [native code] }"));
}
void tst_QQmlEngineDebugService::resetBindingForObject()
{
- QmlDebugObjectReference rootObject = findRootObject();
+ QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
- QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
+ QQmlEngineDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
bool success = false;
@@ -1092,7 +1189,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
- QmlDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
+ QQmlEngineDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
QCOMPARE(boldPropertyRef.value.toBool(), false);
QCOMPARE(boldPropertyRef.binding, QString());
@@ -1104,7 +1201,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
const int sourceIndex = 3;
- QmlDebugObjectReference obj = findRootObject(sourceIndex);
+ QQmlEngineDebugObjectReference obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
@@ -1137,11 +1234,11 @@ void tst_QQmlEngineDebugService::setBindingInStates()
// change the binding
- QmlDebugObjectReference state = obj.children[1];
+ QQmlEngineDebugObjectReference state = obj.children[1];
QCOMPARE(state.className, QString("State"));
QVERIFY(state.children.count() > 0);
- QmlDebugObjectReference propertyChange = state.children[0];
+ QQmlEngineDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
@@ -1220,51 +1317,53 @@ void tst_QQmlEngineDebugService::queryObjectTree()
{
const int sourceIndex = 3;
- QmlDebugObjectReference obj = findRootObject(sourceIndex, true);
+ QQmlEngineDebugObjectReference obj = findRootObject(sourceIndex, true);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
// check state
- QmlDebugObjectReference state = obj.children[1];
+ QQmlEngineDebugObjectReference state = obj.children[1];
QCOMPARE(state.className, QString("State"));
QVERIFY(state.children.count() > 0);
- QmlDebugObjectReference propertyChange = state.children[0];
+ QQmlEngineDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
- QmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
+ QQmlEngineDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
- QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value);
+ QQmlEngineDebugObjectReference targetReference = qvariant_cast<QQmlEngineDebugObjectReference>(propertyChangeTarget.value);
QVERIFY(!targetReference.className.isEmpty());
- QVERIFY(targetReference.debugId != -1);
+ QCOMPARE(targetReference.debugId, -1);
+ QCOMPARE(targetReference.name, QString("<unnamed object>"));
// check transition
- QmlDebugObjectReference transition = obj.children[0];
+ QQmlEngineDebugObjectReference transition = obj.children[0];
QCOMPARE(transition.className, QString("Transition"));
QCOMPARE(findProperty(transition.properties,"from").value.toString(), QString("*"));
QCOMPARE(findProperty(transition.properties,"to").value, findProperty(state.properties,"name").value);
QVERIFY(transition.children.count() > 0);
- QmlDebugObjectReference animation = transition.children[0];
+ QQmlEngineDebugObjectReference animation = transition.children[0];
QVERIFY(!animation.className.isEmpty());
QVERIFY(animation.debugId != -1);
- QmlDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
+ QQmlEngineDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
QCOMPARE(animationTarget.objectDebugId, animation.debugId);
- targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value);
+ targetReference = qvariant_cast<QQmlEngineDebugObjectReference>(animationTarget.value);
QVERIFY(!targetReference.className.isEmpty());
- QVERIFY(targetReference.debugId != -1);
+ QCOMPARE(targetReference.debugId, -1);
+ QCOMPARE(targetReference.name, QString("<unnamed object>"));
QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width"));
QCOMPARE(findProperty(animation.properties,"duration").value.toInt(), 100);
}
void tst_QQmlEngineDebugService::asynchronousCreate() {
- QmlDebugObjectReference object;
+ QQmlEngineDebugObjectReference object;
auto connection = connect(m_dbg, &QQmlEngineDebugClient::newObject, this, [&](int objectId) {
object.debugId = objectId;
});
@@ -1289,6 +1388,49 @@ void tst_QQmlEngineDebugService::asynchronousCreate() {
QTRY_COMPARE(m_dbg->object().idString, QLatin1String("asyncRect"));
}
+void tst_QQmlEngineDebugService::invalidContexts()
+{
+ getContexts();
+ const int base = m_dbg->rootContext().contexts.count();
+ QQmlContext context(m_engine);
+ getContexts();
+ QCOMPARE(m_dbg->rootContext().contexts.count(), base + 1);
+ QQmlContextData *contextData = QQmlContextData::get(&context);
+ contextData->invalidate();
+ getContexts();
+ QCOMPARE(m_dbg->rootContext().contexts.count(), base);
+ QQmlContextData *rootData = QQmlContextData::get(m_engine->rootContext());
+ rootData->invalidate();
+ getContexts();
+ QCOMPARE(m_dbg->rootContext().contexts.count(), 0);
+ contextData->setParent(rootData); // makes context valid again, but not root.
+ getContexts();
+ QCOMPARE(m_dbg->rootContext().contexts.count(), 0);
+}
+
+void tst_QQmlEngineDebugService::createObjectOnDestruction()
+{
+ QSignalSpy spy(m_dbg, SIGNAL(newObject(int)));
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQml 2.0;"
+ "QtObject {"
+ "property Component x:"
+ "Qt.createQmlObject('import QtQml 2.0; Component { QtObject { } }',"
+ "this, 'x.qml');"
+ "Component.onDestruction: x.createObject(this, {});"
+ "}", QUrl::fromLocalFile("x.qml"));
+ QVERIFY(component.isReady());
+ QVERIFY(component.create());
+ QTRY_COMPARE(spy.count(), 2);
+ }
+ // Doesn't crash and doesn't give us another signal for the object created on destruction.
+ QTest::qWait(500);
+ QCOMPARE(spy.count(), 2);
+}
+
int main(int argc, char *argv[])
{
int _argc = argc + 1;
diff --git a/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro
index ee5f3c708a..0d42030b52 100644
--- a/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro
+++ b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro
@@ -1,14 +1,11 @@
CONFIG += testcase
TARGET = tst_qqmlinspector
-QT += qml testlib gui-private core-private
+QT += testlib gui-private core-private
osx:CONFIG -= app_bundle
SOURCES += tst_qqmlinspector.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
-include(../shared/qqmlinspectorclient.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
index 9461922eff..6685558bb5 100644
--- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
+++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
@@ -26,11 +26,12 @@
**
****************************************************************************/
-#include "qqmlinspectorclient.h"
#include "../shared/debugutil_p.h"
+#include "../shared/qqmldebugprocess_p.h"
#include "../../../shared/util.h"
#include <private/qqmldebugconnection_p.h>
+#include <private/qqmlinspectorclient_p.h>
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
@@ -40,64 +41,32 @@
#include <QtCore/qlibraryinfo.h>
#include <QtNetwork/qhostaddress.h>
-#define STR_PORT_FROM "3772"
-#define STR_PORT_TO "3782"
-
-
-class tst_QQmlInspector : public QQmlDataTest
+class tst_QQmlInspector : public QQmlDebugTest
{
Q_OBJECT
private:
- void startQmlProcess(const QString &qmlFile, bool restrictMode = true);
+ ConnectResult startQmlProcess(const QString &qmlFile, bool restrictMode = true);
void checkAnimationSpeed(int targetMillisPerDegree);
+ QList<QQmlDebugClient *> createClients() override;
+ QQmlDebugProcess *createProcess(const QString &executable) override;
-private:
- QScopedPointer<QQmlDebugProcess> m_process;
- QScopedPointer<QQmlDebugConnection> m_connection;
- QScopedPointer<QQmlInspectorClient> m_client;
- QScopedPointer<QQmlInspectorResultRecipient> m_recipient;
+ QPointer<QQmlInspectorClient> m_client;
+ QPointer<QQmlInspectorResultRecipient> m_recipient;
private slots:
- void cleanup();
-
void connect_data();
void connect();
void setAnimationSpeed();
void showAppOnTop();
};
-void tst_QQmlInspector::startQmlProcess(const QString &qmlFile, bool restrictServices)
+QQmlDebugTest::ConnectResult tst_QQmlInspector::startQmlProcess(const QString &qmlFile,
+ bool restrictServices)
{
- const QString argument = QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3")
- .arg(STR_PORT_FROM).arg(STR_PORT_TO)
- .arg(restrictServices ? QStringLiteral(",services:QmlInspector") : QString());
-
- m_process.reset(new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) +
- "/qml"));
- // Make sure the animation timing is exact
- m_process->addEnvironment(QLatin1String("QSG_RENDER_LOOP=basic"));
- m_process->start(QStringList() << argument << testFile(qmlFile));
- QVERIFY2(m_process->waitForSessionStart(),
- "Could not launch application, or did not get 'Waiting for connection'.");
-
- m_client.reset();
- m_connection.reset(new QQmlDebugConnection);
- m_client.reset(new QQmlInspectorClient(m_connection.data()));
-
- m_recipient.reset(new QQmlInspectorResultRecipient);
- QObject::connect(m_client.data(), &QQmlInspectorClient::responseReceived,
- m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse);
-
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection.data());
-
- m_connection->connectToHost(QLatin1String("127.0.0.1"), m_process->debugPort());
- QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
-
- foreach (QQmlDebugClient *other, others)
- QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
+ return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ restrictServices ? QStringLiteral("QmlInspector") : QString(),
+ testFile(qmlFile), true);
}
void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree)
@@ -114,8 +83,7 @@ void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree)
QString output = m_process->output();
int position = output.length();
do {
- QVERIFY(QQmlDebugTest::waitForSignal(m_process.data(),
- SIGNAL(readyReadStandardOutput())));
+ QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
output = m_process->output();
} while (!output.mid(position).contains(markerString));
@@ -144,12 +112,21 @@ void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree)
.arg(targetMillisPerDegree).toLocal8Bit().constData());
}
-void tst_QQmlInspector::cleanup()
+QList<QQmlDebugClient *> tst_QQmlInspector::createClients()
{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << m_process->state();
- qDebug() << "Application Output:" << m_process->output();
- }
+ m_client = new QQmlInspectorClient(m_connection);
+ m_recipient = new QQmlInspectorResultRecipient(m_client);
+ QObject::connect(m_client.data(), &QQmlInspectorClient::responseReceived,
+ m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse);
+ return QList<QQmlDebugClient *>({m_client});
+}
+
+QQmlDebugProcess *tst_QQmlInspector::createProcess(const QString &executable)
+{
+ QQmlDebugProcess *process = QQmlDebugTest::createProcess(executable);
+ // Make sure the animation timing is exact
+ process->addEnvironment(QLatin1String("QSG_RENDER_LOOP=basic"));
+ return process;
}
void tst_QQmlInspector::connect_data()
@@ -166,7 +143,7 @@ void tst_QQmlInspector::connect()
{
QFETCH(QString, file);
QFETCH(bool, restrictMode);
- startQmlProcess(file, restrictMode);
+ QCOMPARE(startQmlProcess(file, restrictMode), ConnectSuccess);
QVERIFY(m_client);
QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
@@ -181,7 +158,7 @@ void tst_QQmlInspector::connect()
void tst_QQmlInspector::showAppOnTop()
{
- startQmlProcess("qtquick2.qml");
+ QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess);
QVERIFY(m_client);
QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
@@ -196,7 +173,7 @@ void tst_QQmlInspector::showAppOnTop()
void tst_QQmlInspector::setAnimationSpeed()
{
- startQmlProcess("qtquick2.qml");
+ QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess);
QVERIFY(m_client);
QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
checkAnimationSpeed(10);
diff --git a/tests/auto/qml/debugger/qqmlnativeconnector/tst_qqmlnativeconnector.cpp b/tests/auto/qml/debugger/qqmlnativeconnector/tst_qqmlnativeconnector.cpp
index 33d3c6369f..6283a93881 100644
--- a/tests/auto/qml/debugger/qqmlnativeconnector/tst_qqmlnativeconnector.cpp
+++ b/tests/auto/qml/debugger/qqmlnativeconnector/tst_qqmlnativeconnector.cpp
@@ -113,7 +113,7 @@ int main(int argc, char *argv[])
argv2[i] = argv[i];
argv2[argc] = strdup("-qmljsdebugger=native,services:NativeQmlDebugger");
++argc;
- argv2[argc] = 0;
+ argv2[argc] = nullptr;
Application app(argc, argv2);
return QTest::qExec(&app, argc, argv);
}
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/broken.qml b/tests/auto/qml/debugger/qqmlpreview/data/broken.qml
new file mode 100644
index 0000000000..4ebbf7576a
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/broken.qml
@@ -0,0 +1,31 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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
+
+Item {
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/i18n/qml_fr_FR.qm b/tests/auto/qml/debugger/qqmlpreview/data/i18n/qml_fr_FR.qm
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/i18n/qml_fr_FR.qm
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/qtquick2.qml b/tests/auto/qml/debugger/qqmlpreview/data/qtquick2.qml
new file mode 100644
index 0000000000..b525ab4fa0
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/qtquick2.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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
+
+Rectangle {
+ width: 100
+ height: 100
+ color: "blue"
+
+ RotationAnimation on rotation {
+ duration: 3600
+ loops: Animation.Infinite
+ from: 0
+ to: 360
+ }
+
+ Timer {
+ interval: 300
+ repeat: true
+ running: true
+ property int prevHit: -1
+ property int prevRotation: -1
+ onTriggered: {
+ var date = new Date;
+ var millis = date.getMilliseconds()
+
+ if (prevHit < 0) {
+ prevHit = millis;
+ prevRotation = parent.rotation
+ return;
+ }
+
+ var milliDelta = millis - prevHit;
+ if (milliDelta <= 0)
+ milliDelta += 1000;
+ prevHit = millis;
+
+ var delta = parent.rotation - prevRotation;
+ if (delta < 0)
+ delta += 360
+ prevRotation = parent.rotation
+ console.log(milliDelta, delta, "ms/degrees ");
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/window.qml b/tests/auto/qml/debugger/qqmlpreview/data/window.qml
new file mode 100644
index 0000000000..f9f8d5aeb1
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/window.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QtQuick.Window 2.0
+
+Window {
+ visible: true
+
+ height: 100
+ width: 100
+
+ Timer {
+ repeat: false
+ interval: 1000
+ running: true
+ onTriggered: console.log("window.qml");
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/window1.qml b/tests/auto/qml/debugger/qqmlpreview/data/window1.qml
new file mode 100644
index 0000000000..e8e9ad706d
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/window1.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QtQuick.Window 2.3
+
+Window {
+ visible: true
+
+ height: 200
+ width: 100
+
+ Timer {
+ interval: 1000
+ running: true
+ onTriggered: console.log("window1.qml");
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/window2.qml b/tests/auto/qml/debugger/qqmlpreview/data/window2.qml
new file mode 100644
index 0000000000..9ad42d2ee2
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/window2.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QtQuick.Window 2.3
+
+Window {
+ visible: true
+
+ height: 100
+ width: 200
+
+ Timer {
+ interval: 1000
+ running: true
+ onTriggered: console.log("window2.qml");
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlpreview/data/zoom.qml b/tests/auto/qml/debugger/qqmlpreview/data/zoom.qml
new file mode 100644
index 0000000000..0aca235de1
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/data/zoom.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QtQuick.Window 2.2
+
+Window {
+ id: w
+ height: 100
+ width: 100
+ visible: true
+
+ Rectangle {
+ width: 50
+ height: 50
+ color: "blue"
+ anchors.centerIn: parent
+ }
+
+ Timer {
+ interval: 100
+ running: true
+ repeat: true
+ onTriggered: console.log("zoom", w.screen.devicePixelRatio)
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlpreview/qqmlpreview.pro b/tests/auto/qml/debugger/qqmlpreview/qqmlpreview.pro
new file mode 100644
index 0000000000..2c27306517
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/qqmlpreview.pro
@@ -0,0 +1,25 @@
+CONFIG += testcase
+TARGET = tst_qqmlpreview
+
+QT += qml testlib core qmldebug-private
+macos:CONFIG -= app_bundle
+
+INCLUDEPATH += ../../../../../src/plugins/qmltooling/qmldbg_preview/
+
+SOURCES += \
+ tst_qqmlpreview.cpp \
+ ../../../../../src/plugins/qmltooling/qmldbg_preview/qqmlpreviewblacklist.cpp
+
+HEADERS += \
+ ../../../../../src/plugins/qmltooling/qmldbg_preview/qqmlpreviewblacklist.h
+
+include(../shared/debugutil.pri)
+
+TESTDATA = \
+ data/window.qml \
+ data/qtquick2.qml \
+ data/window2.qml \
+ data/window1.qml \
+ data/broken.qml \
+ data/zoom.qml \
+ data/i18n/qml_fr_FR.qm
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
new file mode 100644
index 0000000000..4c4c514832
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "qqmldebugprocess_p.h"
+#include "debugutil_p.h"
+#include "qqmlpreviewblacklist.h"
+
+#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtNetwork/qhostaddress.h>
+
+#include <private/qqmldebugconnection_p.h>
+#include <private/qqmlpreviewclient_p.h>
+
+class tst_QQmlPreview : public QQmlDebugTest
+{
+ Q_OBJECT
+
+private:
+ ConnectResult startQmlProcess(const QString &qmlFile);
+ void serveRequest(const QString &path);
+ QList<QQmlDebugClient *> createClients() override;
+ void verifyProcessOutputContains(const QString &string) const;
+
+ QPointer<QQmlPreviewClient> m_client;
+
+ QStringList m_files;
+ QStringList m_filesNotFound;
+ QStringList m_directories;
+ QStringList m_serviceErrors;
+ QQmlPreviewClient::FpsInfo m_frameStats;
+
+private slots:
+ void cleanup() final;
+
+ void connect();
+ void load();
+ void rerun();
+ void blacklist();
+ void error();
+ void zoom();
+ void fps();
+ void language();
+};
+
+QQmlDebugTest::ConnectResult tst_QQmlPreview::startQmlProcess(const QString &qmlFile)
+{
+ return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
+ QStringLiteral("QmlPreview"), testFile(qmlFile), true);
+}
+
+void tst_QQmlPreview::serveRequest(const QString &path)
+{
+ QFileInfo info(path);
+
+ if (info.isDir()) {
+ m_directories.append(path);
+ m_client->sendDirectory(path, QDir(path).entryList());
+ } else {
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_files.append(path);
+ m_client->sendFile(path, file.readAll());
+ } else {
+ m_filesNotFound.append(path);
+ m_client->sendError(path);
+ }
+ }
+}
+
+QList<QQmlDebugClient *> tst_QQmlPreview::createClients()
+{
+ m_client = new QQmlPreviewClient(m_connection);
+
+ QObject::connect(m_client.data(), &QQmlPreviewClient::request, this, &tst_QQmlPreview::serveRequest);
+ QObject::connect(m_client.data(), &QQmlPreviewClient::error, this, [this](const QString &error) {
+ m_serviceErrors.append(error);
+ });
+ QObject::connect(m_client.data(), &QQmlPreviewClient::fps,
+ this, [this](const QQmlPreviewClient::FpsInfo &info) {
+ m_frameStats = info;
+ });
+
+ return QList<QQmlDebugClient *>({m_client});
+}
+
+void tst_QQmlPreview::verifyProcessOutputContains(const QString &string) const
+{
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(string), 30000);
+}
+
+void checkFiles(const QStringList &files)
+{
+ QVERIFY(!files.contains("/etc/localtime"));
+ QVERIFY(!files.contains("/etc/timezome"));
+ QVERIFY(!files.contains(":/qgradient/webgradients.binaryjson"));
+}
+
+void tst_QQmlPreview::cleanup()
+{
+ // Use a separate function so that we don't return early from cleanup() on failure.
+ checkFiles(m_files);
+
+ QQmlDebugTest::cleanup();
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Files loaded:" << m_files;
+ qDebug() << "Files not loaded:" << m_filesNotFound;
+ qDebug() << "Directories loaded:" << m_directories;
+ qDebug() << "Errors reported:" << m_serviceErrors;
+ }
+
+ m_directories.clear();
+ m_files.clear();
+ m_filesNotFound.clear();
+ m_serviceErrors.clear();
+ m_frameStats = QQmlPreviewClient::FpsInfo();
+}
+
+void tst_QQmlPreview::connect()
+{
+ const QString file("window.qml");
+ QCOMPARE(startQmlProcess(file), ConnectSuccess);
+ QVERIFY(m_client);
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+ m_client->triggerLoad(testFileUrl(file));
+ QTRY_VERIFY(m_files.contains(testFile(file)));
+ verifyProcessOutputContains(file);
+ m_process->stop();
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::NotConnected);
+ QVERIFY(m_serviceErrors.isEmpty());
+}
+
+void tst_QQmlPreview::load()
+{
+ const QString file("qtquick2.qml");
+ QCOMPARE(startQmlProcess(file), ConnectSuccess);
+ QVERIFY(m_client);
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+ m_client->triggerLoad(testFileUrl(file));
+ QTRY_VERIFY(m_files.contains(testFile(file)));
+ verifyProcessOutputContains("ms/degrees");
+
+ const QStringList files({"window2.qml", "window1.qml", "window.qml"});
+ for (const QString &newFile : files) {
+ m_client->triggerLoad(testFileUrl(newFile));
+ QTRY_VERIFY(m_files.contains(testFile(newFile)));
+ verifyProcessOutputContains(newFile);
+ }
+
+ m_process->stop();
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::NotConnected);
+ QVERIFY(m_serviceErrors.isEmpty());
+}
+
+void tst_QQmlPreview::rerun()
+{
+ const QString file("window.qml");
+ QCOMPARE(startQmlProcess(file), ConnectSuccess);
+ QVERIFY(m_client);
+ m_client->triggerLoad(testFileUrl(file));
+ const QLatin1String message("window.qml");
+ verifyProcessOutputContains(message);
+ const int pos = m_process->output().lastIndexOf(message) + message.size();
+ QVERIFY(pos >= 0);
+
+ m_client->triggerRerun();
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().indexOf(message, pos) >= pos, 30000);
+
+ m_process->stop();
+ QVERIFY(m_serviceErrors.isEmpty());
+}
+
+void tst_QQmlPreview::blacklist()
+{
+ QQmlPreviewBlacklist blacklist;
+
+ QStringList strings({
+ "lalala", "lulul", "trakdkd", "suppe", "zack"
+ });
+
+ for (const QString &string : strings)
+ QVERIFY(!blacklist.isBlacklisted(string));
+
+ for (const QString &string : strings)
+ blacklist.blacklist(string);
+
+ for (const QString &string : strings) {
+ QVERIFY(blacklist.isBlacklisted(string));
+ QVERIFY(!blacklist.isBlacklisted(string.left(string.size() / 2)));
+ QVERIFY(!blacklist.isBlacklisted(string + "45"));
+ QVERIFY(!blacklist.isBlacklisted(" " + string));
+ QVERIFY(blacklist.isBlacklisted(string + "/45"));
+ }
+
+ for (auto begin = strings.begin(), it = begin, end = strings.end(); it != end; ++it) {
+ std::rotate(begin, it, end);
+ QString path = "/" + strings.join('/');
+ blacklist.blacklist(path);
+ QVERIFY(blacklist.isBlacklisted(path));
+ QVERIFY(blacklist.isBlacklisted(path + "/file"));
+ QVERIFY(!blacklist.isBlacklisted(path + "more"));
+ path.chop(1);
+ QVERIFY(!blacklist.isBlacklisted(path));
+ std::reverse(begin, end);
+ }
+
+ blacklist.clear();
+ for (const QString &string : strings)
+ QVERIFY(!blacklist.isBlacklisted(string));
+
+ blacklist.blacklist(":/qt-project.org");
+ QVERIFY(blacklist.isBlacklisted(":/qt-project.org/QmlRuntime/conf/configuration.qml"));
+ QVERIFY(!blacklist.isBlacklisted(":/qt-project.orgQmlRuntime/conf/configuration.qml"));
+
+ QQmlPreviewBlacklist blacklist2;
+
+ blacklist2.blacklist(":/qt-project.org");
+ blacklist2.blacklist(":/QtQuick/Controls/Styles");
+ blacklist2.blacklist(":/ExtrasImports/QtQuick/Controls/Styles");
+ blacklist2.blacklist(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
+ blacklist2.blacklist("/home/ulf/.local/share/QtProject/Qml Runtime/configuration.qml");
+ blacklist2.blacklist("/usr/share");
+ blacklist2.blacklist("/usr/share/QtProject/Qml Runtime/configuration.qml");
+ QVERIFY(blacklist2.isBlacklisted(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)));
+ blacklist2.blacklist("/usr/local/share/QtProject/Qml Runtime/configuration.qml");
+ blacklist2.blacklist("qml");
+ blacklist2.blacklist(""); // This should not remove all other paths.
+
+ QVERIFY(blacklist2.isBlacklisted(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath) +
+ "/QtQuick/Window.2.0"));
+ QVERIFY(blacklist2.isBlacklisted(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)));
+ QVERIFY(blacklist2.isBlacklisted("/usr/share/QtProject/Qml Runtime/configuration.qml"));
+ QVERIFY(blacklist2.isBlacklisted("/usr/share/stuff"));
+ QVERIFY(blacklist2.isBlacklisted(""));
+
+ QQmlPreviewBlacklist blacklist3;
+ blacklist3.blacklist("/usr/share");
+ blacklist3.blacklist("/usr");
+ blacklist3.blacklist("/usrdings");
+ QVERIFY(blacklist3.isBlacklisted("/usrdings"));
+ QVERIFY(blacklist3.isBlacklisted("/usr/src"));
+ QVERIFY(!blacklist3.isBlacklisted("/opt/share"));
+ QVERIFY(!blacklist3.isBlacklisted("/opt"));
+
+ blacklist3.whitelist("/usr/share");
+ QVERIFY(blacklist3.isBlacklisted("/usrdings"));
+ QVERIFY(!blacklist3.isBlacklisted("/usr"));
+ QVERIFY(!blacklist3.isBlacklisted("/usr/share"));
+ QVERIFY(!blacklist3.isBlacklisted("/usr/src"));
+ QVERIFY(!blacklist3.isBlacklisted("/opt/share"));
+ QVERIFY(!blacklist3.isBlacklisted("/opt"));
+}
+
+void tst_QQmlPreview::error()
+{
+ QCOMPARE(startQmlProcess("window.qml"), ConnectSuccess);
+ QVERIFY(m_client);
+ m_client->triggerLoad(testFileUrl("broken.qml"));
+ QTRY_COMPARE_WITH_TIMEOUT(m_serviceErrors.count(), 1, 10000);
+ QVERIFY(m_serviceErrors.first().contains("broken.qml:32 Expected token `}'"));
+}
+
+static float parseZoomFactor(const QString &output)
+{
+ const QString prefix("zoom ");
+ const int start = output.lastIndexOf(prefix) + prefix.length();
+ if (start < 0)
+ return -1;
+ const int end = output.indexOf('\n', start);
+ if (end < 0)
+ return -1;
+ bool ok = false;
+ const float zoomFactor = output.mid(start, end - start).toFloat(&ok);
+ if (!ok)
+ return -1;
+ return zoomFactor;
+}
+
+static void verifyZoomFactor(const QQmlDebugProcess *process, float factor)
+{
+ QTRY_VERIFY_WITH_TIMEOUT(qFuzzyCompare(parseZoomFactor(process->output()), factor), 30000);
+}
+
+void tst_QQmlPreview::zoom()
+{
+ const QString file("zoom.qml");
+ QCOMPARE(startQmlProcess(file), ConnectSuccess);
+ QVERIFY(m_client);
+ m_client->triggerLoad(testFileUrl(file));
+ QTRY_VERIFY(m_files.contains(testFile(file)));
+ float baseZoomFactor = -1;
+ QTRY_VERIFY_WITH_TIMEOUT((baseZoomFactor = parseZoomFactor(m_process->output())) > 0, 30000);
+ m_client->triggerZoom(2.0f);
+ verifyZoomFactor(m_process, baseZoomFactor * 2.0f);
+ m_client->triggerZoom(1.5f);
+ verifyZoomFactor(m_process, baseZoomFactor * 1.5f);
+ m_client->triggerZoom(0.5f);
+ verifyZoomFactor(m_process, baseZoomFactor * 0.5f);
+ m_client->triggerZoom(-1.0f);
+ verifyZoomFactor(m_process, baseZoomFactor);
+ m_process->stop();
+ QVERIFY(m_serviceErrors.isEmpty());
+}
+
+void tst_QQmlPreview::fps()
+{
+ const QString file("qtquick2.qml");
+ QCOMPARE(startQmlProcess(file), ConnectSuccess);
+ QVERIFY(m_client);
+ m_client->triggerLoad(testFileUrl(file));
+ if (QGuiApplication::platformName() != "offscreen") {
+ QTRY_VERIFY(m_frameStats.numSyncs > 10);
+ QVERIFY(m_frameStats.minSync <= m_frameStats.maxSync);
+ QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs >= m_frameStats.minSync - 1);
+ QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs <= m_frameStats.maxSync);
+
+ QVERIFY(m_frameStats.numRenders > 0);
+ QVERIFY(m_frameStats.minRender <= m_frameStats.maxRender);
+ QVERIFY(m_frameStats.totalRender / m_frameStats.numRenders >= m_frameStats.minRender - 1);
+ QVERIFY(m_frameStats.totalRender / m_frameStats.numRenders <= m_frameStats.maxRender);
+ } else {
+ QSKIP("offscreen rendering doesn't produce any frames");
+ }
+}
+
+void tst_QQmlPreview::language()
+{
+ QCOMPARE(startQmlProcess("window.qml"), ConnectSuccess);
+ QVERIFY(m_client);
+ m_client->triggerLanguage(dataDirectoryUrl(), "fr_FR");
+ QTRY_VERIFY_WITH_TIMEOUT(m_files.contains(testFile("i18n/qml_fr_FR.qm")), 30000);
+}
+
+QTEST_MAIN(tst_QQmlPreview)
+
+#include "tst_qqmlpreview.moc"
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/batchOverflow.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/batchOverflow.qml
new file mode 100644
index 0000000000..dde1def947
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/batchOverflow.qml
@@ -0,0 +1,20 @@
+import QtQml 2.2
+
+QtObject {
+ function iterate(dictionaryTable, j) {
+ var word = "a" + j.toString()
+ dictionaryTable[word] = null;
+ }
+
+ Component.onCompleted: {
+ var dictionaryTable = {};
+ for (var j = 0; j < 256; ++j)
+ iterate(dictionaryTable, j);
+ }
+
+ property Timer timer: Timer {
+ interval: 1
+ running: true;
+ onTriggered: Qt.quit();
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml
index dd7cb2055d..4235a2d55f 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml
@@ -43,13 +43,6 @@ QtObject {
interval: 1000
onTriggered: {
console.profileEnd();
- endTimer.start();
}
}
-
- property var endTimer: Timer {
- id: endTimer
- interval: 1000
- onTriggered: Qt.quit();
- }
}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml
index 4236d70ea3..3b28e65174 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml
@@ -1,7 +1,7 @@
import QtQml 2.0
QtObject {
- Timer {
+ property Timer timer: Timer {
running: true
interval: 1
onTriggered: Qt.quit();
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml
new file mode 100644
index 0000000000..f39dcdf16a
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/memory.qml
@@ -0,0 +1,17 @@
+import QtQml 2.0
+
+Timer {
+ interval: 1
+ running: true
+
+ function recurse(i) {
+ var x = { t: [1, 2, 3, 4] }
+ console.log(x.t[i]);
+ if (i < 3)
+ recurse(i + 1);
+ else
+ Qt.quit();
+ }
+
+ onTriggered: recurse(0)
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml
new file mode 100644
index 0000000000..09dcd34b5c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+Timer {
+ property string stuff: qsTr("foo")
+
+ running: true
+ interval: 1
+ onTriggered: Qt.quit();
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/quit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/quit.qml
new file mode 100644
index 0000000000..bc8c2b90ae
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/quit.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** 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
+
+//DO NOT CHANGE
+
+Item {
+ Timer {
+ running: true
+ triggeredOnStart: true
+ onTriggered: Qt.quit();
+ }
+}
+
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
index 71a58d6f34..0cd4b331f2 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
@@ -4,13 +4,11 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qqmlprofilerservice.cpp
-INCLUDEPATH += ../shared
-include(../../../shared/util.pri)
include(../shared/debugutil.pri)
TESTDATA = data/*
-QT += core qml testlib gui-private core-private
+QT += testlib gui-private
OTHER_FILES += \
data/pixmapCacheTest.qml \
@@ -21,4 +19,7 @@ OTHER_FILES += \
data/TestImage_2x2.png \
data/signalSourceLocation.qml \
data/javascript.qml \
- data/timer.qml
+ data/timer.qml \
+ data/qstr.qml \
+ data/memory.qml \
+ data/batchOverflow.qml
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 692e70d7da..085eb7b87a 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -27,254 +27,160 @@
****************************************************************************/
#include "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
#include "../../../shared/util.h"
#include <private/qqmlprofilerclient_p.h>
#include <private/qqmldebugconnection_p.h>
#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
#include <QtCore/qlibraryinfo.h>
-#define STR_PORT_FROM "13773"
-#define STR_PORT_TO "13783"
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
-struct QQmlProfilerData
-{
- QQmlProfilerData(qint64 time = -2, int messageType = -1, int detailType = -1,
- const QString &detailData = QString()) :
- time(time), messageType(messageType), detailType(detailType), detailData(detailData),
- line(-1), column(-1), framerate(-1), animationcount(-1), amount(-1)
- {}
-
- qint64 time;
- int messageType;
- int detailType;
-
- //###
- QString detailData; //used by RangeData and RangeLocation
- int line; //used by RangeLocation
- int column; //used by RangeLocation
- int framerate; //used by animation events
- int animationcount; //used by animation events
- qint64 amount; //used by heap events
-};
-
-class QQmlProfilerTestClient : public QQmlProfilerClient
+class QQmlProfilerTestClient : public QQmlProfilerEventReceiver
{
Q_OBJECT
public:
- QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection),
- lastTimestamp(-1) {}
+ QQmlProfilerTestClient(QQmlDebugConnection *connection) :
+ client(new QQmlProfilerClient(connection, this))
+ {
+ connect(client.data(), &QQmlProfilerClient::traceStarted,
+ this, &QQmlProfilerTestClient::startTrace);
+ connect(client.data(), &QQmlProfilerClient::traceFinished,
+ this, &QQmlProfilerTestClient::endTrace);
+ }
+
+ void startTrace(qint64 timestamp, const QList<int> &engineIds);
+ void endTrace(qint64 timestamp, const QList<int> &engineIds);
- QVector<QQmlProfilerData> qmlMessages;
- QVector<QQmlProfilerData> javascriptMessages;
- QVector<QQmlProfilerData> jsHeapMessages;
- QVector<QQmlProfilerData> asynchronousMessages;
- QVector<QQmlProfilerData> pixmapMessages;
+ QPointer<QQmlProfilerClient> client; // Owned by QQmlDebugTest
+ QVector<QQmlProfilerEventType> types;
- qint64 lastTimestamp;
+ QVector<QQmlProfilerEvent> qmlMessages;
+ QVector<QQmlProfilerEvent> javascriptMessages;
+ QVector<QQmlProfilerEvent> jsHeapMessages;
+ QVector<QQmlProfilerEvent> asynchronousMessages;
+ QVector<QQmlProfilerEvent> pixmapMessages;
-signals:
- void recordingFinished();
+ int numLoadedEventTypes() const override;
+ void addEventType(const QQmlProfilerEventType &type) override;
+ void addEvent(const QQmlProfilerEvent &event) override;
private:
- void traceStarted(qint64 time, int engineId);
- void traceFinished(qint64 time, int engineId);
- void rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime);
- void rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, const QString &data);
- void rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time,
- const QQmlEventLocation &location);
- void rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime);
- void animationFrame(qint64 time, int frameRate, int animationCount, int threadId);
- void sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, qint64 time,
- qint64 numericData1, qint64 numericData2, qint64 numericData3,
- qint64 numericData4, qint64 numericData5);
- void pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, qint64 time,
- const QString &url, int numericData1, int numericData2);
- void memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 amount);
- void inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b);
- void complete();
-
- void unknownEvent(QQmlProfilerDefinitions::Message messageType, qint64 time, int detailType);
- void unknownData(QPacket &stream);
+ qint64 lastTimestamp = -1;
};
-void QQmlProfilerTestClient::traceStarted(qint64 time, int engineId)
+void QQmlProfilerTestClient::startTrace(qint64 timestamp, const QList<int> &engineIds)
{
- asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event,
- QQmlProfilerDefinitions::StartTrace,
- QString::number(engineId)));
+ types.append(QQmlProfilerEventType(Event, MaximumRangeType, StartTrace));
+ asynchronousMessages.append(QQmlProfilerEvent(timestamp, types.length() - 1,
+ engineIds.toVector()));
}
-void QQmlProfilerTestClient::traceFinished(qint64 time, int engineId)
+void QQmlProfilerTestClient::endTrace(qint64 timestamp, const QList<int> &engineIds)
{
- asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event,
- QQmlProfilerDefinitions::EndTrace,
- QString::number(engineId)));
+ types.append(QQmlProfilerEventType(Event, MaximumRangeType, EndTrace));
+ asynchronousMessages.append(QQmlProfilerEvent(timestamp, types.length() - 1,
+ engineIds.toVector()));
}
-void QQmlProfilerTestClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime)
+int QQmlProfilerTestClient::numLoadedEventTypes() const
{
- QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
- QVERIFY(lastTimestamp <= startTime);
- lastTimestamp = startTime;
- QQmlProfilerData data(startTime, QQmlProfilerDefinitions::RangeStart, type);
- if (type == QQmlProfilerDefinitions::Javascript)
- javascriptMessages.append(data);
- else
- qmlMessages.append(data);
+ return types.length();
}
-void QQmlProfilerTestClient::rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time,
- const QString &string)
+void QQmlProfilerTestClient::addEventType(const QQmlProfilerEventType &type)
{
- QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeData, type, string);
- if (type == QQmlProfilerDefinitions::Javascript)
- javascriptMessages.append(data);
- else
- qmlMessages.append(data);
+ types.append(type);
}
-void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time,
- const QQmlEventLocation &location)
+void QQmlProfilerTestClient::addEvent(const QQmlProfilerEvent &event)
{
- QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
- QVERIFY(location.line >= -2);
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeLocation, type, location.filename);
- data.line = location.line;
- data.column = location.column;
- if (type == QQmlProfilerDefinitions::Javascript)
- javascriptMessages.append(data);
- else
- qmlMessages.append(data);
-}
+ const int typeIndex = event.typeIndex();
+ QVERIFY(typeIndex < types.length());
-void QQmlProfilerTestClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime)
-{
- QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType);
- QVERIFY(lastTimestamp <= endTime);
- lastTimestamp = endTime;
- QQmlProfilerData data(endTime, QQmlProfilerDefinitions::RangeEnd, type);
- if (type == QQmlProfilerDefinitions::Javascript)
- javascriptMessages.append(data);
- else
- qmlMessages.append(data);
-}
+ const QQmlProfilerEventType &type = types[typeIndex];
-void QQmlProfilerTestClient::animationFrame(qint64 time, int frameRate, int animationCount, int threadId)
-{
- QVERIFY(threadId >= 0);
- QVERIFY(frameRate != -1);
- QVERIFY(animationCount != -1);
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- QQmlProfilerData data(time, QQmlProfilerDefinitions::Event,
- QQmlProfilerDefinitions::AnimationFrame);
- data.framerate = frameRate;
- data.animationcount = animationCount;
- asynchronousMessages.append(data);
-}
+ QVERIFY(event.timestamp() >= lastTimestamp);
+ lastTimestamp = event.timestamp();
-void QQmlProfilerTestClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type,
- qint64 time, qint64 numericData1, qint64 numericData2,
- qint64 numericData3, qint64 numericData4,
- qint64 numericData5)
-{
- Q_UNUSED(numericData1);
- Q_UNUSED(numericData2);
- Q_UNUSED(numericData3);
- Q_UNUSED(numericData4);
- Q_UNUSED(numericData5);
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::SceneGraphFrame,
- type));
-}
-
-void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type,
- qint64 time, const QString &url, int numericData1,
- int numericData2)
-{
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- QQmlProfilerData data(time, QQmlProfilerDefinitions::PixmapCacheEvent, type, url);
- switch (type) {
- case QQmlProfilerDefinitions::PixmapSizeKnown:
- data.line = numericData1;
- data.column = numericData2;
+ switch (type.message()) {
+ case Event: {
+ switch (type.detailType()) {
+ case StartTrace:
+ QFAIL("StartTrace should not be passed on as event");
+ break;
+ case EndTrace:
+ QFAIL("EndTrace should not be passed on as event");
+ break;
+ case AnimationFrame:
+ asynchronousMessages.append(event);
+ break;
+ case Mouse:
+ case Key:
+ qmlMessages.append(event);
+ break;
+ default:
+ QFAIL(qPrintable(QString::fromLatin1("Event with unknown detailType %1 received at %2.")
+ .arg(type.detailType()).arg(event.timestamp())));
+ break;
+ }
+ break;
+ }
+ case RangeStart:
+ case RangeData:
+ case RangeLocation:
+ case RangeEnd:
+ QFAIL("Range stages are transmitted as part of events");
+ break;
+ case Complete:
+ QFAIL("Complete should not be passed on as event");
+ break;
+ case PixmapCacheEvent:
+ pixmapMessages.append(event);
break;
- case QQmlProfilerDefinitions::PixmapReferenceCountChanged:
- case QQmlProfilerDefinitions::PixmapCacheCountChanged:
- data.animationcount = numericData1;
+ case SceneGraphFrame:
+ asynchronousMessages.append(event);
break;
- default:
+ case MemoryAllocation:
+ jsHeapMessages.append(event);
+ break;
+ case DebugMessage:
+ // Unhandled
+ break;
+ case MaximumMessage:
+ switch (type.rangeType()) {
+ case Painting:
+ QFAIL("QtQuick1 paint message received.");
+ break;
+ case Compiling:
+ case Creating:
+ case Binding:
+ case HandlingSignal:
+ qmlMessages.append(event);
+ break;
+ case Javascript:
+ javascriptMessages.append(event);
+ break;
+ default:
+ QFAIL(qPrintable(
+ QString::fromLatin1("Unknown range event %1 received at %2.")
+ .arg(type.rangeType()).arg(event.timestamp())));
+ break;
+ }
break;
}
- pixmapMessages.append(data);
-}
-
-void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time,
- qint64 amount)
-{
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- QQmlProfilerData data(time, QQmlProfilerDefinitions::MemoryAllocation, type);
- data.amount = amount;
- jsHeapMessages.append(data);
}
-void QQmlProfilerTestClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time,
- int a, int b)
-{
- QVERIFY(lastTimestamp <= time);
- lastTimestamp = time;
- qmlMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, type,
- QString::number(a) + QLatin1Char('x') +
- QString::number(b)));
-}
-
-void QQmlProfilerTestClient::unknownEvent(QQmlProfilerDefinitions::Message messageType, qint64 time,
- int detailType)
-{
- QFAIL(qPrintable(QString::fromLatin1("Unknown event %1 with detail type %2 received at %3.")
- .arg(messageType).arg(detailType).arg(time)));
-}
-
-void QQmlProfilerTestClient::unknownData(QPacket &stream)
-{
- QFAIL(qPrintable(QString::fromLatin1("%1 bytes of extra data after receiving message.")
- .arg(stream.device()->bytesAvailable())));
-}
-
-void QQmlProfilerTestClient::complete()
-{
- emit recordingFinished();
-}
-
-class tst_QQmlProfilerService : public QQmlDataTest
+class tst_QQmlProfilerService : public QQmlDebugTest
{
Q_OBJECT
-public:
- tst_QQmlProfilerService()
- : m_process(0)
- , m_connection(0)
- , m_client(0)
- {
- }
-
-
private:
- QQmlDebugProcess *m_process;
- QQmlDebugConnection *m_connection;
- QQmlProfilerTestClient *m_client;
-
enum MessageListType {
MessageListQML,
MessageListJavaScript,
@@ -289,18 +195,28 @@ private:
CheckLine = 1 << 2,
CheckColumn = 1 << 3,
CheckDataEndsWith = 1 << 4,
+ CheckFileEndsWith = 1 << 5,
+ CheckNumbers = 1 << 6,
- CheckAll = CheckMessageType | CheckDetailType | CheckLine | CheckColumn | CheckDataEndsWith
+ CheckType = CheckMessageType | CheckDetailType | CheckLine | CheckColumn | CheckFileEndsWith
};
- void connect(bool block, const QString &testFile, bool restrictServices = true);
+ ConnectResult connect(bool block, const QString &file, bool recordFromStart = true,
+ uint flushInterval = 0, bool restrictServices = true,
+ const QString &executable
+ = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene");
+ void checkProcessTerminated();
void checkTraceReceived();
void checkJsHeap();
- bool verify(MessageListType type, int expectedPosition, const QQmlProfilerData &expected,
- quint32 checks);
+ bool verify(MessageListType type, int expectedPosition,
+ const QQmlProfilerEventType &expected, quint32 checks,
+ const QVector<qint64> &expectedNumbers);
+
+ QList<QQmlDebugClient *> createClients() override;
+ QScopedPointer<QQmlProfilerTestClient> m_client;
private slots:
- void cleanup();
+ void cleanup() override;
void connect_data();
void connect();
@@ -311,58 +227,75 @@ private slots:
void signalSourceLocation();
void javascript();
void flushInterval();
+ void translationBinding();
+ void memory();
+ void compile();
+ void multiEngine();
+ void batchOverflow();
+
+private:
+ bool m_recordFromStart = true;
+ bool m_flushInterval = false;
+ bool m_isComplete = false;
+
+ // Don't use ({...}) here as MSVC will interpret that as the "QVector(int size)" ctor.
+ const QVector<qint64> m_rangeStart = (QVector<qint64>() << RangeStart);
+ const QVector<qint64> m_rangeEnd = (QVector<qint64>() << RangeEnd);
};
-#define VERIFY(type, position, expected, checks) QVERIFY(verify(type, position, expected, checks))
+#define VERIFY(type, position, expected, checks, numbers) \
+ QVERIFY(verify(type, position, expected, checks, numbers))
-void tst_QQmlProfilerService::connect(bool block, const QString &testFile, bool restrictServices)
+QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connect(
+ bool block, const QString &file, bool recordFromStart, uint flushInterval,
+ bool restrictServices, const QString &executable)
{
+ m_recordFromStart = recordFromStart;
+ m_flushInterval = flushInterval;
+ m_isComplete = false;
+
// ### Still using qmlscene due to QTBUG-33377
- const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene";
- QStringList arguments;
- arguments << QString::fromLatin1("-qmljsdebugger=port:%1,%2%3%4")
- .arg(STR_PORT_FROM).arg(STR_PORT_TO)
- .arg(block ? QStringLiteral(",block") : QString())
- .arg(restrictServices ? QStringLiteral(",services:CanvasFrameRate") : QString())
- << QQmlDataTest::instance()->testFile(testFile);
-
- m_process = new QQmlDebugProcess(executable, this);
- m_process->start(QStringList() << arguments);
- QVERIFY2(m_process->waitForSessionStart(), "Could not launch application, or did not get 'Waiting for connection'.");
-
- m_connection = new QQmlDebugConnection();
- m_client = new QQmlProfilerTestClient(m_connection);
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection);
-
- const int port = m_process->debugPort();
- m_connection->connectToHost(QLatin1String("127.0.0.1"), port);
- QVERIFY(m_client);
- QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+ return QQmlDebugTest::connect(
+ executable,
+ restrictServices ? "CanvasFrameRate,EngineControl,DebugMessages" : QString(),
+ testFile(file), block);
+}
- foreach (QQmlDebugClient *other, others)
- QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
+void tst_QQmlProfilerService::checkProcessTerminated()
+{
+ // If the process ends before connect(), we get a non-success value from connect()
+ // That's not a problem as we will still receive the trace. We check that process has terminated
+ // cleanly here.
+
+ // Wait for the process to finish by itself, if that hasn't happened already
+ QVERIFY(m_client);
+ QVERIFY(m_client->client);
+ QTRY_COMPARE(m_client->client->state(), QQmlDebugClient::NotConnected);
+ QVERIFY(m_process);
+ QVERIFY(m_process->exitStatus() != QProcess::CrashExit);
+ QTRY_COMPARE(m_process->exitStatus(), QProcess::NormalExit);
}
void tst_QQmlProfilerService::checkTraceReceived()
{
- QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(recordingFinished())),
- "No trace received in time.");
+ QVERIFY(m_process->exitStatus() != QProcess::CrashExit);
+ QTRY_VERIFY2(m_isComplete, "No trace received in time.");
+
+ QVector<qint64> numbers;
// must start with "StartTrace"
- QQmlProfilerData expected(0, QQmlProfilerDefinitions::Event,
- QQmlProfilerDefinitions::StartTrace);
- VERIFY(MessageListAsynchronous, 0, expected, CheckMessageType | CheckDetailType);
+ QQmlProfilerEventType expected(Event, MaximumRangeType, StartTrace);
+ VERIFY(MessageListAsynchronous, 0, expected, CheckMessageType | CheckDetailType, numbers);
// must end with "EndTrace"
- expected.detailType = QQmlProfilerDefinitions::EndTrace;
+ expected = QQmlProfilerEventType(Event, MaximumRangeType, EndTrace);
VERIFY(MessageListAsynchronous, m_client->asynchronousMessages.length() - 1, expected,
- CheckMessageType | CheckDetailType);
+ CheckMessageType | CheckDetailType, numbers);
}
void tst_QQmlProfilerService::checkJsHeap()
{
+ QVERIFY(m_client);
QVERIFY2(m_client->jsHeapMessages.count() > 0, "no JavaScript heap messages received");
bool seen_alloc = false;
@@ -371,33 +304,36 @@ void tst_QQmlProfilerService::checkJsHeap()
qint64 allocated = 0;
qint64 used = 0;
qint64 lastTimestamp = -1;
- foreach (const QQmlProfilerData &message, m_client->jsHeapMessages) {
- switch (message.detailType) {
- case QV4::Profiling::HeapPage:
- allocated += message.amount;
+ foreach (const QQmlProfilerEvent &message, m_client->jsHeapMessages) {
+ const auto amount = message.number<qint64>(0);
+ const QQmlProfilerEventType &type = m_client->types.at(message.typeIndex());
+ switch (type.detailType()) {
+ case HeapPage:
+ allocated += amount;
seen_alloc = true;
break;
- case QV4::Profiling::SmallItem:
- used += message.amount;
+ case SmallItem:
+ used += amount;
seen_small = true;
break;
- case QV4::Profiling::LargeItem:
- allocated += message.amount;
- used += message.amount;
+ case LargeItem:
+ allocated += amount;
+ used += amount;
seen_large = true;
break;
}
- QVERIFY(message.time >= lastTimestamp);
+ QVERIFY(message.timestamp() >= lastTimestamp);
// The heap will only be consistent after all events of the same timestamp are processed.
if (lastTimestamp == -1) {
- lastTimestamp = message.time;
- continue;
- } else if (message.time == lastTimestamp) {
+ lastTimestamp = message.timestamp();
continue;
}
- lastTimestamp = message.time;
+ if (message.timestamp() == lastTimestamp)
+ continue;
+
+ lastTimestamp = message.timestamp();
QVERIFY2(used >= 0, QString::fromLatin1("Negative memory usage seen: %1")
.arg(used).toUtf8().constData());
@@ -416,10 +352,15 @@ void tst_QQmlProfilerService::checkJsHeap()
}
bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType type,
- int expectedPosition, const QQmlProfilerData &expected,
- quint32 checks)
+ int expectedPosition, const QQmlProfilerEventType &expected,
+ quint32 checks, const QVector<qint64> &expectedNumbers)
{
- QVector<QQmlProfilerData> *target = 0;
+ if (!m_client) {
+ qWarning() << "No debug client available";
+ return false;
+ }
+
+ const QVector<QQmlProfilerEvent> *target = nullptr;
switch (type) {
case MessageListQML: target = &(m_client->qmlMessages); break;
case MessageListJavaScript: target = &(m_client->javascriptMessages); break;
@@ -428,48 +369,93 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty
case MessageListPixmap: target = &(m_client->pixmapMessages); break;
}
+ if (!target) {
+ qWarning() << "Invalid MessageListType" << type;
+ return false;
+ }
+
if (target->length() <= expectedPosition) {
qWarning() << "Not enough events. expected position:" << expectedPosition
<< "length:" << target->length();
return false;
}
- uint position = expectedPosition;
- qint64 timestamp = target->at(expectedPosition).time;
- while (position > 0 && target->at(position - 1).time == timestamp)
+ int position = expectedPosition;
+ qint64 timestamp = target->at(expectedPosition).timestamp();
+ while (position > 0 && target->at(position - 1).timestamp() == timestamp)
--position;
QStringList warnings;
do {
- const QQmlProfilerData &actual = target->at(position);
- if ((checks & CheckMessageType) && actual.messageType != expected.messageType) {
- warnings << QString::fromLatin1("%1: unexpected messageType. actual: %2 - expected: %3")
- .arg(position).arg(actual.messageType).arg(expected.messageType);
+ const QQmlProfilerEvent &event = target->at(position);
+ const QQmlProfilerEventType &actual = m_client->types.at(event.typeIndex());
+ if ((checks & CheckMessageType) &&
+ (actual.message() != expected.message()
+ || actual.rangeType() != expected.rangeType())) {
+ warnings << QString::fromLatin1("%1: unexpected messageType or rangeType. "
+ "actual: %2, %3 - expected: %4, %5")
+ .arg(position).arg(actual.message()).arg(actual.rangeType())
+ .arg(expected.message()).arg(expected.rangeType());
continue;
}
- if ((checks & CheckDetailType) && actual.detailType != expected.detailType) {
+ if ((checks & CheckDetailType) && actual.detailType() != expected.detailType()) {
warnings << QString::fromLatin1("%1: unexpected detailType. actual: %2 - expected: %3")
- .arg(position).arg(actual.detailType).arg(expected.detailType);
+ .arg(position).arg(actual.detailType()).arg(expected.detailType());
continue;
}
- if ((checks & CheckLine) && actual.line != expected.line) {
+
+ const QQmlProfilerEventLocation expectedLocation = expected.location();
+ const QQmlProfilerEventLocation actualLocation = actual.location();
+
+ if ((checks & CheckLine) && actualLocation.line() != expectedLocation.line()) {
warnings << QString::fromLatin1("%1: unexpected line. actual: %2 - expected: %3")
- .arg(position).arg(actual.line).arg(expected.line);
+ .arg(position).arg(actualLocation.line())
+ .arg(expectedLocation.line());
continue;
}
- if ((checks & CheckColumn) && actual.column != expected.column) {
+ if ((checks & CheckColumn) && actualLocation.column() != expectedLocation.column()) {
warnings << QString::fromLatin1("%1: unexpected column. actual: %2 - expected: %3")
- .arg(position).arg(actual.column).arg(expected.column);
+ .arg(position).arg(actualLocation.column())
+ .arg(expectedLocation.column());
continue;
}
- if ((checks & CheckDataEndsWith) && !actual.detailData.endsWith(expected.detailData)) {
+ if ((checks & CheckFileEndsWith) &&
+ !actualLocation.filename().endsWith(expectedLocation.filename())) {
+ warnings << QString::fromLatin1("%1: unexpected fileName. actual: %2 - expected: %3")
+ .arg(position).arg(actualLocation.filename())
+ .arg(expectedLocation.filename());
+ continue;
+ }
+
+ if ((checks & CheckDataEndsWith) && !actual.data().endsWith(expected.data())) {
warnings << QString::fromLatin1("%1: unexpected detailData. actual: %2 - expected: %3")
- .arg(position).arg(actual.detailData).arg(expected.detailData);
+ .arg(position).arg(actual.data()).arg(expected.data());
continue;
}
+
+ if (checks & CheckNumbers) {
+ const QVector<qint64> actualNumbers = event.numbers<QVector<qint64>>();
+ if (actualNumbers != expectedNumbers) {
+
+ QStringList expectedList;
+ for (qint64 number : expectedNumbers)
+ expectedList.append(QString::number(number));
+ QStringList actualList;
+ for (qint64 number : actualNumbers)
+ actualList.append(QString::number(number));
+
+ warnings << QString::fromLatin1(
+ "%1: unexpected numbers. actual [%2] - expected: [%3]")
+ .arg(position)
+ .arg(actualList.join(QLatin1String(", ")))
+ .arg(expectedList.join(QLatin1String(", ")));
+ continue;
+ }
+ }
+
return true;
- } while (target->at(++position).time == timestamp);
+ } while (++position < target->length() && target->at(position).timestamp() == timestamp);
foreach (const QString &message, warnings)
qWarning() << message.toLocal8Bit().constData();
@@ -477,54 +463,62 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty
return false;
}
+QList<QQmlDebugClient *> tst_QQmlProfilerService::createClients()
+{
+ m_client.reset(new QQmlProfilerTestClient(m_connection));
+ m_client->client->setRecording(m_recordFromStart);
+ m_client->client->setFlushInterval(m_flushInterval);
+ QObject::connect(m_client->client.data(), &QQmlProfilerClient::complete,
+ this, [this](){ m_isComplete = true; });
+ return QList<QQmlDebugClient *>({m_client->client});
+}
+
void tst_QQmlProfilerService::cleanup()
{
+ auto log = [this](const QQmlProfilerEvent &data, int i) {
+ const QQmlProfilerEventType &type = m_client->types.at(data.typeIndex());
+ const QQmlProfilerEventLocation location = type.location();
+ qDebug() << i << data.timestamp() << type.message() << type.rangeType() << type.detailType()
+ << location.filename() << location.line() << location.column()
+ << data.numbers<QVector<qint64>>();
+ };
+
if (m_client && QTest::currentTestFailed()) {
qDebug() << "QML Messages:" << m_client->qmlMessages.count();
int i = 0;
- foreach (const QQmlProfilerData &data, m_client->qmlMessages) {
- qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData
- << data.line << data.column;
- }
+ for (const QQmlProfilerEvent &data : qAsConst(m_client->qmlMessages))
+ log(data, i++);
+
qDebug() << " ";
qDebug() << "JavaScript Messages:" << m_client->javascriptMessages.count();
i = 0;
- foreach (const QQmlProfilerData &data, m_client->javascriptMessages) {
- qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData
- << data.line << data.column;
- }
+
+ for (const QQmlProfilerEvent &data : qAsConst(m_client->javascriptMessages))
+ log(data, i++);
+
qDebug() << " ";
qDebug() << "Asynchronous Messages:" << m_client->asynchronousMessages.count();
i = 0;
- foreach (const QQmlProfilerData &data, m_client->asynchronousMessages) {
- qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData
- << data.framerate << data.animationcount << data.line << data.column;
- }
+ for (const QQmlProfilerEvent &data : qAsConst(m_client->asynchronousMessages))
+ log(data, i++);
+
qDebug() << " ";
qDebug() << "Pixmap Cache Messages:" << m_client->pixmapMessages.count();
i = 0;
- foreach (const QQmlProfilerData &data, m_client->pixmapMessages) {
- qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData
- << data.line << data.column;
- }
+ for (const QQmlProfilerEvent &data : qAsConst(m_client->pixmapMessages))
+ log(data, i++);
+
qDebug() << " ";
qDebug() << "Javascript Heap Messages:" << m_client->jsHeapMessages.count();
i = 0;
- foreach (const QQmlProfilerData &data, m_client->jsHeapMessages) {
- qDebug() << i++ << data.time << data.messageType << data.detailType;
- }
+ for (const QQmlProfilerEvent &data : qAsConst(m_client->jsHeapMessages))
+ log(data, i++);
+
qDebug() << " ";
- qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null"));
- qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null"));
- qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection);
- qDebug() << "Client State:" << QQmlDebugTest::clientStateString(m_client);
}
- delete m_process;
- m_process = 0;
- delete m_client;
- m_client = 0;
- delete m_connection;
- m_connection = 0;
+
+ m_client.reset();
+ QQmlDebugTest::cleanup();
}
void tst_QQmlProfilerService::connect_data()
@@ -548,63 +542,63 @@ void tst_QQmlProfilerService::connect()
QFETCH(bool, restrictMode);
QFETCH(bool, traceEnabled);
- connect(blockMode, "test.qml", restrictMode);
+ QCOMPARE(connect(blockMode, "test.qml", traceEnabled, 0, restrictMode), ConnectSuccess);
- // if the engine is waiting, then the first message determines if it starts with trace enabled
if (!traceEnabled)
- m_client->sendRecordingStatus(false);
- m_client->sendRecordingStatus(true);
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(true);
+
+ QTRY_VERIFY(m_client->numLoadedEventTypes() > 0);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
}
void tst_QQmlProfilerService::pixmapCacheData()
{
- connect(true, "pixmapCacheTest.qml");
- m_client->sendRecordingStatus(true);
- QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
+ QCOMPARE(connect(true, "pixmapCacheTest.qml"), ConnectSuccess);
+ // Don't wait for readyReadStandardOutput before the loop. It may have already arrived.
while (m_process->output().indexOf(QLatin1String("image loaded")) == -1 &&
m_process->output().indexOf(QLatin1String("image error")) == -1)
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
- QQmlProfilerData expected(0, QQmlProfilerDefinitions::PixmapCacheEvent);
+ auto createType = [](PixmapEventType type) {
+ return QQmlProfilerEventType(PixmapCacheEvent, MaximumRangeType, type);
+ };
+
+ QVector<qint64> numbers;
// image starting to load
- expected.detailType = QQmlProfilerDefinitions::PixmapLoadingStarted;
- VERIFY(MessageListPixmap, 0, expected, CheckMessageType | CheckDetailType);
+ VERIFY(MessageListPixmap, 0, createType(PixmapLoadingStarted),
+ CheckMessageType | CheckDetailType, numbers);
// image size
- expected.detailType = QQmlProfilerDefinitions::PixmapSizeKnown;
- expected.line = expected.column = 2; // width and height, in fact
- VERIFY(MessageListPixmap, 1, expected,
- CheckMessageType | CheckDetailType | CheckLine | CheckColumn);
+ numbers = QVector<qint64>({2, 2, 1});
+ VERIFY(MessageListPixmap, 1, createType(PixmapSizeKnown),
+ CheckMessageType | CheckDetailType | CheckNumbers, numbers);
// image loaded
- expected.detailType = QQmlProfilerDefinitions::PixmapLoadingFinished;
- VERIFY(MessageListPixmap, 2, expected, CheckMessageType | CheckDetailType);
+ VERIFY(MessageListPixmap, 2, createType(PixmapLoadingFinished),
+ CheckMessageType | CheckDetailType, numbers);
// cache size
- expected.detailType = QQmlProfilerDefinitions::PixmapCacheCountChanged;
- VERIFY(MessageListPixmap, 3, expected, CheckMessageType | CheckDetailType);
+ VERIFY(MessageListPixmap, 3, createType(PixmapCacheCountChanged),
+ CheckMessageType | CheckDetailType, numbers);
}
void tst_QQmlProfilerService::scenegraphData()
{
- connect(true, "scenegraphTest.qml");
-
- m_client->sendRecordingStatus(true);
+ QCOMPARE(connect(true, "scenegraphTest.qml"), ConnectSuccess);
while (!m_process->output().contains(QLatin1String("tick")))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
@@ -619,34 +613,39 @@ void tst_QQmlProfilerService::scenegraphData()
qint64 contextFrameTime = -1;
qint64 renderFrameTime = -1;
#if QT_CONFIG(opengl) //Software renderer doesn't have context frames
- foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) {
- if (msg.messageType == QQmlProfilerDefinitions::SceneGraphFrame) {
- if (msg.detailType == QQmlProfilerDefinitions::SceneGraphContextFrame) {
- contextFrameTime = msg.time;
- break;
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
+ foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) {
+ const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex());
+ if (type.message() == SceneGraphFrame) {
+ if (type.detailType() == SceneGraphContextFrame) {
+ contextFrameTime = msg.timestamp();
+ break;
+ }
}
}
- }
- QVERIFY(contextFrameTime != -1);
+ QVERIFY(contextFrameTime != -1);
+ }
#endif
- foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) {
- if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRendererFrame) {
- QVERIFY(msg.time >= contextFrameTime);
- renderFrameTime = msg.time;
+ foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) {
+ const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex());
+ if (type.detailType() == SceneGraphRendererFrame) {
+ QVERIFY(msg.timestamp() >= contextFrameTime);
+ renderFrameTime = msg.timestamp();
break;
}
}
QVERIFY(renderFrameTime != -1);
- foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) {
- if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) {
- if (msg.time >= contextFrameTime) {
+ foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) {
+ const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex());
+ if (type.detailType() == SceneGraphRenderLoopFrame) {
+ if (msg.timestamp() >= contextFrameTime) {
// Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and
// SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is
// OK as the scene graph might decide to do an initial rendering.
- QVERIFY(msg.time >= renderFrameTime);
+ QVERIFY(msg.timestamp() >= renderFrameTime);
break;
}
}
@@ -655,9 +654,8 @@ void tst_QQmlProfilerService::scenegraphData()
void tst_QQmlProfilerService::profileOnExit()
{
- connect(true, "exit.qml");
-
- m_client->sendRecordingStatus(true);
+ QCOMPARE(connect(true, "exit.qml"), ConnectSuccess);
+ checkProcessTerminated();
checkTraceReceived();
checkJsHeap();
@@ -665,78 +663,182 @@ void tst_QQmlProfilerService::profileOnExit()
void tst_QQmlProfilerService::controlFromJS()
{
- connect(true, "controlFromJS.qml");
+ QCOMPARE(connect(true, "controlFromJS.qml", false), ConnectSuccess);
- m_client->sendRecordingStatus(false);
+ QTRY_VERIFY(m_client->numLoadedEventTypes() > 0);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
}
void tst_QQmlProfilerService::signalSourceLocation()
{
- connect(true, "signalSourceLocation.qml");
+ QCOMPARE(connect(true, "signalSourceLocation.qml"), ConnectSuccess);
- m_client->sendRecordingStatus(true);
while (!(m_process->output().contains(QLatin1String("500"))))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
- QQmlProfilerData expected(0, QQmlProfilerDefinitions::RangeLocation,
- QQmlProfilerDefinitions::HandlingSignal,
- QLatin1String("signalSourceLocation.qml"));
- expected.line = 8;
- expected.column = 28;
- VERIFY(MessageListQML, 9, expected, CheckAll);
+ auto createType = [](int line, int column) {
+ return QQmlProfilerEventType(
+ MaximumMessage, HandlingSignal, -1,
+ QQmlProfilerEventLocation(QLatin1String("signalSourceLocation.qml"), line,
+ column));
+ };
- expected.line = 7;
- expected.column = 21;
- VERIFY(MessageListQML, 11, expected, CheckAll);
+ VERIFY(MessageListQML, 4, createType(8, 28), CheckType | CheckNumbers, m_rangeStart);
+ VERIFY(MessageListQML, 6, createType(7, 21), CheckType | CheckNumbers, m_rangeEnd);
}
void tst_QQmlProfilerService::javascript()
{
- connect(true, "javascript.qml");
+ QCOMPARE(connect(true, "javascript.qml"), ConnectSuccess);
- m_client->sendRecordingStatus(true);
while (!(m_process->output().contains(QLatin1String("done"))))
QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
- QQmlProfilerData expected(0, QQmlProfilerDefinitions::RangeStart,
- QQmlProfilerDefinitions::Javascript);
- VERIFY(MessageListJavaScript, 6, expected, CheckMessageType | CheckDetailType);
+ VERIFY(MessageListJavaScript, 2, QQmlProfilerEventType(MaximumMessage, Javascript),
+ CheckMessageType | CheckDetailType | CheckNumbers, m_rangeStart);
- expected.messageType = QQmlProfilerDefinitions::RangeLocation;
- expected.detailData = QLatin1String("javascript.qml");
- expected.line = 4;
- expected.column = 5;
- VERIFY(MessageListJavaScript, 7, expected, CheckAll);
+ VERIFY(MessageListJavaScript, 3,
+ QQmlProfilerEventType(
+ MaximumMessage, Javascript, -1,
+ QQmlProfilerEventLocation(QLatin1String("javascript.qml"), 4, 5)),
+ CheckType | CheckNumbers, m_rangeStart);
- expected.messageType = QQmlProfilerDefinitions::RangeData;
- expected.detailData = QLatin1String("something");
- VERIFY(MessageListJavaScript, 8, expected,
- CheckMessageType | CheckDetailType | CheckDataEndsWith);
+ VERIFY(MessageListJavaScript, 4, QQmlProfilerEventType(
+ MaximumMessage, Javascript, -1,
+ QQmlProfilerEventLocation(), QLatin1String("something")),
+ CheckMessageType | CheckDetailType | CheckDataEndsWith | CheckNumbers, m_rangeStart);
- expected.messageType = QQmlProfilerDefinitions::RangeEnd;
- VERIFY(MessageListJavaScript, 21, expected, CheckMessageType | CheckDetailType);
+ VERIFY(MessageListJavaScript, 10, QQmlProfilerEventType(MaximumMessage, Javascript),
+ CheckMessageType | CheckDetailType | CheckNumbers, m_rangeEnd);
}
void tst_QQmlProfilerService::flushInterval()
{
- connect(true, "timer.qml");
-
- m_client->sendRecordingStatus(true, -1, 1);
+ QCOMPARE(connect(true, "timer.qml", true, 1), ConnectSuccess);
// Make sure we get multiple messages
QTRY_VERIFY(m_client->qmlMessages.length() > 0);
QVERIFY(m_client->qmlMessages.length() < 100);
QTRY_VERIFY(m_client->qmlMessages.length() > 100);
- m_client->sendRecordingStatus(false);
+ m_client->client->setRecording(false);
+ checkTraceReceived();
+ checkJsHeap();
+}
+
+void tst_QQmlProfilerService::translationBinding()
+{
+ QCOMPARE(connect(true, "qstr.qml"), ConnectSuccess);
+ checkProcessTerminated();
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ const QQmlProfilerEventType type(MaximumMessage, Binding);
+
+ VERIFY(MessageListQML, 4, type, CheckDetailType | CheckMessageType | CheckNumbers,
+ m_rangeStart);
+ VERIFY(MessageListQML, 5, type, CheckDetailType | CheckMessageType | CheckNumbers,
+ m_rangeEnd);
+}
+
+void tst_QQmlProfilerService::memory()
+{
+ QCOMPARE(connect(true, "memory.qml"), ConnectSuccess);
+ checkProcessTerminated();
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ QVERIFY(m_client);
+ int smallItems = 0;
+ for (const auto& message : m_client->jsHeapMessages) {
+ const QQmlProfilerEventType &type = m_client->types[message.typeIndex()];
+ if (type.detailType() == SmallItem)
+ ++smallItems;
+ }
+
+ QVERIFY(smallItems > 5);
+}
+
+static bool hasCompileEvents(const QVector<QQmlProfilerEventType> &types)
+{
+ for (const QQmlProfilerEventType &type : types) {
+ if (type.message() == MaximumMessage && type.rangeType() == Compiling)
+ return true;
+ }
+ return false;
+}
+
+void tst_QQmlProfilerService::compile()
+{
+ // Flush interval so that we actually get the events before we stop recording.
+ connect(true, "test.qml", true, 100);
+
+ QVERIFY(m_client);
+
+ // We need to check specifically for compile events as we can otherwise stop recording after the
+ // StartTrace has arrived, but before it compiles anything.
+ QTRY_VERIFY(hasCompileEvents(m_client->types));
+ m_client->client->setRecording(false);
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ Message rangeStage = MaximumMessage;
+ for (const auto& message : m_client->qmlMessages) {
+ const QQmlProfilerEventType &type = m_client->types[message.typeIndex()];
+ if (type.rangeType() == Compiling) {
+ switch (rangeStage) {
+ case MaximumMessage:
+ QCOMPARE(message.rangeStage(), RangeStart);
+ break;
+ case RangeStart:
+ QCOMPARE(message.rangeStage(), RangeEnd);
+ break;
+ default:
+ QFAIL("Wrong range stage");
+ }
+ rangeStage = message.rangeStage();
+ QCOMPARE(type.message(), MaximumMessage);
+ QCOMPARE(type.location().filename(), testFileUrl("test.qml").toString());
+ QCOMPARE(type.location().line(), 0);
+ QCOMPARE(type.location().column(), 0);
+ }
+ }
+
+ QCOMPARE(rangeStage, RangeEnd);
+}
+
+void tst_QQmlProfilerService::multiEngine()
+{
+ QCOMPARE(connect(true, "quit.qml", true, 0, false, debugJsServerPath("qqmlprofilerservice")),
+ ConnectSuccess);
+
+ QSignalSpy spy(m_client->client, SIGNAL(complete(qint64)));
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ QTRY_COMPARE(m_process->state(), QProcess::NotRunning);
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QQmlProfilerService::batchOverflow()
+{
+ // The trace client checks that the events are received in order.
+ QCOMPARE(connect(true, "batchOverflow.qml"), ConnectSuccess);
+ checkProcessTerminated();
checkTraceReceived();
checkJsHeap();
}
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 441f8c113f..b75fb6b895 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -38,7 +38,6 @@
#include <private/qv4debugging_p.h>
#include <private/qv8engine_p.h>
#include <private/qv4objectiterator_p.h>
-#include <private/qv4isel_moth_p.h>
#include <private/qv4string_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmldebugservice_p.h>
@@ -46,7 +45,7 @@
using namespace QV4;
using namespace QV4::Debugging;
-typedef void (*InjectedFunction)(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+typedef QV4::ReturnedValue (*InjectedFunction)(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int);
Q_DECLARE_METATYPE(InjectedFunction)
static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000)
@@ -79,7 +78,7 @@ public:
emit evaluateFinished();
}
- QV4::ExecutionEngine *v4Engine() { return QV8Engine::getV4(this); }
+ QV4::ExecutionEngine *v4Engine() { return handle(); }
Q_INVOKABLE void injectFunction(const QString &functionName, InjectedFunction injectedFunction)
{
@@ -87,8 +86,7 @@ public:
QV4::Scope scope(v4);
QV4::ScopedString name(scope, v4->newString(functionName));
- QV4::ScopedContext ctx(scope, v4->rootContext());
- QV4::ScopedValue function(scope, BuiltinFunction::create(ctx, name, injectedFunction));
+ QV4::ScopedValue function(scope, FunctionObject::createBuiltinFunction(v4, name, injectedFunction, 0));
v4->globalObject->put(name, function);
}
@@ -107,7 +105,7 @@ public:
void run() {
QV4::Scope scope(collector->engine());
QV4::ScopedValue v(scope, *collector->engine()->exceptionValue);
- exception = collector->collect(v);
+ exception = collector->addValueRef(v);
}
QV4DataCollector::Ref exceptionValue() const { return exception; }
@@ -167,7 +165,7 @@ public:
, m_thrownValue(-1)
, collector(engine)
, m_resumeSpeed(QV4Debugger::FullThrottle)
- , m_debugger(0)
+ , m_debugger(nullptr)
{
}
@@ -221,16 +219,26 @@ public:
{
for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
m_capturedScope.append(NamedRefs());
- ScopeJob job(&collector, i, 0);
+ FrameJob frameJob(&collector, i);
+ debugger->runInEngine(&frameJob);
+ QJsonObject frameObj = frameJob.returnValue();
+ QJsonArray scopes = frameObj.value(QLatin1String("scopes")).toArray();
+ int nscopes = scopes.size();
+ int s = 0;
+ for (s = 0; s < nscopes; ++s) {
+ QJsonObject o = scopes.at(s).toObject();
+ if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext
+ break;
+ }
+ if (s == nscopes)
+ return;
+
+ ScopeJob job(&collector, i, s);
debugger->runInEngine(&job);
NamedRefs &refs = m_capturedScope.last();
QJsonObject object = job.returnValue();
object = object.value(QLatin1String("object")).toObject();
- if (object.contains("ref") && !object.contains("properties")) {
- QVERIFY(collector.redundantRefs());
- object = collector.lookupRef(object.value("ref").toInt(), true);
- QVERIFY(object.contains("properties"));
- }
+ QVERIFY(!object.contains("ref") || object.contains("properties"));
foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) {
QJsonObject property = value.toObject();
QString name = property.value(QLatin1String("name")).toString();
@@ -296,13 +304,10 @@ private slots:
void conditionalBreakPointInQml();
// context access:
- void readArguments_data() { redundancy_data(); }
void readArguments();
- void readLocals_data() { redundancy_data(); }
+ void readComplicatedArguments();
void readLocals();
- void readObject_data() { redundancy_data(); }
void readObject();
- void readContextInAllFrames_data() { redundancy_data(); }
void readContextInAllFrames();
// exceptions:
@@ -310,13 +315,13 @@ private slots:
void breakInCatch();
void breakInWith();
- void evaluateExpression_data() { redundancy_data(); }
void evaluateExpression();
- void stepToEndOfScript_data() { redundancy_data(); }
void stepToEndOfScript();
void lastLineOfConditional_data();
void lastLineOfConditional();
+
+ void readThis();
private:
QV4Debugger *debugger() const
{
@@ -330,8 +335,6 @@ private:
waitForSignal(m_engine, SIGNAL(evaluateFinished()), /*timeout*/0);
}
- void redundancy_data();
-
TestEngine *m_engine;
QV4::ExecutionEngine *m_v4;
TestAgent *m_debuggerAgent;
@@ -343,7 +346,6 @@ void tst_qv4debugger::init()
m_javaScriptThread = new QThread;
m_engine = new TestEngine;
m_v4 = m_engine->v4Engine();
- m_v4->iselFactory.reset(new QV4::Moth::ISelFactory);
m_v4->setDebugger(new QV4Debugger(m_v4));
m_engine->moveToThread(m_javaScriptThread);
m_javaScriptThread->start();
@@ -357,10 +359,10 @@ void tst_qv4debugger::cleanup()
m_javaScriptThread->wait();
delete m_engine;
delete m_javaScriptThread;
- m_engine = 0;
- m_v4 = 0;
+ m_engine = nullptr;
+ m_v4 = nullptr;
delete m_debuggerAgent;
- m_debuggerAgent = 0;
+ m_debuggerAgent = nullptr;
}
void tst_qv4debugger::breakAnywhere()
@@ -438,9 +440,9 @@ void tst_qv4debugger::addBreakPointWhilePaused()
QCOMPARE(state.lineNumber, 2);
}
-static void someCall(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
+static QV4::ReturnedValue someCall(const FunctionObject *function, const QV4::Value *, const QV4::Value *, int)
{
- static_cast<QV4Debugger *>(scope.engine->debugger())
+ static_cast<QV4Debugger *>(function->engine()->debugger())
->removeBreakPoint("removeBreakPointForNextInstruction", 2);
RETURN_UNDEFINED();
}
@@ -464,7 +466,7 @@ void tst_qv4debugger::conditionalBreakPoint()
{
m_debuggerAgent->m_captureContextInfo = true;
QString script =
- "function test() {\n"
+ "var test = function() {\n"
" for (var i = 0; i < 15; ++i) {\n"
" var x = i;\n"
" }\n"
@@ -481,7 +483,7 @@ void tst_qv4debugger::conditionalBreakPoint()
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 2);
+ QCOMPARE(frame0.size(), 3);
QVERIFY(frame0.contains("i"));
QCOMPARE(frame0.value("i").toInt(), 11);
}
@@ -489,9 +491,8 @@ void tst_qv4debugger::conditionalBreakPoint()
void tst_qv4debugger::conditionalBreakPointInQml()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
+ QV4::ExecutionEngine *v4 = engine.handle();
QV4Debugger *v4Debugger = new QV4Debugger(v4);
- v4->iselFactory.reset(new QV4::Moth::ISelFactory);
v4->setDebugger(v4Debugger);
QScopedPointer<QThread> debugThread(new QThread);
@@ -526,12 +527,9 @@ void tst_qv4debugger::conditionalBreakPointInQml()
void tst_qv4debugger::readArguments()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
-
m_debuggerAgent->m_captureContextInfo = true;
QString script =
- "function f(a, b, c, d) {\n"
+ "var f = function(a, b, c, d) {\n"
" return a === b\n"
"}\n"
"var four;\n"
@@ -541,7 +539,7 @@ void tst_qv4debugger::readArguments()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 4);
+ QCOMPARE(frame0.size(), 5);
QVERIFY(frame0.contains(QStringLiteral("a")));
QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number"));
QCOMPARE(frame0.value(QStringLiteral("a")).toDouble(), 1.0);
@@ -550,14 +548,31 @@ void tst_qv4debugger::readArguments()
QCOMPARE(frame0.value(QStringLiteral("b")).toString(), QStringLiteral("two"));
}
-void tst_qv4debugger::readLocals()
+void tst_qv4debugger::readComplicatedArguments()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "var f = function(a) {\n"
+ " a = 12;\n"
+ " return a;\n"
+ "}\n"
+ "f(1, 2);\n";
+ debugger()->addBreakPoint("readArguments", 3);
+ evaluateJavaScript(script, "readArguments");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
+ const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
+ QCOMPARE(frame0.size(), 2);
+ QVERIFY(frame0.contains(QStringLiteral("a")));
+ QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number"));
+ QCOMPARE(frame0.value(QStringLiteral("a")).toInt(), 12);
+}
+void tst_qv4debugger::readLocals()
+{
m_debuggerAgent->m_captureContextInfo = true;
QString script =
- "function f(a, b) {\n"
+ "var f = function(a, b) {\n"
" var c = a + b\n"
" var d = a - b\n" // breakpoint, c should be set, d should be undefined
" return c === d\n"
@@ -568,7 +583,7 @@ void tst_qv4debugger::readLocals()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 4); // locals and parameters
+ QCOMPARE(frame0.size(), 5); // locals and parameters
QVERIFY(frame0.contains("c"));
QCOMPARE(frame0.type("c"), QStringLiteral("number"));
QCOMPARE(frame0.value("c").toDouble(), 3.0);
@@ -578,12 +593,9 @@ void tst_qv4debugger::readLocals()
void tst_qv4debugger::readObject()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
-
m_debuggerAgent->m_captureContextInfo = true;
QString script =
- "function f(a) {\n"
+ "var f = function(a) {\n"
" var b = a\n"
" return b\n"
"}\n"
@@ -593,7 +605,7 @@ void tst_qv4debugger::readObject()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 2);
+ QCOMPARE(frame0.size(), 3);
QVERIFY(frame0.contains("b"));
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
QJsonObject b = frame0.rawValue("b");
@@ -602,7 +614,7 @@ void tst_qv4debugger::readObject()
QVERIFY(!b.contains(QStringLiteral("properties")));
QVERIFY(b.value("value").isDouble());
QCOMPARE(b.value("value").toInt(), 2);
- b = m_debuggerAgent->collector.lookupRef(b.value("ref").toInt(), true);
+ b = m_debuggerAgent->collector.lookupRef(b.value("ref").toInt());
QVERIFY(b.contains(QStringLiteral("properties")));
QVERIFY(b.value("properties").isArray());
QJsonArray b_props = b.value("properties").toArray();
@@ -618,8 +630,7 @@ void tst_qv4debugger::readObject()
QCOMPARE(b_tail.value("name").toString(), QStringLiteral("tail"));
QVERIFY(b_tail.contains("ref"));
- QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt(),
- true);
+ QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt());
QCOMPARE(b_tail_value.value("type").toString(), QStringLiteral("object"));
QVERIFY(b_tail_value.contains("properties"));
QJsonArray b_tail_props = b_tail_value.value("properties").toArray();
@@ -630,18 +641,15 @@ void tst_qv4debugger::readObject()
QCOMPARE(b_tail_head.value("value").toString(), QStringLiteral("asdf"));
QJsonObject b_tail_tail = b_tail_props.at(1).toObject();
QCOMPARE(b_tail_tail.value("name").toString(), QStringLiteral("tail"));
- QCOMPARE(b_tail_tail.value("type").toString(), QStringLiteral("null"));
+ QCOMPARE(b_tail_tail.value("type").toString(), QStringLiteral("object"));
QVERIFY(b_tail_tail.value("value").isNull());
}
void tst_qv4debugger::readContextInAllFrames()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
-
m_debuggerAgent->m_captureContextInfo = true;
QString script =
- "function fact(n) {\n"
+ "var fact = function(n) {\n"
" if (n > 1) {\n"
" var n_1 = n - 1;\n"
" n_1 = fact(n_1);\n"
@@ -658,7 +666,7 @@ void tst_qv4debugger::readContextInAllFrames()
for (int i = 0; i < 12; ++i) {
const TestAgent::NamedRefs &scope = m_debuggerAgent->m_capturedScope.at(i);
- QCOMPARE(scope.size(), 2);
+ QCOMPARE(scope.size(), 3);
QVERIFY(scope.contains("n"));
QCOMPARE(scope.type("n"), QStringLiteral("number"));
QCOMPARE(scope.value("n").toDouble(), i + 1.0);
@@ -686,8 +694,7 @@ void tst_qv4debugger::pauseOnThrow()
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Throwing);
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
QVERIFY(m_debuggerAgent->m_thrownValue >= qint64(0));
- QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue,
- true);
+ QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue);
// DUMP_JSON(exception);
QCOMPARE(exception.value("type").toString(), QStringLiteral("string"));
QCOMPARE(exception.value("value").toString(), QStringLiteral("hard"));
@@ -731,9 +738,6 @@ void tst_qv4debugger::breakInWith()
void tst_qv4debugger::evaluateExpression()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
-
QString script =
"function testFunction() {\n"
" var x = 10\n"
@@ -775,9 +779,6 @@ void tst_qv4debugger::evaluateExpression()
void tst_qv4debugger::stepToEndOfScript()
{
- QFETCH(bool, redundantRefs);
- m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
-
QString script =
"var ret = 0;\n"
"ret += 4;\n"
@@ -814,13 +815,13 @@ void tst_qv4debugger::lastLineOfConditional_data()
QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7;
QTest::newRow("if true {block}") << "if (true) {\n" << "}"
- << 4 << 7;
+ << 4 << 8;
QTest::newRow("if false {block}") << "if (false) {\n" << "}"
<< 2 << 8;
QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}"
- << 4 << 7;
+ << 4 << 10;
QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}"
- << 8 << 9;
+ << 8 << 10;
QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2;
QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2;
@@ -829,11 +830,11 @@ void tst_qv4debugger::lastLineOfConditional_data()
// For two nested if statements without blocks, we need to map the jump from the inner to the
// outer one on the outer "if". There is just no better place.
- QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2;
+ QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 8;
QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8;
// Also two nested ifs without blocks.
- QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2;
+ QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 9;
QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9;
}
@@ -868,11 +869,34 @@ void tst_qv4debugger::lastLineOfConditional()
QCOMPARE(secondState.lineNumber, lastLine);
}
-void tst_qv4debugger::redundancy_data()
+void tst_qv4debugger::readThis()
{
- QTest::addColumn<bool>("redundantRefs");
- QTest::addRow("redundant") << true;
- QTest::addRow("sparse") << false;
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "var x = function() {\n"
+ " return this.a;\n"
+ "}.apply({a : 5}, []);\n";
+
+ TestAgent::ExpressionRequest request;
+ request.expression = "this";
+ request.frameNr = 0;
+ request.context = -1; // no extra context
+ m_debuggerAgent->m_expressionRequests << request;
+
+ debugger()->addBreakPoint("applyThis", 2);
+ evaluateJavaScript(script, "applyThis");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+
+ QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 1);
+ QJsonObject result0 = m_debuggerAgent->m_expressionResults[0];
+ QCOMPARE(result0.value("type").toString(), QStringLiteral("object"));
+ QCOMPARE(result0.value("value").toInt(), 1);
+ QJsonArray properties = result0.value("properties").toArray();
+ QCOMPARE(properties.size(), 1);
+ QJsonObject a = properties.first().toObject();
+ QCOMPARE(a.value("name").toString(), QStringLiteral("a"));
+ QCOMPARE(a.value("type").toString(), QStringLiteral("number"));
+ QCOMPARE(a.value("value").toInt(), 5);
}
QTEST_MAIN(tst_qv4debugger)
diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp
index 7b9e935678..68446b53a4 100644
--- a/tests/auto/qml/debugger/shared/debugutil.cpp
+++ b/tests/auto/qml/debugger/shared/debugutil.cpp
@@ -27,13 +27,12 @@
****************************************************************************/
#include "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
#include <private/qqmldebugconnection_p.h>
#include <QtCore/qeventloop.h>
#include <QtCore/qtimer.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qdir.h>
bool QQmlDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) {
QEventLoop loop;
@@ -51,15 +50,23 @@ bool QQmlDebugTest::waitForSignal(QObject *receiver, const char *member, int tim
QList<QQmlDebugClient *> QQmlDebugTest::createOtherClients(QQmlDebugConnection *connection)
{
QList<QQmlDebugClient *> ret;
- foreach (const QString &service, QQmlDebuggingEnabler::debuggerServices()) {
+
+ static const auto debuggerServices
+ = QStringList({"V8Debugger", "QmlDebugger", "DebugMessages"});
+ static const auto inspectorServices
+ = QStringList({"QmlInspector"});
+ static const auto profilerServices
+ = QStringList({"CanvasFrameRate", "EngineControl", "DebugMessages"});
+
+ for (const QString &service : debuggerServices) {
if (!connection->client(service))
ret << new QQmlDebugClient(service, connection);
}
- foreach (const QString &service, QQmlDebuggingEnabler::inspectorServices()) {
+ for (const QString &service : inspectorServices) {
if (!connection->client(service))
ret << new QQmlDebugClient(service, connection);
}
- foreach (const QString &service, QQmlDebuggingEnabler::profilerServices()) {
+ for (const QString &service : profilerServices) {
if (!connection->client(service))
ret << new QQmlDebugClient(service, connection);
}
@@ -91,6 +98,9 @@ QString QQmlDebugTest::connectionStateString(const QQmlDebugConnection *connecti
QQmlDebugTestClient::QQmlDebugTestClient(const QString &s, QQmlDebugConnection *c)
: QQmlDebugClient(s, c)
{
+ connect(this, &QQmlDebugClient::stateChanged, this, [this](QQmlDebugClient::State newState) {
+ QCOMPARE(newState, state());
+ });
}
QByteArray QQmlDebugTestClient::waitForResponse()
@@ -104,201 +114,150 @@ QByteArray QQmlDebugTestClient::waitForResponse()
return lastMsg;
}
-void QQmlDebugTestClient::stateChanged(State stat)
-{
- QCOMPARE(stat, state());
- emit stateHasChanged();
-}
-
void QQmlDebugTestClient::messageReceived(const QByteArray &ba)
{
lastMsg = ba;
emit serverMessage(ba);
}
-QQmlDebugProcess::QQmlDebugProcess(const QString &executable, QObject *parent)
- : QObject(parent)
- , m_executable(executable)
- , m_started(false)
- , m_port(0)
- , m_maximumBindErrors(0)
- , m_receivedBindErrors(0)
+QQmlDebugTest::ConnectResult QQmlDebugTest::connect(
+ const QString &executable, const QString &services, const QString &extraArgs,
+ bool block)
{
- m_process.setProcessChannelMode(QProcess::MergedChannels);
- m_timer.setSingleShot(true);
- m_timer.setInterval(5000);
- connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processAppOutput()));
- connect(&m_process, SIGNAL(errorOccurred(QProcess::ProcessError)),
- this, SLOT(processError(QProcess::ProcessError)));
- connect(&m_timer, SIGNAL(timeout()), SLOT(timeout()));
-}
+ QStringList arguments;
+ arguments << QString::fromLatin1("-qmljsdebugger=port:13773,13783%3%4")
+ .arg(block ? QStringLiteral(",block") : QString())
+ .arg(services.isEmpty() ? services : (QStringLiteral(",services:") + services))
+ << extraArgs;
-QQmlDebugProcess::~QQmlDebugProcess()
-{
- stop();
-}
+ m_process = createProcess(executable);
+ if (!m_process)
+ return ProcessFailed;
-QString QQmlDebugProcess::state()
-{
- QString stateStr;
- switch (m_process.state()) {
- case QProcess::NotRunning: {
- stateStr = "not running";
- if (m_process.exitStatus() == QProcess::CrashExit)
- stateStr += " (crashed!)";
- else
- stateStr += ", return value " + QString::number(m_process.exitCode());
- break;
- }
- case QProcess::Starting: stateStr = "starting"; break;
- case QProcess::Running: stateStr = "running"; break;
- }
- return stateStr;
-}
+ m_process->start(QStringList() << arguments);
+ if (!m_process->waitForSessionStart())
+ return SessionFailed;
-void QQmlDebugProcess::start(const QStringList &arguments)
-{
-#ifdef Q_OS_MAC
- // make sure m_executable points to the actual binary even if it's inside an app bundle
- QFileInfo binFile(m_executable);
- if (!binFile.isExecutable()) {
- QDir bundleDir(m_executable + ".app");
- if (bundleDir.exists()) {
- m_executable = bundleDir.absoluteFilePath("Contents/MacOS/" + binFile.baseName());
- //qDebug() << Q_FUNC_INFO << "found bundled binary" << m_executable;
- }
- }
-#endif
- m_mutex.lock();
- m_port = 0;
- m_process.setEnvironment(QProcess::systemEnvironment() + m_environment);
- m_process.start(m_executable, arguments);
- if (!m_process.waitForStarted()) {
- qWarning() << "QML Debug Client: Could not launch app " << m_executable
- << ": " << m_process.errorString();
- m_eventLoop.quit();
- } else {
- m_timer.start();
- }
- m_mutex.unlock();
+ m_connection = createConnection();
+ if (!m_connection)
+ return ConnectionFailed;
+
+ m_clients = createClients();
+ if (m_clients.contains(nullptr))
+ return ClientsFailed;
+
+ ClientStateHandler stateHandler(m_clients, createOtherClients(m_connection), services.isEmpty()
+ ? QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
+
+
+ const int port = m_process->debugPort();
+ m_connection->connectToHost(QLatin1String("127.0.0.1"), port);
+
+ QEventLoop loop;
+ QTimer timer;
+ QObject::connect(&stateHandler, &ClientStateHandler::allOk, &loop, &QEventLoop::quit);
+ QObject::connect(m_connection, &QQmlDebugConnection::disconnected, &loop, &QEventLoop::quit);
+ QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+
+ timer.start(5000);
+ loop.exec();
+
+ if (!stateHandler.allEnabled())
+ return EnableFailed;
+
+ if (!stateHandler.othersAsExpected())
+ return RestrictFailed;
+
+ return ConnectSuccess;
}
-void QQmlDebugProcess::stop()
+QList<QQmlDebugClient *> QQmlDebugTest::createClients()
{
- if (m_process.state() != QProcess::NotRunning) {
- m_process.kill();
- m_process.waitForFinished(5000);
- }
+ return QList<QQmlDebugClient *>();
}
-void QQmlDebugProcess::setMaximumBindErrors(int ignore)
+QQmlDebugProcess *QQmlDebugTest::createProcess(const QString &executable)
{
- m_maximumBindErrors = ignore;
+ return new QQmlDebugProcess(executable, this);
}
-void QQmlDebugProcess::timeout()
+QQmlDebugConnection *QQmlDebugTest::createConnection()
{
- qWarning() << "Timeout while waiting for QML debugging messages "
- "in application output. Process is in state" << m_process.state() << ", Output:" << m_output << ".";
- m_eventLoop.quit();
+ return new QQmlDebugConnection(this);
}
-bool QQmlDebugProcess::waitForSessionStart()
+void QQmlDebugTest::cleanup()
{
- if (m_process.state() != QProcess::Running) {
- qWarning() << "Could not start up " << m_executable;
- return false;
+ if (QTest::currentTestFailed()) {
+ const QString null = QStringLiteral("null");
+
+ qDebug() << "Process State:" << (m_process ? m_process->stateString() : null);
+ qDebug() << "Application Output:" << (m_process ? m_process->output() : null);
+ qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection);
+ for (QQmlDebugClient *client : m_clients) {
+ if (client)
+ qDebug() << client->name() << "State:" << QQmlDebugTest::clientStateString(client);
+ else
+ qDebug() << "Failed Client:" << null;
+ }
}
- m_eventLoop.exec();
- return m_started;
-}
+ qDeleteAll(m_clients);
+ m_clients.clear();
-int QQmlDebugProcess::debugPort() const
-{
- return m_port;
-}
+ delete m_connection;
+ m_connection = nullptr;
-bool QQmlDebugProcess::waitForFinished()
-{
- return m_process.waitForFinished();
+ if (m_process) {
+ m_process->stop();
+ delete m_process;
+ m_process = nullptr;
+ }
}
-QProcess::ExitStatus QQmlDebugProcess::exitStatus() const
+ClientStateHandler::ClientStateHandler(const QList<QQmlDebugClient *> &clients,
+ const QList<QQmlDebugClient *> &others,
+ QQmlDebugClient::State expectedOthers) :
+ m_clients(clients), m_others(others), m_expectedOthers(expectedOthers)
{
- return m_process.exitStatus();
+ for (QQmlDebugClient *client : m_clients) {
+ QObject::connect(client, &QQmlDebugClient::stateChanged,
+ this, &ClientStateHandler::checkStates);
+ }
+ for (QQmlDebugClient *client : m_others) {
+ QObject::connect(client, &QQmlDebugClient::stateChanged,
+ this, &ClientStateHandler::checkStates);
+ }
}
-void QQmlDebugProcess::addEnvironment(const QString &environment)
+ClientStateHandler::~ClientStateHandler()
{
- m_environment.append(environment);
+ qDeleteAll(m_others);
}
-QString QQmlDebugProcess::output() const
+void ClientStateHandler::checkStates()
{
- return m_output;
-}
+ for (QQmlDebugClient *client : m_clients) {
+ if (client->state() != QQmlDebugClient::Enabled)
+ return;
+ }
-void QQmlDebugProcess::processAppOutput()
-{
- m_mutex.lock();
-
- bool outputFromAppItself = false;
-
- QString newOutput = m_process.readAll();
- m_output.append(newOutput);
- m_outputBuffer.append(newOutput);
-
- while (true) {
- const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n'));
- if (nlIndex < 0) // no further complete lines
- break;
- const QString line = m_outputBuffer.left(nlIndex);
- m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1);
-
- if (line.contains("QML Debugger:")) {
- const QRegExp portRx("Waiting for connection on port (\\d+)");
- if (portRx.indexIn(line) != -1) {
- m_port = portRx.cap(1).toInt();
- m_timer.stop();
- m_started = true;
- m_eventLoop.quit();
- continue;
- }
- if (line.contains("Unable to listen")) {
- if (++m_receivedBindErrors >= m_maximumBindErrors) {
- if (m_maximumBindErrors == 0)
- qWarning() << "App was unable to bind to port!";
- m_timer.stop();
- m_eventLoop.quit();
- }
- continue;
- }
- } else {
- // set to true if there is output not coming from the debugger
- outputFromAppItself = true;
- }
+ m_allEnabled = true;
+
+ for (QQmlDebugClient *other : m_others) {
+ if (other->state() != m_expectedOthers)
+ return;
}
- m_mutex.unlock();
- if (outputFromAppItself)
- emit readyReadStandardOutput();
+ m_othersAsExpected = true;
+ emit allOk();
}
-void QQmlDebugProcess::processError(QProcess::ProcessError error)
+QString debugJsServerPath(const QString &selfPath)
{
- if (!m_eventLoop.isRunning())
- return;
-
- qDebug() << "An error occurred while waiting for debug process to become available:";
- switch (error) {
- case QProcess::FailedToStart: qDebug() << "Process failed to start."; break;
- case QProcess::Crashed: qDebug() << "Process crashed."; break;
- case QProcess::Timedout: qDebug() << "Process timed out."; break;
- case QProcess::WriteError: qDebug() << "Error while writing to process."; break;
- case QProcess::ReadError: qDebug() << "Error while reading from process."; break;
- case QProcess::UnknownError: qDebug() << "Unknown process error."; break;
- }
-
- m_eventLoop.exit();
+ static const char *debugserver = "qqmldebugjsserver";
+ QString appPath = QCoreApplication::applicationDirPath();
+ const int position = appPath.lastIndexOf(selfPath);
+ return (position == -1 ? appPath : appPath.replace(position, selfPath.length(), debugserver))
+ + "/" + debugserver;
}
diff --git a/tests/auto/qml/debugger/shared/debugutil.pri b/tests/auto/qml/debugger/shared/debugutil.pri
index 1983f3583e..13dcdb91d8 100644
--- a/tests/auto/qml/debugger/shared/debugutil.pri
+++ b/tests/auto/qml/debugger/shared/debugutil.pri
@@ -1,4 +1,11 @@
QT += qmldebug-private
-HEADERS += $$PWD/debugutil_p.h
-SOURCES += $$PWD/debugutil.cpp
+INCLUDEPATH += $$PWD
+include($$PWD/../../../shared/util.pri)
+
+HEADERS += \
+ $$PWD/debugutil_p.h \
+ $$PWD/qqmldebugprocess_p.h
+SOURCES += \
+ $$PWD/debugutil.cpp \
+ $$PWD/qqmldebugprocess.cpp
diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h
index 1ec0a6513d..1c32590305 100644
--- a/tests/auto/qml/debugger/shared/debugutil_p.h
+++ b/tests/auto/qml/debugger/shared/debugutil_p.h
@@ -1,4 +1,3 @@
-
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
@@ -41,23 +40,43 @@
// We mean it.
//
+#include <../../../shared/util.h>
#include <private/qqmldebugclient_p.h>
-#include <QtCore/qeventloop.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qthread.h>
-#include <QtCore/qprocess.h>
-#include <QtCore/qmutex.h>
-#include <QtTest/qtest.h>
-#include <QtQml/qqmlengine.h>
-
-class QQmlDebugTest
+class QQmlDebugProcess;
+class QQmlDebugTest : public QQmlDataTest
{
+ Q_OBJECT
public:
static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000);
static QList<QQmlDebugClient *> createOtherClients(QQmlDebugConnection *connection);
static QString clientStateString(const QQmlDebugClient *client);
static QString connectionStateString(const QQmlDebugConnection *connection);
+
+protected:
+ enum ConnectResult {
+ ConnectSuccess,
+ ProcessFailed,
+ SessionFailed,
+ ConnectionFailed,
+ ClientsFailed,
+ EnableFailed,
+ RestrictFailed
+ };
+
+ ConnectResult connect(const QString &executable, const QString &services,
+ const QString &extraArgs, bool block);
+
+ virtual QQmlDebugProcess *createProcess(const QString &executable);
+ virtual QQmlDebugConnection *createConnection();
+ virtual QList<QQmlDebugClient *> createClients();
+
+ QQmlDebugProcess *m_process = nullptr;
+ QQmlDebugConnection *m_connection = nullptr;
+ QList<QQmlDebugClient *> m_clients;
+
+protected slots:
+ virtual void cleanup();
};
class QQmlDebugTestClient : public QQmlDebugClient
@@ -69,62 +88,15 @@ public:
QByteArray waitForResponse();
signals:
- void stateHasChanged();
void serverMessage(const QByteArray &);
protected:
- virtual void stateChanged(State state);
virtual void messageReceived(const QByteArray &ba);
private:
QByteArray lastMsg;
};
-class QQmlDebugProcess : public QObject
-{
- Q_OBJECT
-public:
- QQmlDebugProcess(const QString &executable, QObject *parent = 0);
- ~QQmlDebugProcess();
-
- QString state();
-
- void addEnvironment(const QString &environment);
-
- void start(const QStringList &arguments);
- bool waitForSessionStart();
- int debugPort() const;
-
- bool waitForFinished();
- QProcess::ExitStatus exitStatus() const;
-
- QString output() const;
- void stop();
- void setMaximumBindErrors(int numErrors);
-
-signals:
- void readyReadStandardOutput();
-
-private slots:
- void timeout();
- void processAppOutput();
- void processError(QProcess::ProcessError error);
-
-private:
- QString m_executable;
- QProcess m_process;
- QString m_outputBuffer;
- QString m_output;
- QTimer m_timer;
- QEventLoop m_eventLoop;
- QMutex m_mutex;
- bool m_started;
- QStringList m_environment;
- int m_port;
- int m_maximumBindErrors;
- int m_receivedBindErrors;
-};
-
class QQmlInspectorResultRecipient : public QObject
{
Q_OBJECT
@@ -142,4 +114,33 @@ public:
}
};
+class ClientStateHandler : public QObject
+{
+ Q_OBJECT
+public:
+ ClientStateHandler(const QList<QQmlDebugClient *> &clients,
+ const QList<QQmlDebugClient *> &others,
+ QQmlDebugClient::State expectedOthers);
+
+ ~ClientStateHandler();
+
+ bool allEnabled() const { return m_allEnabled; }
+ bool othersAsExpected() const { return m_othersAsExpected; }
+
+signals:
+ void allOk();
+
+private:
+ void checkStates();
+
+ const QList<QQmlDebugClient *> m_clients;
+ const QList<QQmlDebugClient *> m_others;
+ const QQmlDebugClient::State m_expectedOthers;
+
+ bool m_allEnabled = false;
+ bool m_othersAsExpected = false;
+};
+
+QString debugJsServerPath(const QString &selfPath);
+
#endif // DEBUGUTIL_P_H
diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
new file mode 100644
index 0000000000..956e97e7ba
--- /dev/null
+++ b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "qqmldebugprocess_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+
+QQmlDebugProcess::QQmlDebugProcess(const QString &executable, QObject *parent)
+ : QObject(parent)
+ , m_executable(executable)
+ , m_state(SessionUnknown)
+ , m_port(0)
+ , m_maximumBindErrors(0)
+ , m_receivedBindErrors(0)
+{
+ m_process.setProcessChannelMode(QProcess::MergedChannels);
+ m_timer.setInterval(15000);
+ connect(&m_process, &QProcess::readyReadStandardOutput,
+ this, &QQmlDebugProcess::processAppOutput);
+ connect(&m_process, &QProcess::errorOccurred,
+ this, &QQmlDebugProcess::processError);
+ connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ this, [this]() {
+ m_timer.stop();
+ m_eventLoop.quit();
+ emit finished();
+ });
+ connect(&m_timer, &QTimer::timeout,
+ this, &QQmlDebugProcess::timeout);
+}
+
+QQmlDebugProcess::~QQmlDebugProcess()
+{
+ stop();
+}
+
+QString QQmlDebugProcess::stateString() const
+{
+ QString stateStr;
+ switch (m_process.state()) {
+ case QProcess::NotRunning: {
+ stateStr = "not running";
+ if (m_process.exitStatus() == QProcess::CrashExit)
+ stateStr += " (crashed!)";
+ else
+ stateStr += ", return value " + QString::number(m_process.exitCode());
+ break;
+ }
+ case QProcess::Starting:
+ stateStr = "starting";
+ break;
+ case QProcess::Running:
+ stateStr = "running";
+ break;
+ }
+ return stateStr;
+}
+
+void QQmlDebugProcess::start(const QStringList &arguments)
+{
+#ifdef Q_OS_MAC
+ // make sure m_executable points to the actual binary even if it's inside an app bundle
+ QFileInfo binFile(m_executable);
+ if (!binFile.isExecutable()) {
+ QDir bundleDir(m_executable + ".app");
+ if (bundleDir.exists()) {
+ m_executable = bundleDir.absoluteFilePath("Contents/MacOS/" + binFile.baseName());
+ //qDebug() << Q_FUNC_INFO << "found bundled binary" << m_executable;
+ }
+ }
+#endif
+ m_mutex.lock();
+ m_port = 0;
+ m_process.setEnvironment(QProcess::systemEnvironment() + m_environment);
+ m_process.start(m_executable, arguments);
+ if (!m_process.waitForStarted()) {
+ qWarning() << "QML Debug Client: Could not launch app " << m_executable
+ << ": " << m_process.errorString();
+ m_eventLoop.quit();
+ }
+ m_mutex.unlock();
+}
+
+void QQmlDebugProcess::stop()
+{
+ if (m_process.state() != QProcess::NotRunning) {
+ disconnect(&m_process, &QProcess::errorOccurred, this, &QQmlDebugProcess::processError);
+ m_process.kill();
+ m_process.waitForFinished(5000);
+ }
+}
+
+void QQmlDebugProcess::setMaximumBindErrors(int ignore)
+{
+ m_maximumBindErrors = ignore;
+}
+
+void QQmlDebugProcess::timeout()
+{
+ qWarning() << "Timeout while waiting for QML debugging messages "
+ "in application output. Process is in state" << m_process.state()
+ << ", Output:" << m_output << ".";
+}
+
+bool QQmlDebugProcess::waitForSessionStart()
+{
+ if (m_process.state() != QProcess::Running) {
+ qWarning() << "Could not start up " << m_executable;
+ return false;
+ } else if (m_state == SessionStarted) {
+ return true;
+ } else if (m_state == SessionFailed) {
+ return false;
+ }
+
+ m_timer.start();
+ m_eventLoop.exec();
+
+ return m_state == SessionStarted;
+}
+
+int QQmlDebugProcess::debugPort() const
+{
+ return m_port;
+}
+
+bool QQmlDebugProcess::waitForFinished()
+{
+ return m_process.waitForFinished();
+}
+
+QProcess::ProcessState QQmlDebugProcess::state() const
+{
+ return m_process.state();
+}
+
+QProcess::ExitStatus QQmlDebugProcess::exitStatus() const
+{
+ return m_process.exitStatus();
+}
+
+void QQmlDebugProcess::addEnvironment(const QString &environment)
+{
+ m_environment.append(environment);
+}
+
+QString QQmlDebugProcess::output() const
+{
+ return m_output;
+}
+
+void QQmlDebugProcess::processAppOutput()
+{
+ m_mutex.lock();
+
+ bool outputFromAppItself = false;
+
+ QString newOutput = m_process.readAll();
+ m_output.append(newOutput);
+ m_outputBuffer.append(newOutput);
+
+ while (true) {
+ const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n'));
+ if (nlIndex < 0) // no further complete lines
+ break;
+ const QString line = m_outputBuffer.left(nlIndex);
+ m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1);
+
+ if (line.contains("QML Debugger:")) {
+ const QRegExp portRx("Waiting for connection on port (\\d+)");
+ if (portRx.indexIn(line) != -1) {
+ m_port = portRx.cap(1).toInt();
+ m_timer.stop();
+ m_state = SessionStarted;
+ m_eventLoop.quit();
+ continue;
+ }
+ if (line.contains("Unable to listen")) {
+ if (++m_receivedBindErrors >= m_maximumBindErrors) {
+ if (m_maximumBindErrors == 0)
+ qWarning() << "App was unable to bind to port!";
+ m_timer.stop();
+ m_state = SessionFailed;
+ m_eventLoop.quit();
+ }
+ continue;
+ }
+ }
+
+ // set to true if there is output not coming from the debugger or we don't understand it
+ outputFromAppItself = true;
+ }
+ m_mutex.unlock();
+
+ if (outputFromAppItself)
+ emit readyReadStandardOutput();
+}
+
+void QQmlDebugProcess::processError(QProcess::ProcessError error)
+{
+ qDebug() << "An error occurred while waiting for debug process to become available:";
+ switch (error) {
+ case QProcess::FailedToStart:
+ qDebug() << "Process failed to start.";
+ break;
+ case QProcess::Crashed:
+ qDebug() << "Process crashed.";
+ break;
+ case QProcess::Timedout:
+ qDebug() << "Process timed out.";
+ break;
+ case QProcess::WriteError:
+ qDebug() << "Error while writing to process.";
+ break;
+ case QProcess::ReadError:
+ qDebug() << "Error while reading from process.";
+ break;
+ case QProcess::UnknownError:
+ qDebug() << "Unknown process error.";
+ break;
+ }
+}
diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h
new file mode 100644
index 0000000000..945cc58c85
--- /dev/null
+++ b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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$
+**
+****************************************************************************/
+
+#ifndef QQMLDEBUGPROCESS_P_H
+#define QQMLDEBUGPROCESS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qprocess.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qmutex.h>
+
+class QQmlDebugProcess : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDebugProcess(const QString &executable, QObject *parent = 0);
+ ~QQmlDebugProcess();
+
+ QString stateString() const;
+
+ void addEnvironment(const QString &environment);
+
+ void start(const QStringList &arguments);
+ bool waitForSessionStart();
+ int debugPort() const;
+
+ bool waitForFinished();
+ QProcess::ProcessState state() const;
+ QProcess::ExitStatus exitStatus() const;
+
+ QString output() const;
+ void stop();
+ void setMaximumBindErrors(int numErrors);
+
+signals:
+ void readyReadStandardOutput();
+ void finished();
+
+private slots:
+ void timeout();
+ void processAppOutput();
+ void processError(QProcess::ProcessError error);
+
+private:
+ enum SessionState {
+ SessionUnknown,
+ SessionStarted,
+ SessionFailed
+ };
+
+ QString m_executable;
+ QProcess m_process;
+ QString m_outputBuffer;
+ QString m_output;
+ QTimer m_timer;
+ QEventLoop m_eventLoop;
+ QMutex m_mutex;
+ SessionState m_state;
+ QStringList m_environment;
+ int m_port;
+ int m_maximumBindErrors;
+ int m_receivedBindErrors;
+};
+
+#endif // QQMLDEBUGPROCESS_P_H
diff --git a/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp b/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
index 4dce07d824..896ed608fd 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
@@ -48,5 +48,4 @@ void QQmlDebugTestService::stateAboutToBeChanged(QQmlDebugService::State)
void QQmlDebugTestService::stateChanged(State)
{
Q_ASSERT(QThread::currentThread() != thread());
- emit stateHasChanged();
}
diff --git a/tests/auto/qml/debugger/shared/qqmldebugtestservice.h b/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
index 37b4a9f98c..9c39c0893d 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
+++ b/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
@@ -38,9 +38,6 @@ class QQmlDebugTestService : public QQmlDebugService
public:
QQmlDebugTestService(const QString &s, float version = 1, QObject *parent = 0);
-signals:
- void stateHasChanged();
-
protected:
virtual void messageReceived(const QByteArray &ba);
virtual void stateAboutToBeChanged(State state);
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
deleted file mode 100644
index c0252a0290..0000000000
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
+++ /dev/null
@@ -1,508 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module 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 "qqmlenginedebugclient.h"
-#include <private/qqmldebugconnection_p.h>
-
-struct QmlObjectData {
- QUrl url;
- int lineNumber;
- int columnNumber;
- QString idString;
- QString objectName;
- QString objectType;
- int objectId;
- int contextId;
- int parentId;
-};
-
-QPacket &operator>>(QPacket &ds, QmlObjectData &data)
-{
- ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
- >> data.objectName >> data.objectType >> data.objectId >> data.contextId
- >> data.parentId;
- return ds;
-}
-
-struct QmlObjectProperty {
- enum Type { Unknown, Basic, Object, List, SignalProperty };
- Type type;
- QString name;
- QVariant value;
- QString valueTypeName;
- QString binding;
- bool hasNotifySignal;
-};
-
-QPacket &operator>>(QPacket &ds, QmlObjectProperty &data)
-{
- int type;
- ds >> type >> data.name >> data.value >> data.valueTypeName
- >> data.binding >> data.hasNotifySignal;
- data.type = (QmlObjectProperty::Type)type;
- return ds;
-}
-
-QQmlEngineDebugClient::QQmlEngineDebugClient(
- QQmlDebugConnection *connection)
- : QQmlDebugClient(QLatin1String("QmlDebugger"), connection),
- m_nextId(0),
- m_valid(false)
-{
-}
-
-quint32 QQmlEngineDebugClient::addWatch(
- const QmlDebugPropertyReference &property, bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("WATCH_PROPERTY") << id << property.objectDebugId
- << property.name.toUtf8();
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::addWatch(
- const QmlDebugContextReference &, const QString &, bool *success)
-{
- *success = false;
- qWarning("QQmlEngineDebugClient::addWatch(): Not implemented");
- return 0;
-}
-
-quint32 QQmlEngineDebugClient::addWatch(
- const QmlDebugObjectReference &object, const QString &expr,
- bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("WATCH_EXPR_OBJECT") << id << object.debugId << expr;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::addWatch(
- const QmlDebugObjectReference &object, bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("WATCH_OBJECT") << id << object.debugId;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::addWatch(
- const QmlDebugFileReference &, bool *success)
-{
- *success = false;
- qWarning("QQmlEngineDebugClient::addWatch(): Not implemented");
- return 0;
-}
-
-void QQmlEngineDebugClient::removeWatch(quint32 id, bool *success)
-{
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("NO_WATCH") << id;
- sendMessage(ds.data());
- *success = true;
- }
-}
-
-quint32 QQmlEngineDebugClient::queryAvailableEngines(bool *success)
-{
- m_engines.clear();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("LIST_ENGINES") << id;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryRootContexts(
- const QmlDebugEngineReference &engine, bool *success)
-{
- m_rootContext = QmlDebugContextReference();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && engine.debugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("LIST_OBJECTS") << id << engine.debugId;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryObject(
- const QmlDebugObjectReference &object, bool *success)
-{
- m_object = QmlDebugObjectReference();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && object.debugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("FETCH_OBJECT") << id << object.debugId << false << true;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryObjectsForLocation(
- const QString &file, int lineNumber, int columnNumber, bool *success)
-{
- m_objects.clear();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber
- << columnNumber << false << true;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryObjectRecursive(
- const QmlDebugObjectReference &object, bool *success)
-{
- m_object = QmlDebugObjectReference();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && object.debugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("FETCH_OBJECT") << id << object.debugId << true << true;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryObjectsForLocationRecursive(const QString &file,
- int lineNumber, int columnNumber, bool *success)
-{
- m_objects.clear();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("FETCH_OBJECTS_FOR_LOCATION") << id << file << lineNumber
- << columnNumber << true << true;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryExpressionResult(
- int objectDebugId, const QString &expr, bool *success)
-{
- m_exprResult = QVariant();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr
- << engines()[0].debugId;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::queryExpressionResultBC(
- int objectDebugId, const QString &expr, bool *success)
-{
- m_exprResult = QVariant();
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::setBindingForObject(
- int objectDebugId,
- const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QString source, int line,
- bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("SET_BINDING") << id << objectDebugId << propertyName
- << bindingExpression << isLiteralValue << source << line;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::resetBindingForObject(
- int objectDebugId,
- const QString &propertyName,
- bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("RESET_BINDING") << id << objectDebugId << propertyName;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-quint32 QQmlEngineDebugClient::setMethodBody(
- int objectDebugId, const QString &methodName,
- const QString &methodBody, bool *success)
-{
- quint32 id = -1;
- *success = false;
- if (state() == QQmlDebugClient::Enabled && objectDebugId != -1) {
- id = getId();
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("SET_METHOD_BODY") << id << objectDebugId
- << methodName << methodBody;
- sendMessage(ds.data());
- *success = true;
- }
- return id;
-}
-
-void QQmlEngineDebugClient::decode(QPacket &ds,
- QmlDebugObjectReference &o,
- bool simple)
-{
- QmlObjectData data;
- ds >> data;
- o.debugId = data.objectId;
- o.className = data.objectType;
- o.idString = data.idString;
- o.name = data.objectName;
- o.source.url = data.url;
- o.source.lineNumber = data.lineNumber;
- o.source.columnNumber = data.columnNumber;
- o.contextDebugId = data.contextId;
-
- if (simple)
- return;
-
- int childCount;
- bool recur;
- ds >> childCount >> recur;
-
- for (int ii = 0; ii < childCount; ++ii) {
- o.children.append(QmlDebugObjectReference());
- decode(ds, o.children.last(), !recur);
- }
-
- int propCount;
- ds >> propCount;
-
- for (int ii = 0; ii < propCount; ++ii) {
- QmlObjectProperty data;
- ds >> data;
- QmlDebugPropertyReference prop;
- prop.objectDebugId = o.debugId;
- prop.name = data.name;
- prop.binding = data.binding;
- prop.hasNotifySignal = data.hasNotifySignal;
- prop.valueTypeName = data.valueTypeName;
- switch (data.type) {
- case QmlObjectProperty::Basic:
- case QmlObjectProperty::List:
- case QmlObjectProperty::SignalProperty:
- {
- prop.value = data.value;
- break;
- }
- case QmlObjectProperty::Object:
- {
- QmlDebugObjectReference obj;
- obj.debugId = prop.value.toInt();
- obj.className = prop.valueTypeName;
- prop.value = qVariantFromValue(obj);
- break;
- }
- case QmlObjectProperty::Unknown:
- break;
- }
- o.properties << prop;
- }
-}
-
-void QQmlEngineDebugClient::decode(QPacket &ds,
- QList<QmlDebugObjectReference> &o,
- bool simple)
-{
- int count;
- ds >> count;
- for (int i = 0; i < count; i++) {
- QmlDebugObjectReference obj;
- decode(ds, obj, simple);
- o << obj;
- }
-}
-
-void QQmlEngineDebugClient::decode(QPacket &ds,
- QmlDebugContextReference &c)
-{
- ds >> c.name >> c.debugId;
-
- int contextCount;
- ds >> contextCount;
-
- for (int ii = 0; ii < contextCount; ++ii) {
- c.contexts.append(QmlDebugContextReference());
- decode(ds, c.contexts.last());
- }
-
- int objectCount;
- ds >> objectCount;
-
- for (int ii = 0; ii < objectCount; ++ii) {
- QmlDebugObjectReference obj;
- decode(ds, obj, true);
-
- obj.contextDebugId = c.debugId;
- c.objects << obj;
- }
-}
-
-void QQmlEngineDebugClient::messageReceived(const QByteArray &data)
-{
- m_valid = false;
- QPacket ds(connection()->currentDataStreamVersion(), data);
-
- int queryId;
- QByteArray type;
- ds >> type >> queryId;
-
- //qDebug() << "QQmlEngineDebugPrivate::message()" << type;
-
- if (type == "LIST_ENGINES_R") {
- int count;
- ds >> count;
-
- m_engines.clear();
- for (int ii = 0; ii < count; ++ii) {
- QmlDebugEngineReference eng;
- ds >> eng.name;
- ds >> eng.debugId;
- m_engines << eng;
- }
- } else if (type == "LIST_OBJECTS_R") {
- if (!ds.atEnd())
- decode(ds, m_rootContext);
-
- } else if (type == "FETCH_OBJECT_R") {
- if (!ds.atEnd())
- decode(ds, m_object, false);
-
- } else if (type == "FETCH_OBJECTS_FOR_LOCATION_R") {
- if (!ds.atEnd())
- decode(ds, m_objects, false);
-
- } else if (type == "EVAL_EXPRESSION_R") {;
- ds >> m_exprResult;
-
- } else if (type == "WATCH_PROPERTY_R") {
- ds >> m_valid;
-
- } else if (type == "WATCH_OBJECT_R") {
- ds >> m_valid;
-
- } else if (type == "WATCH_EXPR_OBJECT_R") {
- ds >> m_valid;
-
- } else if (type == "UPDATE_WATCH") {
- int debugId;
- QByteArray name;
- QVariant value;
- ds >> debugId >> name >> value;
- emit valueChanged(name, value);
- return;
-
- } else if (type == "OBJECT_CREATED") {
- int engineId, objectId, parentId;
- ds >> engineId >> objectId >> parentId;
- emit newObject(objectId);
- return;
- } else if (type == "SET_BINDING_R") {
- ds >> m_valid;
- } else if (type == "RESET_BINDING_R") {
- ds >> m_valid;
- } else if (type == "SET_METHOD_BODY_R") {
- ds >> m_valid;
- } else if (type == "NO_WATCH_R") {
- ds >> m_valid;
- }
- emit result();
-}
-
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h
deleted file mode 100644
index 5d74f2d43c..0000000000
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module 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$
-**
-****************************************************************************/
-
-#ifndef QQMLENGINEDEBUGCLIENT_H
-#define QQMLENGINEDEBUGCLIENT_H
-
-#include <private/qqmldebugclient_p.h>
-#include <private/qpacket_p.h>
-
-#include <QtCore/qurl.h>
-#include <QtCore/qvariant.h>
-
-struct QmlDebugPropertyReference
-{
- QmlDebugPropertyReference()
- : objectDebugId(-1), hasNotifySignal(false)
- {
- }
-
- QmlDebugPropertyReference &operator=(
- const QmlDebugPropertyReference &o)
- {
- objectDebugId = o.objectDebugId; name = o.name; value = o.value;
- valueTypeName = o.valueTypeName; binding = o.binding;
- hasNotifySignal = o.hasNotifySignal;
- return *this;
- }
-
- int objectDebugId;
- QString name;
- QVariant value;
- QString valueTypeName;
- QString binding;
- bool hasNotifySignal;
-};
-
-struct QmlDebugFileReference
-{
- QmlDebugFileReference()
- : lineNumber(-1), columnNumber(-1)
- {
- }
-
- QmlDebugFileReference &operator=(
- const QmlDebugFileReference &o)
- {
- url = o.url; lineNumber = o.lineNumber; columnNumber = o.columnNumber;
- return *this;
- }
-
- QUrl url;
- int lineNumber;
- int columnNumber;
-};
-
-struct QmlDebugObjectReference
-{
- QmlDebugObjectReference()
- : debugId(-1), contextDebugId(-1)
- {
- }
-
- QmlDebugObjectReference(int id)
- : debugId(id), contextDebugId(-1)
- {
- }
-
- QmlDebugObjectReference &operator=(
- const QmlDebugObjectReference &o)
- {
- debugId = o.debugId; className = o.className; idString = o.idString;
- name = o.name; source = o.source; contextDebugId = o.contextDebugId;
- properties = o.properties; children = o.children;
- return *this;
- }
- int debugId;
- QString className;
- QString idString;
- QString name;
- QmlDebugFileReference source;
- int contextDebugId;
- QList<QmlDebugPropertyReference> properties;
- QList<QmlDebugObjectReference> children;
-};
-
-Q_DECLARE_METATYPE(QmlDebugObjectReference)
-
-struct QmlDebugContextReference
-{
- QmlDebugContextReference()
- : debugId(-1)
- {
- }
-
- QmlDebugContextReference &operator=(
- const QmlDebugContextReference &o)
- {
- debugId = o.debugId; name = o.name; objects = o.objects;
- contexts = o.contexts;
- return *this;
- }
-
- int debugId;
- QString name;
- QList<QmlDebugObjectReference> objects;
- QList<QmlDebugContextReference> contexts;
-};
-
-struct QmlDebugEngineReference
-{
- QmlDebugEngineReference()
- : debugId(-1)
- {
- }
-
- QmlDebugEngineReference(int id)
- : debugId(id)
- {
- }
-
- QmlDebugEngineReference &operator=(
- const QmlDebugEngineReference &o)
- {
- debugId = o.debugId; name = o.name;
- return *this;
- }
-
- int debugId;
- QString name;
-};
-
-class QQmlEngineDebugClient : public QQmlDebugClient
-{
- Q_OBJECT
-public:
- explicit QQmlEngineDebugClient(QQmlDebugConnection *conn);
-
- quint32 addWatch(const QmlDebugPropertyReference &,
- bool *success);
- quint32 addWatch(const QmlDebugContextReference &, const QString &,
- bool *success);
- quint32 addWatch(const QmlDebugObjectReference &, const QString &,
- bool *success);
- quint32 addWatch(const QmlDebugObjectReference &,
- bool *success);
- quint32 addWatch(const QmlDebugFileReference &,
- bool *success);
-
- void removeWatch(quint32 watch, bool *success);
-
- quint32 queryAvailableEngines(bool *success);
- quint32 queryRootContexts(const QmlDebugEngineReference &,
- bool *success);
- quint32 queryObject(const QmlDebugObjectReference &,
- bool *success);
- quint32 queryObjectsForLocation(const QString &file,
- int lineNumber, int columnNumber, bool *success);
- quint32 queryObjectRecursive(const QmlDebugObjectReference &,
- bool *success);
- quint32 queryObjectsForLocationRecursive(const QString &file,
- int lineNumber, int columnNumber, bool *success);
- quint32 queryExpressionResult(int objectDebugId,
- const QString &expr,
- bool *success);
- quint32 queryExpressionResultBC(int objectDebugId,
- const QString &expr,
- bool *success);
- quint32 setBindingForObject(int objectDebugId, const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QString source, int line, bool *success);
- quint32 resetBindingForObject(int objectDebugId,
- const QString &propertyName, bool *success);
- quint32 setMethodBody(int objectDebugId, const QString &methodName,
- const QString &methodBody, bool *success);
-
- quint32 getId() { return m_nextId++; }
-
- void decode(QPacket &ds, QmlDebugContextReference &);
- void decode(QPacket &ds, QmlDebugObjectReference &, bool simple);
- void decode(QPacket &ds, QList<QmlDebugObjectReference> &o, bool simple);
-
- QList<QmlDebugEngineReference> engines() { return m_engines; }
- QmlDebugContextReference rootContext() { return m_rootContext; }
- QmlDebugObjectReference object() { return m_object; }
- QList<QmlDebugObjectReference> objects() { return m_objects; }
- QVariant resultExpr() { return m_exprResult; }
- bool valid() { return m_valid; }
-
-signals:
- void newObject(int objectId);
- void valueChanged(QByteArray,QVariant);
- void result();
-
-protected:
- void messageReceived(const QByteArray &);
-
-private:
- quint32 m_nextId;
- bool m_valid;
- QList<QmlDebugEngineReference> m_engines;
- QmlDebugContextReference m_rootContext;
- QmlDebugObjectReference m_object;
- QList<QmlDebugObjectReference> m_objects;
- QVariant m_exprResult;
-};
-
-#endif // QQMLENGINEDEBUGCLIENT_H
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.pri b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.pri
deleted file mode 100644
index a969b4f153..0000000000
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.pri
+++ /dev/null
@@ -1,3 +0,0 @@
-HEADERS += $$PWD/qqmlenginedebugclient.h
-
-SOURCES += $$PWD/qqmlenginedebugclient.cpp
diff --git a/tests/auto/qml/debugger/shared/qqmlinspectorclient.cpp b/tests/auto/qml/debugger/shared/qqmlinspectorclient.cpp
deleted file mode 100644
index 20faef177e..0000000000
--- a/tests/auto/qml/debugger/shared/qqmlinspectorclient.cpp
+++ /dev/null
@@ -1,124 +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 "qqmlinspectorclient.h"
-
-#include <private/qpacket_p.h>
-#include <private/qqmldebugconnection_p.h>
-#include <QtCore/qdebug.h>
-
-QQmlInspectorClient::QQmlInspectorClient(QQmlDebugConnection *connection) :
- QQmlDebugClient(QLatin1String("QmlInspector"), connection),
- m_lastRequestId(-1)
-{
-}
-
-int QQmlInspectorClient::setInspectToolEnabled(bool enabled)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray(enabled ? "enable" : "disable");
-
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::setShowAppOnTop(bool showOnTop)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("showAppOnTop") << showOnTop;
-
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::setAnimationSpeed(qreal speed)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("setAnimationSpeed") << speed;
-
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::select(const QList<int> &objectIds)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("select") << objectIds;
-
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::createObject(const QString &qml, int parentId, const QStringList &imports,
- const QString &filename)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("createObject") << qml << parentId << imports << filename;
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::moveObject(int childId, int newParentId)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("moveObject") << childId << newParentId;
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-int QQmlInspectorClient::destroyObject(int objectId)
-{
- QPacket ds(connection()->currentDataStreamVersion());
- ds << QByteArray("request") << ++m_lastRequestId
- << QByteArray("destroyObject") << objectId;
- sendMessage(ds.data());
- return m_lastRequestId;
-}
-
-void QQmlInspectorClient::messageReceived(const QByteArray &message)
-{
- QPacket ds(connection()->currentDataStreamVersion(), message);
- QByteArray type;
- ds >> type;
-
- if (type != QByteArray("response")) {
- qDebug() << "Unhandled message of type" << type;
- return;
- }
-
- int responseId;
- bool result;
- ds >> responseId >> result;
- emit responseReceived(responseId, result);
-}
diff --git a/tests/auto/qml/debugger/shared/qqmlinspectorclient.pri b/tests/auto/qml/debugger/shared/qqmlinspectorclient.pri
deleted file mode 100644
index c136e1313a..0000000000
--- a/tests/auto/qml/debugger/shared/qqmlinspectorclient.pri
+++ /dev/null
@@ -1,3 +0,0 @@
-HEADERS += $$PWD/qqmlinspectorclient.h
-
-SOURCES += $$PWD/qqmlinspectorclient.cpp
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 27498de473..0e0d70845b 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -1,178 +1,720 @@
-# wrong tests
-# uses octal number
-15.2.3.6-2-17-1 failing
+# ----- These are tests we will not fix
-# these fail after the update to Unicode 6.3.
-# the reason is that u+180e changed type from whitespace to control
-S9.3.1_A2
-S9.3.1_A3_T1
-S9.3.1_A3_T2
-S15.1.2.2_A2_T10
-S15.1.2.3_A2_T10
-15.5.4.20-3-2
-15.5.4.20-3-3
-15.5.4.20-3-4
-15.5.4.20-3-5
-15.5.4.20-3-6
+# The tests below rely on the ES6 spec quirk that allows 'let' as an identifier. We've
+# always treated 'let' as a reserved keyword (without ever getting a bug report about it),
+# so we'll keep it that way. It also removes a huge headache in the parser.
+language/statements/for-in/let-block-with-newline.js sloppyFails
+language/statements/for-of/let-block-with-newline.js sloppyFails
+language/statements/for/let-block-with-newline.js sloppyFails
+language/statements/if/let-block-with-newline.js sloppyFails
+language/statements/labeled/let-block-with-newline.js sloppyFails
+language/statements/while/let-block-with-newline.js sloppyFails
+language/statements/with/let-block-with-newline.js sloppyFails
+language/statements/for-in/let-identifier-with-newline.js sloppyFails
+language/statements/for-of/let-identifier-with-newline.js sloppyFails
+language/statements/for/let-identifier-with-newline.js sloppyFails
+language/statements/if/let-identifier-with-newline.js sloppyFails
+language/statements/labeled/let-identifier-with-newline.js sloppyFails
+language/statements/while/let-identifier-with-newline.js sloppyFails
+language/statements/with/let-identifier-with-newline.js sloppyFails
-10.4.3-1-106 failing
-11.2.3-3_3 failing
-S13_A15_T4 failing
-S15.4.4.3_A1_T1 failing
-S15.4.4.3_A3_T1 failing
-S15.5.4.11_A5_T1 failing
-S15.2.4.4_A14 failing
+# The ES6/7 spec says that [[DefineOwnProperty]] on the module namespace exotic object
+# always returns false. This was changed in https://github.com/tc39/ecma262/pull/858
+# but it's not in the published spec yet.
+language/module-code/namespace/internals/define-own-property.js strictFails
+# This test includes the above and therefore also fails.
+language/module-code/namespace/internals/set.js strictFails
-# Function declarations in conditionals. We allow them, because the real
-# world requires them.
-Sbp_12.5_A9_T3 failing
-Sbp_12.6.1_A13_T3 failing
-Sbp_12.6.2_A13_T3 failing
-Sbp_12.6.4_A13_T3 failing
-
-# es6: function length attributes are configurable, wasn't in es5
-S15.1.2.2_A9.2 failing
-S15.1.3.1_A5.2 failing
-S15.1.3.2_A5.2 failing
-S15.1.3.3_A5.2 failing
-S15.1.2.3_A7.2 failing
-S15.1.2.4_A2.2 failing
-S15.1.2.5_A2.2 failing
-S15.1.3.4_A5.2 failing
-15.2.3.3-4-186 failing
-S15.2.4.2_A9 failing
-S15.2.4.3_A9 failing
-S15.2.4.4_A9 failing
-S15.2.4.5_A9 failing
-S15.2.4.6_A9 failing
-S15.2.4.7_A9 failing
-15.3.3.2-1 failing
-15.4.4.2_A4.2
-S15.3.4.2_A9 failing
-S15.3.4.3_A9 failing
-S15.3.4.4_A9 failing
-15.3.4.5-15-2 failing
-S15.4.4.2_A4.2 failing
-S15.4.4.3_A4.2 failing
-S15.4.4.4_A4.2 failing
-S15.4.4.5_A6.2 failing
-S15.4.4.6_A5.2 failing
-S15.4.4.7_A6.2 failing
-S15.4.4.8_A5.2 failing
-S15.4.4.9_A5.2 failing
-S15.4.4.10_A5.2 failing
-S15.4.4.11_A7.2 failing
-S15.4.4.12_A5.2 failing
-S15.4.4.13_A5.2 failing
-S15.5.4.10_A9 failing
-S15.5.4.11_A9 failing
-S15.5.4.12_A9 failing
-S15.5.4.13_A9 failing
-S15.5.4.14_A9 failing
-S15.5.4.15_A9 failing
-S15.5.4.16_A9 failing
-S15.5.4.17_A9 failing
-S15.5.4.18_A9 failing
-S15.5.4.19_A9 failing
-S15.5.4.4_A9 failing
-S15.5.4.5_A9 failing
-S15.5.4.6_A9 failing
-S15.5.4.7_A9 failing
-S15.5.4.8_A9 failing
-S15.5.4.9_A9 failing
-S15.9.4.2_A3_T2 failing
-S15.9.4.3_A3_T2 failing
-S15.9.5.2_A3_T2 failing
-S15.9.5.3_A3_T2 failing
-S15.9.5.4_A3_T2 failing
-S15.9.5.5_A3_T2 failing
-S15.9.5.1_A3_T2 failing
-S15.9.5.10_A3_T2 failing
-S15.9.5.11_A3_T2 failing
-S15.9.5.12_A3_T2 failing
-S15.9.5.13_A3_T2 failing
-S15.9.5.14_A3_T2 failing
-S15.9.5.15_A3_T2 failing
-S15.9.5.16_A3_T2 failing
-S15.9.5.17_A3_T2 failing
-S15.9.5.18_A3_T2 failing
-S15.9.5.19_A3_T2 failing
-S15.9.5.20_A3_T2 failing
-S15.9.5.21_A3_T2 failing
-S15.9.5.22_A3_T2 failing
-S15.9.5.23_A3_T2 failing
-S15.9.5.24_A3_T2 failing
-S15.9.5.25_A3_T2 failing
-S15.9.5.26_A3_T2 failing
-S15.9.5.27_A3_T2 failing
-S15.9.5.28_A3_T2 failing
-S15.9.5.29_A3_T2 failing
-S15.9.5.30_A3_T2 failing
-S15.9.5.31_A3_T2 failing
-S15.9.5.32_A3_T2 failing
-S15.9.5.33_A3_T2 failing
-S15.9.5.34_A3_T2 failing
-S15.9.5.35_A3_T2 failing
-S15.9.5.36_A3_T2 failing
-S15.9.5.37_A3_T2 failing
-S15.9.5.38_A3_T2 failing
-S15.9.5.39_A3_T2 failing
-S15.9.5.40_A3_T2 failing
-S15.9.5.41_A3_T2 failing
-S15.9.5.42_A3_T2 failing
-S15.9.5.6_A3_T2 failing
-S15.9.5.7_A3_T2 failing
-S15.9.5.8_A3_T2 failing
-S15.9.5.9_A3_T2 failing
-S15.10.6.2_A9 failing
-S15.10.6.3_A9 failing
-S15.10.6.4_A9 failing
-
-# es6: Object.freeze(v) on a non-object returns v, no longer TypeError
-15.2.3.9-1 failing
-15.2.3.9-1-1 failing
-15.2.3.9-1-2 failing
-15.2.3.9-1-3 failing
-15.2.3.9-1-4 failing
-# es6: Object.preventExtensions(O) on a non-object, no longer TypeError
-15.2.3.10-1 failing
-15.2.3.10-1-3 failing
-15.2.3.10-1-4 failing
-# es6: Object.isSealed(O) on a non-object, no longer TypeError
-15.2.3.11-1
-# es6: Object.isFrozen(O) on a non-object, no longer TypeError
-15.2.3.12-1
-15.2.3.12-1-3
-15.2.3.12-1-4
-# es6: Object.isExtensible(O) on a non-object, no longer TypeError
-15.2.3.13-1
-15.2.3.13-1-3
-15.2.3.13-1-4
-# es6: Object.keys(O) on a non-object, no longer TypeError
-15.2.3.14-1-1
-15.2.3.14-1-2
-15.2.3.14-1-3
-15.2.3.14-1
-15.2.3.14-2
-15.2.3.14-3
-# es6: Object.getOwnPropertyDescriptor(O) on a non-object, no longer TypeError
-15.2.3.3-1
-15.2.3.3-1-3
-15.2.3.3-1-4
-# es6: Object.getPrototypeOf(O) on a non-object, no longer TypeError
-15.2.3.2-1
-15.2.3.2-1-3
-15.2.3.2-1-4
-# es6: Object.getOwnPropertyNames(O) on a non-object, no longer TypeError
-15.2.3.4-1
-15.2.3.4-1-4
-15.2.3.4-1-5
-# es6: Object.seal(O) on a non-object, no longer TypeError
-15.2.3.8-1
-15.2.3.8-1-1
-15.2.3.8-1-2
-15.2.3.8-1-3
-15.2.3.8-1-4
-
-# es6: Date.prototype is no longer a DateObject
-15.9.5.40_1 failing
+# ----- test failures that should be fixed
+built-ins/Array/prototype/concat/Array.prototype.concat_large-typed-array.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-with-dupes.js sloppyFails
+built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_small-typed-array.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-function.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-reg-exp.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-sparse-object.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_strict-arguments.js fails
+built-ins/Array/prototype/concat/S15.4.4.4_A3_T1.js fails
+built-ins/Array/prototype/concat/S15.4.4.4_A3_T2.js fails
+built-ins/Array/prototype/concat/S15.4.4.4_A3_T3.js fails
+built-ins/Array/prototype/concat/create-ctor-non-object.js fails
+built-ins/Array/prototype/concat/create-ctor-poisoned.js fails
+built-ins/Array/prototype/concat/create-proxy.js fails
+built-ins/Array/prototype/concat/create-species-abrupt.js fails
+built-ins/Array/prototype/concat/create-species-non-ctor.js fails
+built-ins/Array/prototype/concat/create-species-poisoned.js fails
+built-ins/Array/prototype/concat/create-species.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-val-falsey.js fails
+built-ins/Array/prototype/copyWithin/return-abrupt-from-has-start.js fails
+built-ins/Array/prototype/every/15.4.4.16-3-29.js fails
+built-ins/Array/prototype/filter/create-ctor-non-object.js fails
+built-ins/Array/prototype/filter/create-ctor-poisoned.js fails
+built-ins/Array/prototype/filter/create-proxy.js fails
+built-ins/Array/prototype/filter/create-species-abrupt.js fails
+built-ins/Array/prototype/filter/create-species-non-ctor.js fails
+built-ins/Array/prototype/filter/create-species-poisoned.js fails
+built-ins/Array/prototype/filter/create-species.js fails
+built-ins/Array/prototype/includes/length-boundaries.js fails
+built-ins/Array/prototype/indexOf/15.4.4.14-3-28.js fails
+built-ins/Array/prototype/indexOf/15.4.4.14-3-29.js fails
+built-ins/Array/prototype/join/S15.4.4.5_A4_T3.js fails
+built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-28.js fails
+built-ins/Array/prototype/map/create-ctor-non-object.js fails
+built-ins/Array/prototype/map/create-ctor-poisoned.js fails
+built-ins/Array/prototype/map/create-proxy.js fails
+built-ins/Array/prototype/map/create-species-abrupt.js fails
+built-ins/Array/prototype/map/create-species-non-ctor.js fails
+built-ins/Array/prototype/map/create-species-poisoned.js fails
+built-ins/Array/prototype/map/create-species.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A2_T2.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A3_T1.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A3_T2.js fails
+built-ins/Array/prototype/pop/clamps-to-integer-limit.js fails
+built-ins/Array/prototype/pop/length-near-integer-limit.js fails
+built-ins/Array/prototype/push/S15.4.4.7_A2_T2.js fails
+built-ins/Array/prototype/push/S15.4.4.7_A3.js fails
+built-ins/Array/prototype/push/throws-if-integer-limit-exceeded.js fails
+built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js fails
+built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js fails
+built-ins/Array/prototype/slice/S15.4.4.10_A3_T1.js fails
+built-ins/Array/prototype/slice/S15.4.4.10_A3_T2.js fails
+built-ins/Array/prototype/slice/create-ctor-non-object.js fails
+built-ins/Array/prototype/slice/create-ctor-poisoned.js fails
+built-ins/Array/prototype/slice/create-non-array-invalid-len.js fails
+built-ins/Array/prototype/slice/create-proxied-array-invalid-len.js fails
+built-ins/Array/prototype/slice/create-proxy.js fails
+built-ins/Array/prototype/slice/create-species-abrupt.js fails
+built-ins/Array/prototype/slice/create-species-neg-zero.js fails
+built-ins/Array/prototype/slice/create-species-non-ctor.js fails
+built-ins/Array/prototype/slice/create-species-poisoned.js fails
+built-ins/Array/prototype/slice/create-species.js fails
+built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js fails
+built-ins/Array/prototype/slice/length-exceeding-integer-limit.js fails
+built-ins/Array/prototype/some/15.4.4.17-3-28.js fails
+built-ins/Array/prototype/some/15.4.4.17-3-29.js fails
+built-ins/Array/prototype/sort/comparefn-nonfunction-call-throws.js fails
+built-ins/Array/prototype/splice/S15.4.4.12_A3_T1.js fails
+built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js fails
+built-ins/Array/prototype/splice/create-ctor-non-object.js fails
+built-ins/Array/prototype/splice/create-ctor-poisoned.js fails
+built-ins/Array/prototype/splice/create-proxy.js fails
+built-ins/Array/prototype/splice/create-species-abrupt.js fails
+built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js fails
+built-ins/Array/prototype/splice/create-species-neg-zero.js fails
+built-ins/Array/prototype/splice/create-species-non-ctor.js fails
+built-ins/Array/prototype/splice/create-species-poisoned.js fails
+built-ins/Array/prototype/splice/create-species.js fails
+built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js fails
+built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js fails
+built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js fails
+built-ins/Array/prototype/toLocaleString/primitive_this_value.js strictFails
+built-ins/Array/prototype/toLocaleString/primitive_this_value_getter.js strictFails
+built-ins/Array/prototype/unshift/clamps-to-integer-limit.js fails
+built-ins/Array/prototype/unshift/length-near-integer-limit.js fails
+built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js fails
+built-ins/ArrayBuffer/data-allocation-after-object-creation.js fails
+built-ins/ArrayIteratorPrototype/next/detach-typedarray-in-progress.js fails
+built-ins/AsyncFunction/AsyncFunction-construct.js fails
+built-ins/AsyncFunction/AsyncFunction-is-extensible.js fails
+built-ins/AsyncFunction/AsyncFunction-is-subclass.js fails
+built-ins/AsyncFunction/AsyncFunction-length.js fails
+built-ins/AsyncFunction/AsyncFunction-name.js fails
+built-ins/AsyncFunction/AsyncFunction-prototype.js fails
+built-ins/AsyncFunction/AsyncFunction.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-is-extensible.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-prototype.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-to-string.js fails
+built-ins/AsyncFunction/instance-construct-throws.js fails
+built-ins/AsyncFunction/instance-has-name.js fails
+built-ins/AsyncFunction/instance-length.js fails
+built-ins/AsyncFunction/instance-prototype-property.js fails
+built-ins/AsyncGeneratorPrototype/next/name.js fails
+built-ins/AsyncGeneratorPrototype/return/name.js fails
+built-ins/AsyncGeneratorPrototype/throw/name.js fails
+built-ins/Atomics/wait/did-timeout.js fails
+built-ins/Atomics/wait/good-views.js fails
+built-ins/Atomics/wait/nan-timeout.js fails
+built-ins/Atomics/wait/negative-timeout.js fails
+built-ins/Atomics/wait/no-spurious-wakeup.js fails
+built-ins/Atomics/wait/was-woken.js fails
+built-ins/Atomics/wake/counts.js fails
+built-ins/Atomics/wake/wake-all-on-loc.js fails
+built-ins/Atomics/wake/wake-all.js fails
+built-ins/Atomics/wake/wake-in-order.js fails
+built-ins/Atomics/wake/wake-nan.js fails
+built-ins/Atomics/wake/wake-negative.js fails
+built-ins/Atomics/wake/wake-one.js fails
+built-ins/Atomics/wake/wake-two.js fails
+built-ins/Atomics/wake/wake-zero.js fails
+built-ins/DataView/custom-proto-access-throws.js fails
+built-ins/DataView/custom-proto-if-object-is-used.js fails
+built-ins/Date/prototype/toDateString/format.js fails
+built-ins/Date/prototype/toDateString/invalid-date.js fails
+built-ins/Date/prototype/toString/format.js fails
+built-ins/Date/prototype/toTimeString/format.js fails
+built-ins/Date/prototype/toTimeString/invalid-date.js fails
+built-ins/Date/prototype/toUTCString/day-names.js fails
+built-ins/Date/prototype/toUTCString/format.js fails
+built-ins/Date/prototype/toUTCString/month-names.js fails
+built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails
+built-ins/Function/prototype/Symbol.hasInstance/value-get-prototype-of-err.js fails
+built-ins/Function/prototype/bind/BoundFunction_restricted-properties.js fails
+built-ins/Function/prototype/bind/instance-name-chained.js fails
+built-ins/Function/prototype/bind/instance-name-error.js fails
+built-ins/Function/prototype/bind/instance-name-non-string.js fails
+built-ins/Function/prototype/bind/instance-name.js fails
+built-ins/Function/prototype/toString/AsyncFunction.js fails
+built-ins/Function/prototype/toString/async-arrow-function.js fails
+built-ins/Function/prototype/toString/async-function-declaration.js fails
+built-ins/Function/prototype/toString/async-function-expression.js fails
+built-ins/Function/prototype/toString/async-method-class-expression-static.js fails
+built-ins/Function/prototype/toString/async-method-class-expression.js fails
+built-ins/Function/prototype/toString/async-method-class-statement-static.js fails
+built-ins/Function/prototype/toString/async-method-class-statement.js fails
+built-ins/Function/prototype/toString/async-method-object.js fails
+built-ins/Function/prototype/toString/method-computed-property-name.js fails
+built-ins/JSON/parse/revived-proxy-revoked.js fails
+built-ins/JSON/parse/revived-proxy.js fails
+built-ins/JSON/parse/reviver-array-define-prop-err.js fails
+built-ins/JSON/parse/reviver-array-delete-err.js fails
+built-ins/JSON/parse/reviver-array-length-coerce-err.js fails
+built-ins/JSON/parse/reviver-array-length-get-err.js fails
+built-ins/JSON/parse/reviver-call-err.js fails
+built-ins/JSON/parse/reviver-get-name-err.js fails
+built-ins/JSON/parse/reviver-object-define-prop-err.js fails
+built-ins/JSON/parse/reviver-object-delete-err.js fails
+built-ins/JSON/parse/reviver-object-own-keys-err.js fails
+built-ins/JSON/stringify/replacer-proxy-revoked.js fails
+built-ins/JSON/stringify/replacer-proxy.js fails
+built-ins/JSON/stringify/value-proxy.js fails
+built-ins/Map/prototype/forEach/iterates-values-deleted-then-readded.js fails
+built-ins/Math/round/S15.8.2.15_A7.js fails
+built-ins/Number/prototype/toPrecision/return-values.js fails
+built-ins/Object/create/15.2.3.5-4-14.js strictFails
+built-ins/Object/create/15.2.3.5-4-37.js strictFails
+built-ins/Object/entries/getter-making-future-key-nonenumerable.js fails
+built-ins/Object/entries/getter-removing-future-key.js fails
+built-ins/Object/entries/observable-operations.js fails
+built-ins/Object/getOwnPropertyDescriptors/proxy-undefined-descriptor.js fails
+built-ins/Object/keys/proxy-keys.js fails
+built-ins/Object/proto-from-ctor.js fails
+built-ins/Object/prototype/toLocaleString/primitive_this_value_getter.js strictFails
+built-ins/Object/prototype/toString/proxy-array.js fails
+built-ins/Object/prototype/toString/proxy-function.js fails
+built-ins/Object/prototype/valueOf/S15.2.4.4_A14.js fails
+built-ins/Object/values/getter-adding-key.js fails
+built-ins/Object/values/observable-operations.js fails
+built-ins/Promise/prototype/catch/this-value-obj-coercible.js fails
+built-ins/Promise/prototype/then/capability-executor-not-callable.js fails
+built-ins/Promise/prototype/then/ctor-custom.js fails
+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/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
+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/unicode_restricted_brackets.js fails
+built-ins/RegExp/unicode_restricted_character_class_escape.js fails
+built-ins/RegExp/unicode_restricted_identity_escape.js fails
+built-ins/RegExp/unicode_restricted_identity_escape_alpha.js fails
+built-ins/RegExp/unicode_restricted_identity_escape_c.js fails
+built-ins/RegExp/unicode_restricted_incomple_quantifier.js fails
+built-ins/RegExp/unicode_restricted_octal_escape.js fails
+built-ins/RegExp/unicode_restricted_quantifiable_assertion.js fails
+built-ins/Set/prototype/forEach/iterates-values-revisits-after-delete-re-add.js fails
+built-ins/SharedArrayBuffer/data-allocation-after-object-creation.js fails
+built-ins/SharedArrayBuffer/prototype-from-newtarget.js fails
+built-ins/String/prototype/endsWith/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/includes/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/indexOf/position-tointeger-toprimitive.js fails
+built-ins/String/prototype/indexOf/position-tointeger.js fails
+built-ins/String/prototype/indexOf/searchstring-tostring-toprimitive.js fails
+built-ins/String/prototype/replace/cstm-replace-get-err.js fails
+built-ins/String/prototype/replace/cstm-replace-invocation.js fails
+built-ins/String/prototype/replace/this-value-not-obj-coercible.js fails
+built-ins/String/prototype/search/cstm-search-get-err.js fails
+built-ins/String/prototype/search/cstm-search-invocation.js fails
+built-ins/String/prototype/search/invoke-builtin-search-searcher-undef.js fails
+built-ins/String/prototype/search/invoke-builtin-search.js fails
+built-ins/String/prototype/slice/this-value-not-obj-coercible.js fails
+built-ins/String/prototype/split/cstm-split-get-err.js fails
+built-ins/String/prototype/split/cstm-split-invocation.js fails
+built-ins/String/prototype/startsWith/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/toLocaleLowerCase/Final_Sigma_U180E.js fails
+built-ins/String/prototype/toLocaleLowerCase/special_casing_conditional.js fails
+built-ins/String/prototype/toLowerCase/Final_Sigma_U180E.js fails
+built-ins/String/prototype/toLowerCase/special_casing_conditional.js fails
+built-ins/TypedArray/from/arylk-get-length-error.js fails
+built-ins/TypedArray/from/arylk-to-length-error.js fails
+built-ins/TypedArray/from/iter-access-error.js fails
+built-ins/TypedArray/from/iter-invoke-error.js fails
+built-ins/TypedArray/from/iter-next-error.js fails
+built-ins/TypedArray/from/iter-next-value-error.js fails
+built-ins/TypedArray/from/length.js fails
+built-ins/TypedArray/from/name.js fails
+built-ins/TypedArray/from/prop-desc.js fails
+built-ins/TypedArray/prototype/constructor.js fails
+built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails
+built-ins/TypedArray/prototype/slice/bit-precision.js fails
+built-ins/TypedArray/prototype/sort/arraylength-internal.js fails
+built-ins/TypedArray/prototype/sort/comparefn-call-throws.js fails
+built-ins/TypedArray/prototype/sort/comparefn-calls.js fails
+built-ins/TypedArray/prototype/sort/detached-buffer-comparefn.js fails
+built-ins/TypedArray/prototype/sort/invoked-as-func.js fails
+built-ins/TypedArray/prototype/sort/invoked-as-method.js fails
+built-ins/TypedArray/prototype/sort/length.js fails
+built-ins/TypedArray/prototype/sort/name.js fails
+built-ins/TypedArray/prototype/sort/prop-desc.js fails
+built-ins/TypedArray/prototype/sort/return-same-instance.js fails
+built-ins/TypedArray/prototype/sort/sortcompare-with-no-tostring.js fails
+built-ins/TypedArray/prototype/sort/sorted-values-nan.js fails
+built-ins/TypedArray/prototype/sort/sorted-values.js fails
+built-ins/TypedArrays/ctors/buffer-arg/defined-negative-length.js fails
+built-ins/TypedArrays/ctors/object-arg/as-generator-iterable-returns.js fails
+built-ins/TypedArrays/ctors/object-arg/iterating-throws.js fails
+built-ins/TypedArrays/ctors/object-arg/iterator-not-callable-throws.js fails
+built-ins/TypedArrays/ctors/object-arg/iterator-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-access-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-access-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-access-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js fails
+built-ins/TypedArrays/from/arylk-get-length-error.js fails
+built-ins/TypedArrays/from/arylk-to-length-error.js fails
+built-ins/TypedArrays/from/custom-ctor-returns-other-instance.js fails
+built-ins/TypedArrays/from/custom-ctor.js fails
+built-ins/TypedArrays/from/iter-access-error.js fails
+built-ins/TypedArrays/from/iter-invoke-error.js fails
+built-ins/TypedArrays/from/iter-next-error.js fails
+built-ins/TypedArrays/from/iter-next-value-error.js fails
+built-ins/TypedArrays/from/mapfn-abrupt-completion.js fails
+built-ins/TypedArrays/from/mapfn-arguments.js fails
+built-ins/TypedArrays/from/mapfn-this-with-thisarg.js fails
+built-ins/TypedArrays/from/mapfn-this-without-thisarg-non-strict.js sloppyFails
+built-ins/TypedArrays/from/mapfn-this-without-thisarg-strict.js strictFails
+built-ins/TypedArrays/from/nan-conversion.js fails
+built-ins/TypedArrays/from/new-instance-empty.js fails
+built-ins/TypedArrays/from/new-instance-from-ordinary-object.js fails
+built-ins/TypedArrays/from/new-instance-from-sparse-array.js fails
+built-ins/TypedArrays/from/new-instance-from-zero.js fails
+built-ins/TypedArrays/from/new-instance-using-custom-ctor.js fails
+built-ins/TypedArrays/from/new-instance-with-mapfn.js fails
+built-ins/TypedArrays/from/new-instance-without-mapfn.js fails
+built-ins/TypedArrays/from/property-abrupt-completion.js fails
+built-ins/TypedArrays/from/set-value-abrupt-completion.js fails
+built-ins/TypedArrays/internals/Get/key-is-not-integer.js fails
+built-ins/TypedArrays/internals/Get/key-is-not-minus-zero.js fails
+built-ins/TypedArrays/internals/Get/key-is-out-of-bounds.js fails
+built-ins/TypedArrays/internals/Set/detached-buffer.js fails
+built-ins/TypedArrays/internals/Set/tonumber-value-throws.js fails
+built-ins/global/global-object.js fails
+built-ins/global/property-descriptor.js fails
+built-ins/isFinite/toprimitive-not-callable-throws.js fails
+built-ins/isNaN/toprimitive-not-callable-throws.js fails
+language/computed-property-names/class/static/method-number.js fails
+language/computed-property-names/class/static/method-string.js fails
+language/computed-property-names/class/static/method-symbol.js fails
+language/eval-code/direct/new.target-arrow.js fails
+language/eval-code/direct/new.target.js fails
+language/eval-code/direct/non-definable-function-with-function.js sloppyFails
+language/eval-code/direct/non-definable-function-with-variable.js sloppyFails
+language/eval-code/direct/non-definable-global-function.js sloppyFails
+language/eval-code/direct/non-definable-global-generator.js sloppyFails
+language/eval-code/direct/super-call-arrow.js fails
+language/eval-code/direct/super-call-fn.js fails
+language/eval-code/direct/super-call-method.js fails
+language/eval-code/direct/super-call.js fails
+language/eval-code/direct/super-prop-arrow.js fails
+language/eval-code/direct/super-prop-dot-no-home.js fails
+language/eval-code/direct/super-prop-expr-no-home-no-eval.js fails
+language/eval-code/direct/super-prop-expr-no-home.js fails
+language/eval-code/direct/super-prop.js fails
+language/eval-code/direct/this-value-func-strict-source.js sloppyFails
+language/eval-code/direct/var-env-func-init-global-update-configurable.js sloppyFails
+language/eval-code/direct/var-env-global-lex-non-strict.js sloppyFails
+language/eval-code/direct/var-env-lower-lex-catch-non-strict.js sloppyFails
+language/eval-code/direct/var-env-lower-lex-non-strict.js sloppyFails
+language/eval-code/indirect/always-non-strict.js strictFails
+language/eval-code/indirect/new.target.js fails
+language/eval-code/indirect/non-definable-function-with-function.js sloppyFails
+language/eval-code/indirect/non-definable-function-with-variable.js sloppyFails
+language/eval-code/indirect/non-definable-global-function.js fails
+language/eval-code/indirect/non-definable-global-generator.js fails
+language/eval-code/indirect/non-definable-global-var.js strictFails
+language/eval-code/indirect/super-call.js fails
+language/eval-code/indirect/super-prop.js fails
+language/eval-code/indirect/this-value-func.js strictFails
+language/eval-code/indirect/var-env-func-init-global-new.js strictFails
+language/eval-code/indirect/var-env-func-init-global-update-configurable.js fails
+language/eval-code/indirect/var-env-func-init-multi.js strictFails
+language/eval-code/indirect/var-env-func-non-strict.js strictFails
+language/eval-code/indirect/var-env-global-lex-non-strict.js fails
+language/eval-code/indirect/var-env-var-init-global-exstng.js strictFails
+language/eval-code/indirect/var-env-var-init-global-new.js strictFails
+language/eval-code/indirect/var-env-var-non-strict.js strictFails
+language/expressions/arrow-function/dflt-params-ref-later.js fails
+language/expressions/arrow-function/dflt-params-ref-self.js fails
+language/expressions/arrow-function/lexical-super-call-from-within-constructor.js fails
+language/expressions/arrow-function/lexical-supercall-from-immediately-invoked-arrow.js fails
+language/expressions/arrow-function/scope-body-lex-distinct.js sloppyFails
+language/expressions/arrow-function/scope-param-elem-var-close.js sloppyFails
+language/expressions/arrow-function/scope-param-elem-var-open.js sloppyFails
+language/expressions/arrow-function/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/arrow-function/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/arrow-function/scope-paramsbody-var-open.js fails
+language/expressions/assignment/S11.13.1_A5_T1.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T2.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T3.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T4.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T5.js fails
+language/expressions/assignment/S11.13.1_A6_T1.js sloppyFails
+language/expressions/assignment/S11.13.1_A6_T2.js sloppyFails
+language/expressions/assignment/S11.13.1_A6_T3.js sloppyFails
+language/expressions/assignment/S11.13.1_A7_T1.js fails
+language/expressions/assignment/S11.13.1_A7_T2.js fails
+language/expressions/assignment/S11.13.1_A7_T3.js fails
+language/expressions/assignment/destructuring/iterator-destructuring-property-reference-target-evaluation-order.js fails
+language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order.js fails
+language/expressions/assignment/dstr-array-elem-iter-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-elem-iter-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-iter-thrw-close.js fails
+language/expressions/assignment/dstr-array-elem-put-let.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-thrw-close.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-thrw-close.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close.js fails
+language/expressions/assignment/dstr-array-rest-iter-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-rest-iter-thrw-close.js fails
+language/expressions/assignment/dstr-array-rest-lref-err.js fails
+language/expressions/assignment/dstr-array-rest-put-let.js fails
+language/expressions/assignment/dstr-obj-id-put-let.js fails
+language/expressions/assignment/dstr-obj-prop-put-let.js fails
+language/expressions/assignment/fn-name-lhs-cover.js fails
+language/expressions/assignment/fn-name-lhs-member.js fails
+language/expressions/async-function/expression-returns-promise.js fails
+language/expressions/async-function/syntax-expression-is-PrimaryExpression.js fails
+language/expressions/await/await-BindingIdentifier-in-global.js fails
+language/expressions/await/await-in-nested-function.js fails
+language/expressions/await/await-in-nested-generator.js fails
+language/expressions/await/await-throws-rejections.js fails
+language/expressions/call/11.2.3-3_3.js fails
+language/expressions/call/eval-spread-empty-leading.js fails
+language/expressions/call/eval-spread-empty-trailing.js fails
+language/expressions/call/eval-spread.js fails
+language/expressions/call/scope-lex-open.js fails
+language/expressions/class/gen-meth-dflt-params-ref-later.js fails
+language/expressions/class/gen-meth-dflt-params-ref-self.js fails
+language/expressions/class/gen-meth-static-dflt-params-ref-later.js fails
+language/expressions/class/gen-meth-static-dflt-params-ref-self.js fails
+language/expressions/class/meth-dflt-params-ref-later.js fails
+language/expressions/class/meth-dflt-params-ref-self.js fails
+language/expressions/class/meth-static-dflt-params-ref-later.js fails
+language/expressions/class/meth-static-dflt-params-ref-self.js fails
+language/expressions/class/name.js fails
+language/expressions/class/scope-gen-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-setter-paramsbody-var-open.js fails
+language/expressions/class/scope-static-gen-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-static-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-static-setter-paramsbody-var-open.js fails
+language/expressions/compound-assignment/S11.13.2_A5.10_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.11_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.1_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.2_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.3_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.4_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.5_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.6_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.7_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.8_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.9_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A6.10_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.11_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.1_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.2_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.3_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.4_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.5_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.6_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.7_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.8_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.9_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A7.10_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.11_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.1_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.2_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.3_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.4_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.5_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.6_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.7_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.8_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.9_T4.js fails
+language/expressions/delete/super-property.js fails
+language/expressions/function/arguments-with-arguments-fn.js sloppyFails
+language/expressions/function/arguments-with-arguments-lex.js sloppyFails
+language/expressions/function/dflt-params-ref-later.js fails
+language/expressions/function/dflt-params-ref-self.js fails
+language/expressions/function/name.js fails
+language/expressions/function/param-dflt-yield-non-strict.js sloppyFails
+language/expressions/function/scope-body-lex-distinct.js sloppyFails
+language/expressions/function/scope-name-var-open-non-strict.js sloppyFails
+language/expressions/function/scope-name-var-open-strict.js strictFails
+language/expressions/function/scope-param-elem-var-close.js sloppyFails
+language/expressions/function/scope-param-elem-var-open.js sloppyFails
+language/expressions/function/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/function/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/function/scope-paramsbody-var-open.js fails
+language/expressions/generators/arguments-with-arguments-fn.js sloppyFails
+language/expressions/generators/arguments-with-arguments-lex.js sloppyFails
+language/expressions/generators/default-proto.js fails
+language/expressions/generators/dflt-params-ref-later.js fails
+language/expressions/generators/dflt-params-ref-self.js fails
+language/expressions/generators/name.js fails
+language/expressions/generators/named-yield-identifier-non-strict.js sloppyFails
+language/expressions/generators/scope-body-lex-distinct.js sloppyFails
+language/expressions/generators/scope-name-var-open-non-strict.js sloppyFails
+language/expressions/generators/scope-name-var-open-strict.js strictFails
+language/expressions/generators/scope-param-elem-var-close.js sloppyFails
+language/expressions/generators/scope-param-elem-var-open.js sloppyFails
+language/expressions/generators/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/generators/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/generators/scope-paramsbody-var-open.js fails
+language/expressions/generators/yield-as-function-expression-binding-identifier.js sloppyFails
+language/expressions/generators/yield-as-identifier-in-nested-function.js sloppyFails
+language/expressions/generators/yield-as-literal-property-name.js fails
+language/expressions/generators/yield-as-property-name.js fails
+language/expressions/generators/yield-identifier-non-strict.js sloppyFails
+language/expressions/object/let-non-strict-access.js sloppyFails
+language/expressions/object/let-non-strict-syntax.js sloppyFails
+language/expressions/object/method-definition/gen-meth-dflt-params-ref-later.js fails
+language/expressions/object/method-definition/gen-meth-dflt-params-ref-self.js fails
+language/expressions/object/method-definition/gen-yield-identifier-non-strict.js sloppyFails
+language/expressions/object/method-definition/meth-dflt-params-ref-later.js fails
+language/expressions/object/method-definition/meth-dflt-params-ref-self.js fails
+language/expressions/object/method-definition/object-method-returns-promise.js fails
+language/expressions/object/method-definition/yield-as-function-expression-binding-identifier.js sloppyFails
+language/expressions/object/method-definition/yield-as-identifier-in-nested-function.js sloppyFails
+language/expressions/object/method-definition/yield-as-literal-property-name.js fails
+language/expressions/object/method-definition/yield-as-property-name.js fails
+language/expressions/object/properties-names-eval-arguments.js strictFails
+language/expressions/object/scope-gen-meth-body-lex-distinct.js sloppyFails
+language/expressions/object/scope-gen-meth-param-elem-var-close.js sloppyFails
+language/expressions/object/scope-gen-meth-param-elem-var-open.js sloppyFails
+language/expressions/object/scope-gen-meth-param-rest-elem-var-close.js sloppyFails
+language/expressions/object/scope-gen-meth-param-rest-elem-var-open.js sloppyFails
+language/expressions/object/scope-gen-meth-paramsbody-var-open.js fails
+language/expressions/object/scope-getter-body-lex-distinc.js sloppyFails
+language/expressions/object/scope-meth-body-lex-distinct.js sloppyFails
+language/expressions/object/scope-meth-param-elem-var-close.js sloppyFails
+language/expressions/object/scope-meth-param-elem-var-open.js sloppyFails
+language/expressions/object/scope-meth-param-rest-elem-var-close.js sloppyFails
+language/expressions/object/scope-meth-param-rest-elem-var-open.js sloppyFails
+language/expressions/object/scope-meth-paramsbody-var-open.js fails
+language/expressions/object/scope-setter-body-lex-distinc.js sloppyFails
+language/expressions/object/scope-setter-paramsbody-var-open.js fails
+language/expressions/postfix-decrement/S11.3.2_A5_T1.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T2.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T3.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T4.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T5.js fails
+language/expressions/postfix-decrement/S11.3.2_A6_T3.js fails
+language/expressions/postfix-increment/S11.3.1_A5_T1.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T2.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T3.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T4.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T5.js fails
+language/expressions/postfix-increment/S11.3.1_A6_T3.js fails
+language/expressions/prefix-decrement/S11.4.5_A5_T1.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T2.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T3.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T4.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T5.js fails
+language/expressions/prefix-decrement/S11.4.5_A6_T3.js fails
+language/expressions/prefix-increment/S11.4.4_A5_T1.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T2.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T5.js fails
+language/expressions/prefix-increment/S11.4.4_A6_T3.js fails
+language/expressions/tagged-template/invalid-escape-sequences.js fails
+language/expressions/tagged-template/tco-member.js strictFails
+language/function-code/each-param-has-own-non-shared-eval-scope.js sloppyFails
+language/function-code/each-param-has-own-scope.js sloppyFails
+language/function-code/eval-param-env-with-computed-key.js sloppyFails
+language/function-code/eval-param-env-with-prop-initializer.js sloppyFails
+language/global-code/decl-lex-restricted-global.js fails
+language/global-code/script-decl-func-dups.js fails
+language/global-code/script-decl-func.js fails
+language/global-code/script-decl-lex-deletion.js sloppyFails
+language/global-code/script-decl-lex-lex.js fails
+language/global-code/script-decl-lex-restricted-global.js fails
+language/global-code/script-decl-lex-var.js fails
+language/global-code/script-decl-lex.js fails
+language/global-code/script-decl-var-collision.js fails
+language/global-code/script-decl-var.js fails
+language/identifiers/other_id_continue.js fails
+language/identifiers/other_id_start-escaped.js fails
+language/identifiers/other_id_start.js fails
+language/statements/async-function/cptn-decl.js fails
+language/statements/async-function/declaration-returns-promise.js fails
+language/statements/async-function/evaluation-body.js fails
+language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails
+language/statements/class/constructor-inferred-observable-iteration.js fails
+language/statements/class/cptn-decl.js fails
+language/statements/class/definition/class-method-returns-promise.js fails
+language/statements/class/definition/getters-restricted-ids.js fails
+language/statements/class/definition/methods-gen-yield-as-literal-property-name.js fails
+language/statements/class/definition/methods-gen-yield-as-property-name.js fails
+language/statements/class/definition/methods-named-eval-arguments.js fails
+language/statements/class/definition/prototype-property.js fails
+language/statements/class/definition/setters-prop-desc.js fails
+language/statements/class/definition/setters-restricted-ids.js fails
+language/statements/class/definition/this-access-restriction-2.js fails
+language/statements/class/definition/this-access-restriction.js fails
+language/statements/class/definition/this-check-ordering.js fails
+language/statements/class/gen-meth-dflt-params-ref-later.js fails
+language/statements/class/gen-meth-dflt-params-ref-self.js fails
+language/statements/class/gen-meth-static-dflt-params-ref-later.js fails
+language/statements/class/gen-meth-static-dflt-params-ref-self.js fails
+language/statements/class/meth-dflt-params-ref-later.js fails
+language/statements/class/meth-dflt-params-ref-self.js fails
+language/statements/class/meth-static-dflt-params-ref-later.js fails
+language/statements/class/meth-static-dflt-params-ref-self.js fails
+language/statements/class/scope-gen-meth-paramsbody-var-open.js fails
+language/statements/class/scope-meth-paramsbody-var-open.js fails
+language/statements/class/scope-setter-paramsbody-var-open.js fails
+language/statements/class/scope-static-gen-meth-paramsbody-var-open.js fails
+language/statements/class/scope-static-meth-paramsbody-var-open.js fails
+language/statements/class/scope-static-setter-paramsbody-var-open.js fails
+language/statements/class/subclass/bound-function.js fails
+language/statements/class/subclass/default-constructor-spread-override.js fails
+language/statements/for-in/head-lhs-let.js sloppyFails
+language/statements/for-in/head-var-bound-names-let.js sloppyFails
+language/statements/for-in/identifier-let-allowed-as-lefthandside-expression-not-strict.js sloppyFails
+language/statements/for-of/dstr-array-elem-iter-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-elem-iter-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-iter-thrw-close.js fails
+language/statements/for-of/dstr-array-elem-put-let.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-thrw-close.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-thrw-close.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close.js fails
+language/statements/for-of/dstr-array-rest-iter-thrw-close-err.js fails
+language/statements/for-of/dstr-array-rest-iter-thrw-close.js fails
+language/statements/for-of/dstr-array-rest-lref-err.js fails
+language/statements/for-of/dstr-array-rest-put-let.js fails
+language/statements/for-of/dstr-obj-id-put-let.js fails
+language/statements/for-of/dstr-obj-prop-put-let.js fails
+language/statements/for-of/head-var-bound-names-let.js sloppyFails
+language/statements/for-of/iterator-next-reference.js fails
+language/statements/for/head-lhs-let.js sloppyFails
+language/statements/for/scope-body-lex-open.js fails
+language/statements/function/13.2-30-s.js fails
+language/statements/function/S13_A15_T4.js sloppyFails
+language/statements/function/arguments-with-arguments-fn.js sloppyFails
+language/statements/function/arguments-with-arguments-lex.js sloppyFails
+language/statements/function/dflt-params-ref-later.js fails
+language/statements/function/dflt-params-ref-self.js fails
+language/statements/function/param-dflt-yield-non-strict.js sloppyFails
+language/statements/function/scope-body-lex-distinct.js sloppyFails
+language/statements/function/scope-param-elem-var-close.js sloppyFails
+language/statements/function/scope-param-elem-var-open.js sloppyFails
+language/statements/function/scope-param-rest-elem-var-close.js sloppyFails
+language/statements/function/scope-param-rest-elem-var-open.js sloppyFails
+language/statements/function/scope-paramsbody-var-open.js fails
+language/statements/generators/arguments-with-arguments-fn.js sloppyFails
+language/statements/generators/arguments-with-arguments-lex.js sloppyFails
+language/statements/generators/default-proto.js fails
+language/statements/generators/dflt-params-ref-later.js fails
+language/statements/generators/dflt-params-ref-self.js fails
+language/statements/generators/scope-body-lex-distinct.js sloppyFails
+language/statements/generators/scope-param-elem-var-close.js sloppyFails
+language/statements/generators/scope-param-elem-var-open.js sloppyFails
+language/statements/generators/scope-param-rest-elem-var-close.js sloppyFails
+language/statements/generators/scope-param-rest-elem-var-open.js sloppyFails
+language/statements/generators/scope-paramsbody-var-open.js fails
+language/statements/generators/yield-as-function-expression-binding-identifier.js sloppyFails
+language/statements/generators/yield-as-identifier-in-nested-function.js sloppyFails
+language/statements/generators/yield-as-literal-property-name.js fails
+language/statements/generators/yield-as-property-name.js fails
+language/statements/generators/yield-identifier-non-strict.js sloppyFails
+language/statements/let/block-local-closure-set-before-initialization.js fails
+language/statements/let/function-local-closure-set-before-initialization.js fails
+language/statements/let/global-closure-set-before-initialization.js fails
+language/statements/throw/S12.13_A2_T6.js strictFails
+language/statements/try/S12.14_A18_T6.js strictFails
+language/statements/try/scope-catch-block-lex-open.js fails
+language/statements/variable/binding-resolution.js sloppyFails
+language/statements/with/unscopables-inc-dec.js sloppyFails
+language/types/reference/put-value-prop-base-primitive.js strictFails
diff --git a/tests/auto/qml/ecmascripttests/ecmascripttests.pro b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
index 6d3ee12307..9c09ee701e 100644
--- a/tests/auto/qml/ecmascripttests/ecmascripttests.pro
+++ b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
@@ -1,20 +1,13 @@
-CONFIG += testcase
-TARGET = tst_ecmascripttests
-QT += testlib
-macos:CONFIG -= app_bundle
-SOURCES += tst_ecmascripttests.cpp
-DEFINES += SRCDIR=\\\"$$PWD\\\"
-
-TESTSCRIPT=$$PWD/test262.py
-isEmpty(V4CMD): V4CMD = qmljs
+TEMPLATE = subdirs
+SUBDIRS = testcase.pro qjstest
checkjittarget.target = check-jit
-checkjittarget.commands = python $$TESTSCRIPT --command=$$V4CMD --parallel --with-test-expectations --update-expectations
+checkjittarget.commands = qjstest --jit --parallel --with-test-expectations --update-expectations
checkjittarget.depends = all
QMAKE_EXTRA_TARGETS += checkjittarget
checkmothtarget.target = check-interpreter
-checkmothtarget.commands = python $$TESTSCRIPT --command=\"$$V4CMD --interpret\" --parallel --with-test-expectations
+checkmothtarget.commands = qjstest --interpret --parallel --with-test-expectations
checkmothtarget.depends = all
QMAKE_EXTRA_TARGETS += checkmothtarget
diff --git a/tests/auto/qml/ecmascripttests/qjstest/main.cpp b/tests/auto/qml/ecmascripttests/qjstest/main.cpp
new file mode 100644
index 0000000000..4a3541d892
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/main.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module 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 <QJSEngine>
+#include <QCoreApplication>
+#include <QCommandLineParser>
+#include <qdebug.h>
+#include <stdlib.h>
+
+#include "test262runner.h"
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption verbose("verbose", "Verbose output");
+ parser.addOption(verbose);
+ QCommandLineOption commandOption("command", "Javascript command line interpreter", "command");
+ parser.addOption(commandOption);
+ QCommandLineOption testDir("tests", "path to the tests", "tests", "test262");
+ parser.addOption(testDir);
+ QCommandLineOption cat("cat", "Print packaged test code that would be run");
+ parser.addOption(cat);
+ QCommandLineOption parallel("parallel", "Run tests in parallel");
+ parser.addOption(parallel);
+ QCommandLineOption jit("jit", "JIT all code");
+ parser.addOption(jit);
+ QCommandLineOption bytecode("interpret", "Run using the bytecode interpreter");
+ parser.addOption(bytecode);
+ QCommandLineOption withExpectations("with-test-expectations", "Parse TestExpectations to deal with known failures");
+ parser.addOption(withExpectations);
+ QCommandLineOption updateExpectations("update-expectations", "Update TestExpectations to remove unexepected passes");
+ parser.addOption(updateExpectations);
+ QCommandLineOption writeExpectations("write-expectations", "Generate a new TestExpectations file based on the results of the run");
+ parser.addOption(writeExpectations);
+ parser.addPositionalArgument("[filter]", "Only run tests that contain filter in their name");
+
+ parser.process(app);
+
+ Test262Runner testRunner(parser.value(commandOption), parser.value(testDir));
+
+ QStringList otherArgs = parser.positionalArguments();
+ if (otherArgs.size() > 1) {
+ qWarning() << "too many arguments";
+ return 1;
+ } else if (otherArgs.size()) {
+ testRunner.setFilter(otherArgs.at(0));
+ }
+
+ if (parser.isSet(cat)) {
+ testRunner.cat();
+ return 0;
+ }
+
+ if (parser.isSet(updateExpectations) && parser.isSet(writeExpectations)) {
+ qWarning() << "Can only specify one of --update-expectations and --write-expectations.";
+ exit(1);
+ }
+
+ if (parser.isSet(jit) && parser.isSet(bytecode)) {
+ qWarning() << "Can only specify one of --jit and --interpret.";
+ exit(1);
+ }
+
+ int flags = 0;
+ if (parser.isSet(verbose))
+ flags |= Test262Runner::Verbose;
+ if (parser.isSet(parallel))
+ flags |= Test262Runner::Parallel;
+ if (parser.isSet(jit))
+ flags |= Test262Runner::ForceJIT;
+ if (parser.isSet(bytecode))
+ flags |= Test262Runner::ForceBytecode;
+ if (parser.isSet(withExpectations))
+ flags |= Test262Runner::WithTestExpectations;
+ if (parser.isSet(updateExpectations))
+ flags |= Test262Runner::UpdateTestExpectations;
+ if (parser.isSet(writeExpectations))
+ flags |= Test262Runner::WriteTestExpectations;
+ testRunner.setFlags(flags);
+
+ if (testRunner.run())
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
diff --git a/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro b/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro
new file mode 100644
index 0000000000..6dec5f8f23
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET = qjstest
+QT += qml-private
+INCLUDEPATH += .
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+HEADERS += test262runner.h
+SOURCES += main.cpp test262runner.cpp
+
+QMAKE_TARGET_DESCRIPTION = Javascript test runner
+
+load(qt_tool)
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
new file mode 100644
index 0000000000..cbe3be2e70
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -0,0 +1,852 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module 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 "test262runner.h"
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qdiriterator.h>
+#include <qdebug.h>
+#include <qprocess.h>
+#include <qtemporaryfile.h>
+
+#include <private/qv4script_p.h>
+#include "private/qv4globalobject_p.h"
+#include "private/qqmlbuiltinfunctions_p.h"
+#include "private/qv4arraybuffer_p.h"
+
+#include "qrunnable.h"
+
+static const char *excludedFeatures[] = {
+ "BigInt",
+ "class-fields-public",
+ "class-fields-private",
+ "Promise.prototype.finally",
+ "async-iteration",
+ "Symbol.asyncIterator",
+ "object-rest",
+ "object-spread",
+ "optional-catch-binding",
+ "regexp-dotall",
+ "regexp-lookbehind",
+ "regexp-named-groups",
+ "regexp-unicode-property-escapes",
+ "Atomics",
+ "SharedArrayBuffer",
+ "Array.prototype.flatten",
+ "Array.prototype.flatMap",
+ "string-trimming",
+ "String.prototype.trimEnd",
+ "String.prototype.trimStart",
+ "numeric-separator-literal",
+
+ // optional features, not supported by us
+ "caller",
+ nullptr
+};
+
+static const char *excludedFilePatterns[] = {
+ "realm",
+ nullptr
+};
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+static ReturnedValue method_detachArrayBuffer(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (!argc)
+ return scope.engine->throwTypeError();
+ Scoped<ArrayBuffer> a(scope, argv[0]);
+ if (!a)
+ return scope.engine->throwTypeError();
+
+ if (a->isShared())
+ return scope.engine->throwTypeError();
+
+ a->d()->detachArrayBuffer();
+
+ return Encode::null();
+}
+
+static void initD262(ExecutionEngine *e)
+{
+ Scope scope(e);
+ ScopedObject d262(scope, e->newObject());
+
+ d262->defineDefaultProperty(QStringLiteral("detachArrayBuffer"), method_detachArrayBuffer, 1);
+
+ ScopedString s(scope, e->newString(QStringLiteral("$262")));
+ e->globalObject->put(s, d262);
+}
+
+}
+
+QT_END_NAMESPACE
+
+Test262Runner::Test262Runner(const QString &command, const QString &dir)
+ : command(command), testDir(dir)
+{
+ if (testDir.endsWith(QLatin1Char('/')))
+ testDir = testDir.chopped(1);
+}
+
+Test262Runner::~Test262Runner()
+{
+ delete threadPool;
+}
+
+void Test262Runner::cat()
+{
+ if (!loadTests())
+ return;
+
+ if (testCases.size() != 1)
+ qWarning() << "test262 --cat: Ambiguous test case, using" << testCases.begin().key();
+ TestData data = getTestData(testCases.begin().value());
+ printf("%s", data.content.constData());
+}
+
+bool Test262Runner::run()
+{
+ if (!loadTests())
+ return false;
+
+ if (flags & Parallel) {
+ threadPool = new QThreadPool;
+ threadPool->setStackSize(16*1024*1024);
+ if (flags & Verbose)
+ qDebug() << "Running in parallel with" << QThread::idealThreadCount() << "threads.";
+ }
+
+ if (flags & ForceJIT)
+ qputenv("QV4_JIT_CALL_THRESHOLD", QByteArray("0"));
+ else if (flags & ForceBytecode)
+ qputenv("QV4_FORCE_INTERPRETER", QByteArray("1"));
+
+ if (flags & WithTestExpectations)
+ loadTestExpectations();
+
+ for (auto it = testCases.constBegin(); it != testCases.constEnd(); ++it) {
+ auto c = it.value();
+ if (!c.skipTestCase) {
+ int result = runSingleTest(c);
+ if (result == -2)
+ return false;
+ }
+ }
+
+ if (threadPool)
+ threadPool->waitForDone();
+
+ const bool testsOk = report();
+
+ if (flags & WriteTestExpectations)
+ writeTestExpectations();
+ else if (flags & UpdateTestExpectations)
+ updateTestExpectations();
+
+ return testsOk;
+}
+
+bool Test262Runner::report()
+{
+ qDebug() << "Test execution summary:";
+ qDebug() << " Executed" << testCases.size() << "test cases.";
+ QStringList crashes;
+ QStringList unexpectedFailures;
+ QStringList unexpectedPasses;
+ for (auto it = testCases.constBegin(); it != testCases.constEnd(); ++it) {
+ const auto c = it.value();
+ if (c.strictResult == c.strictExpectation && c.sloppyResult == c.sloppyExpectation)
+ continue;
+ auto report = [&] (TestCase::Result expected, TestCase::Result result, const char *s) {
+ if (result == TestCase::Crashes)
+ crashes << (it.key() + " crashed in " + s + " mode");
+ if (result == TestCase::Fails && expected == TestCase::Passes)
+ unexpectedFailures << (it.key() + " failed in " + s + " mode");
+ if (result == TestCase::Passes && expected == TestCase::Fails)
+ unexpectedPasses << (it.key() + " unexpectedly passed in " + s + " mode");
+ };
+ report(c.strictExpectation, c.strictResult, "strict");
+ report(c.sloppyExpectation, c.sloppyResult, "sloppy");
+ }
+ if (!crashes.isEmpty()) {
+ qDebug() << " Encountered" << crashes.size() << "crashes in the following files:";
+ for (const QString &f : qAsConst(crashes))
+ qDebug() << " " << f;
+ }
+ if (!unexpectedFailures.isEmpty()) {
+ qDebug() << " Encountered" << unexpectedFailures.size() << "unexpected failures in the following files:";
+ for (const QString &f : qAsConst(unexpectedFailures))
+ qDebug() << " " << f;
+ }
+ if (!unexpectedPasses.isEmpty()) {
+ qDebug() << " Encountered" << unexpectedPasses.size() << "unexpected passes in the following files:";
+ for (const QString &f : qAsConst(unexpectedPasses))
+ qDebug() << " " << f;
+ }
+ return crashes.isEmpty() && unexpectedFailures.isEmpty() && unexpectedPasses.isEmpty();
+}
+
+bool Test262Runner::loadTests()
+{
+ QDir dir(testDir + "/test");
+ if (!dir.exists()) {
+ qWarning() << "Could not load tests," << dir.path() << "does not exist.";
+ return false;
+ }
+
+ QString annexB = "annexB";
+ QString harness = "harness";
+ QString intl402 = "intl402";
+
+ int pathlen = dir.path().length() + 1;
+ QDirIterator it(dir, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ QString file = it.next().mid(pathlen);
+ if (!file.endsWith(".js"))
+ continue;
+ if (file.endsWith("_FIXTURE.js"))
+ continue;
+ if (!filter.isEmpty() && !file.contains(filter))
+ continue;
+ if (file.startsWith(annexB) || file.startsWith(harness) || file.startsWith(intl402))
+ continue;
+ const char **excluded = excludedFilePatterns;
+ bool skip = false;
+ while (*excluded) {
+ if (file.contains(QLatin1String(*excluded)))
+ skip = true;
+ ++excluded;
+ }
+ if (skip)
+ continue;
+
+ testCases.insert(file, TestCase{ file });
+ }
+ if (testCases.isEmpty()) {
+ qWarning() << "No tests to run.";
+ return false;
+ }
+
+ return true;
+}
+
+
+struct TestExpectationLine {
+ TestExpectationLine(const QByteArray &line);
+ enum State {
+ Fails,
+ SloppyFails,
+ StrictFails,
+ Skip,
+ Passes
+ } state;
+ QString testCase;
+
+ QByteArray toLine() const;
+ void update(const TestCase &testCase);
+
+ static TestExpectationLine fromTestCase(const TestCase &testCase);
+private:
+ TestExpectationLine() = default;
+ static State stateFromTestCase(const TestCase &testCase);
+};
+
+TestExpectationLine::TestExpectationLine(const QByteArray &line)
+{
+ int space = line.indexOf(' ');
+
+ testCase = QString::fromUtf8(space > 0 ? line.left(space) : line);
+ if (!testCase.endsWith(".js"))
+ testCase += ".js";
+
+ state = Fails;
+ if (space < 0)
+ return;
+ QByteArray qualifier = line.mid(space + 1);
+ if (qualifier == "skip")
+ state = Skip;
+ else if (qualifier == "strictFails")
+ state = StrictFails;
+ else if (qualifier == "sloppyFails")
+ state = SloppyFails;
+ else if (qualifier == "fails")
+ state = Fails;
+ else
+ qWarning() << "illegal format in TestExpectations, line" << line;
+}
+
+QByteArray TestExpectationLine::toLine() const {
+ const char *res = nullptr;
+ switch (state) {
+ case Fails:
+ res = " fails\n";
+ break;
+ case SloppyFails:
+ res = " sloppyFails\n";
+ break;
+ case StrictFails:
+ res = " strictFails\n";
+ break;
+ case Skip:
+ res = " skip\n";
+ break;
+ case Passes:
+ // no need for an entry
+ return QByteArray();
+ }
+ QByteArray result = testCase.toUtf8() + res;
+ return result;
+}
+
+void TestExpectationLine::update(const TestCase &testCase)
+{
+ Q_ASSERT(testCase.test == this->testCase);
+
+ State resultState = stateFromTestCase(testCase);
+ switch (resultState) {
+ case Fails:
+ // no improvement, don't update
+ break;
+ case SloppyFails:
+ if (state == Fails)
+ state = SloppyFails;
+ else if (state == StrictFails)
+ // we have a regression in sloppy mode, but strict now passes
+ state = Passes;
+ break;
+ case StrictFails:
+ if (state == Fails)
+ state = StrictFails;
+ else if (state == SloppyFails)
+ // we have a regression in strict mode, but sloppy now passes
+ state = Passes;
+ break;
+ case Skip:
+ Q_ASSERT(state == Skip);
+ // nothing to do
+ break;
+ case Passes:
+ state = Passes;
+ }
+}
+
+TestExpectationLine TestExpectationLine::fromTestCase(const TestCase &testCase)
+{
+ TestExpectationLine l;
+ l.testCase = testCase.test;
+ l.state = stateFromTestCase(testCase);
+ return l;
+}
+
+TestExpectationLine::State TestExpectationLine::stateFromTestCase(const TestCase &testCase)
+{
+ // keep skipped tests
+ if (testCase.skipTestCase)
+ return Skip;
+
+ bool strictFails = (testCase.strictResult == TestCase::Crashes || testCase.strictResult == TestCase::Fails);
+ bool sloppyFails = (testCase.sloppyResult == TestCase::Crashes || testCase.sloppyResult == TestCase::Fails);
+ if (strictFails && sloppyFails)
+ return Fails;
+ if (strictFails)
+ return StrictFails;
+ if (sloppyFails)
+ return SloppyFails;
+ return Passes;
+}
+
+
+void Test262Runner::loadTestExpectations()
+{
+ QFile file("TestExpectations");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Could not open TestExpectations file.";
+ return;
+ }
+
+ int line = 0;
+ while (!file.atEnd()) {
+ ++line;
+ QByteArray line = file.readLine().trimmed();
+ if (line.startsWith('#') || line.isEmpty())
+ continue;
+ TestExpectationLine expectation(line);
+ if (!filter.isEmpty() && !expectation.testCase.contains(filter))
+ continue;
+
+ if (!testCases.contains(expectation.testCase))
+ qWarning() << "Unknown test case" << expectation.testCase << "in TestExpectations file.";
+ //qDebug() << "TestExpectations:" << expectation.testCase << expectation.state;
+ TestCase &s = testCases[expectation.testCase];
+ switch (expectation.state) {
+ case TestExpectationLine::Fails:
+ s.strictExpectation = TestCase::Fails;
+ s.sloppyExpectation = TestCase::Fails;
+ break;
+ case TestExpectationLine::SloppyFails:
+ s.strictExpectation = TestCase::Passes;
+ s.sloppyExpectation = TestCase::Fails;
+ break;
+ case TestExpectationLine::StrictFails:
+ s.strictExpectation = TestCase::Fails;
+ s.sloppyExpectation = TestCase::Passes;
+ break;
+ case TestExpectationLine::Skip:
+ s.skipTestCase = true;
+ break;
+ case TestExpectationLine::Passes:
+ Q_UNREACHABLE();
+ }
+ }
+}
+
+void Test262Runner::updateTestExpectations()
+{
+ QFile file("TestExpectations");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Could not open TestExpectations file.";
+ return;
+ }
+
+ QTemporaryFile updatedExpectations;
+ updatedExpectations.open();
+
+ int line = 0;
+ while (!file.atEnd()) {
+ ++line;
+ QByteArray originalLine = file.readLine();
+ QByteArray line = originalLine.trimmed();
+ if (line.startsWith('#') || line.isEmpty()) {
+ updatedExpectations.write(originalLine);
+ continue;
+ }
+
+ TestExpectationLine expectation(line);
+// qDebug() << "checking: " << expectation.testCase;
+ if (!testCases.contains(expectation.testCase)) {
+ updatedExpectations.write(originalLine);
+ continue;
+ }
+ const TestCase &testcase = testCases.value(expectation.testCase);
+ expectation.update(testcase);
+
+ line = expectation.toLine();
+// qDebug() << "updated line:" << line;
+ updatedExpectations.write(line);
+ }
+ file.close();
+ updatedExpectations.close();
+ file.remove();
+ qDebug() << updatedExpectations.fileName() << file.fileName();
+ updatedExpectations.copy(file.fileName());
+ qDebug() << "Updated TestExpectations file written!";
+}
+
+void Test262Runner::writeTestExpectations()
+{
+ QFile file("TestExpectations");
+
+ QTemporaryFile expectations;
+ expectations.open();
+
+ for (auto c : qAsConst(testCases)) {
+ TestExpectationLine line = TestExpectationLine::fromTestCase(c);
+ expectations.write(line.toLine());
+ }
+
+ expectations.close();
+ if (file.exists())
+ file.remove();
+ qDebug() << expectations.fileName() << file.fileName();
+ expectations.copy(file.fileName());
+ qDebug() << "new TestExpectations file written!";
+
+}
+
+static bool executeTest(const QByteArray &data, bool runAsModule = false, const QString &testCasePath = QString(), const QByteArray &harnessForModules = QByteArray())
+{
+ QString testData = QString::fromUtf8(data.constData(), data.size());
+
+ QV4::ExecutionEngine vm;
+
+ QV4::Scope scope(&vm);
+
+ QV4::GlobalExtensions::init(vm.globalObject, QJSEngine::ConsoleExtension | QJSEngine::GarbageCollectionExtension);
+ QV4::initD262(&vm);
+
+ if (runAsModule) {
+ const QUrl rootModuleUrl = QUrl::fromLocalFile(testCasePath);
+ // inject all modules with the harness
+ QVector<QUrl> modulesToLoad = { rootModuleUrl };
+ while (!modulesToLoad.isEmpty()) {
+ QUrl url = modulesToLoad.takeFirst();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> module;
+
+ QFile f(url.toLocalFile());
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray content = harnessForModules + f.readAll();
+ module = vm.compileModule(url.toString(), QString::fromUtf8(content.constData(), content.length()), QFileInfo(f).lastModified());
+ if (vm.hasException)
+ break;
+ vm.injectModule(module);
+ } else {
+ vm.throwError(QStringLiteral("Could not load module"));
+ break;
+ }
+
+ for (const QString &request: module->moduleRequests()) {
+ const QUrl absoluteRequest = module->finalUrl().resolved(QUrl(request));
+ if (!vm.modules.contains(absoluteRequest))
+ modulesToLoad << absoluteRequest;
+ }
+ }
+
+ if (!vm.hasException) {
+ if (auto rootModuleUnit = vm.loadModule(rootModuleUrl)) {
+ if (rootModuleUnit->instantiate(&vm))
+ rootModuleUnit->evaluate();
+ }
+ }
+ } else {
+ QV4::ScopedContext ctx(scope, vm.rootContext());
+
+ QV4::Script script(ctx, QV4::Compiler::ContextType::Global, testData);
+ script.parse();
+
+ if (!vm.hasException)
+ script.run();
+ }
+ return !vm.hasException;
+}
+
+class SingleTest : public QRunnable
+{
+public:
+ SingleTest(Test262Runner *runner, const TestData &data)
+ : runner(runner), data(data)
+ {
+ command = runner->command;
+ }
+ void run();
+
+ void runExternalTest();
+
+ QString command;
+ Test262Runner *runner;
+ TestData data;
+};
+
+void SingleTest::run()
+{
+ if (!command.isEmpty()) {
+ runExternalTest();
+ return;
+ }
+
+ if (data.runInSloppyMode) {
+ bool ok = ::executeTest(data.content);
+ if (data.negative)
+ ok = !ok;
+
+ data.sloppyResult = ok ? TestCase::Passes : TestCase::Fails;
+ } else {
+ data.sloppyResult = TestCase::Skipped;
+ }
+ if (data.runInStrictMode) {
+ const QString testCasePath = QFileInfo(runner->testDir + "/test/" + data.test).absoluteFilePath();
+ QByteArray c = "'use strict';\n" + data.content;
+ bool ok = ::executeTest(c, data.runAsModuleCode, testCasePath, data.harness);
+ if (data.negative)
+ ok = !ok;
+
+ data.strictResult = ok ? TestCase::Passes : TestCase::Fails;
+ } else {
+ data.strictResult = TestCase::Skipped;
+ }
+ runner->addResult(data);
+}
+
+void SingleTest::runExternalTest()
+{
+ auto runTest = [=] (const char *header, TestCase::Result *result) {
+ QTemporaryFile tempFile;
+ tempFile.open();
+ tempFile.write(header);
+ tempFile.write(data.content);
+ tempFile.close();
+
+ QProcess process;
+// if (flags & Verbose)
+// process.setReadChannelMode(QProcess::ForwardedChannels);
+
+ process.start(command, QStringList(tempFile.fileName()));
+ if (!process.waitForFinished(-1) || process.error() == QProcess::FailedToStart) {
+ qWarning() << "Could not execute" << command;
+ *result = TestCase::Crashes;
+ }
+ if (process.exitStatus() != QProcess::NormalExit) {
+ *result = TestCase::Crashes;
+ }
+ bool ok = (process.exitCode() == EXIT_SUCCESS);
+ if (data.negative)
+ ok = !ok;
+ *result = ok ? TestCase::Passes : TestCase::Fails;
+ };
+
+ if (data.runInSloppyMode)
+ runTest("", &data.sloppyResult);
+ if (data.runInStrictMode)
+ runTest("'use strict';\n", &data.strictResult);
+
+ runner->addResult(data);
+}
+
+int Test262Runner::runSingleTest(TestCase testCase)
+{
+ TestData data = getTestData(testCase);
+// qDebug() << "starting test" << data.test;
+
+ if (data.isExcluded || data.async)
+ return 0;
+
+ if (threadPool) {
+ SingleTest *test = new SingleTest(this, data);
+ threadPool->start(test);
+ return 0;
+ }
+ SingleTest test(this, data);
+ test.run();
+ return 0;
+}
+
+void Test262Runner::addResult(TestCase result)
+{
+ {
+ QMutexLocker locker(&mutex);
+ Q_ASSERT(result.strictExpectation == testCases[result.test].strictExpectation);
+ Q_ASSERT(result.sloppyExpectation == testCases[result.test].sloppyExpectation);
+ testCases[result.test] = result;
+ }
+
+ if (!(flags & Verbose))
+ return;
+
+ QString test = result.test;
+ if (result.strictResult == TestCase::Skipped) {
+ ;
+ } else if (result.strictResult == TestCase::Crashes) {
+ qDebug() << "FAIL:" << test << "crashed in strict mode!";
+ } else if ((result.strictResult == TestCase::Fails) && (result.strictExpectation == TestCase::Fails)) {
+ qDebug() << "PASS:" << test << "failed in strict mode as expected";
+ } else if ((result.strictResult == TestCase::Passes) == (result.strictExpectation == TestCase::Passes)) {
+ qDebug() << "PASS:" << test << "passed in strict mode";
+ } else if (!(result.strictExpectation == TestCase::Fails)) {
+ qDebug() << "FAIL:" << test << "failed in strict mode";
+ } else {
+ qDebug() << "XPASS:" << test << "unexpectedly passed in strict mode";
+ }
+
+ if (result.sloppyResult == TestCase::Skipped) {
+ ;
+ } else if (result.sloppyResult == TestCase::Crashes) {
+ qDebug() << "FAIL:" << test << "crashed in sloppy mode!";
+ } else if ((result.sloppyResult == TestCase::Fails) && (result.sloppyExpectation == TestCase::Fails)) {
+ qDebug() << "PASS:" << test << "failed in sloppy mode as expected";
+ } else if ((result.sloppyResult == TestCase::Passes) == (result.sloppyExpectation == TestCase::Passes)) {
+ qDebug() << "PASS:" << test << "passed in sloppy mode";
+ } else if (!(result.sloppyExpectation == TestCase::Fails)) {
+ qDebug() << "FAIL:" << test << "failed in sloppy mode";
+ } else {
+ qDebug() << "XPASS:" << test << "unexpectedly passed in sloppy mode";
+ }
+}
+
+TestData Test262Runner::getTestData(const TestCase &testCase)
+{
+ QFile testFile(testDir + "/test/" + testCase.test);
+ if (!testFile.open(QFile::ReadOnly)) {
+ qWarning() << "wrong test file" << testCase.test;
+ exit(1);
+ }
+ QByteArray content = testFile.readAll();
+ content.replace(QByteArrayLiteral("\r\n"), "\n");
+
+// qDebug() << "parsing test file" << test;
+
+ TestData data(testCase);
+ parseYaml(content, &data);
+
+ data.harness += harness("assert.js");
+ data.harness += harness("sta.js");
+
+ for (QByteArray inc : qAsConst(data.includes)) {
+ inc = inc.trimmed();
+ data.harness += harness(inc);
+ }
+
+ if (data.async)
+ data.harness += harness("doneprintHandle.js");
+
+ data.content = data.harness + content;
+
+ return data;
+}
+
+struct YamlSection {
+ YamlSection(const QByteArray &yaml, const char *sectionName);
+
+ bool contains(const char *keyword) const;
+ QList<QByteArray> keywords() const;
+
+ QByteArray yaml;
+ int start = -1;
+ int length = 0;
+ bool shortSection = false;
+};
+
+YamlSection::YamlSection(const QByteArray &yaml, const char *sectionName)
+ : yaml(yaml)
+{
+ start = yaml.indexOf(sectionName);
+ if (start < 0)
+ return;
+ start += static_cast<int>(strlen(sectionName));
+ int end = yaml.indexOf('\n', start + 1);
+ if (end < 0)
+ end = yaml.length();
+
+ int s = yaml.indexOf('[', start);
+ if (s > 0 && s < end) {
+ shortSection = true;
+ start = s + 1;
+ end = yaml.indexOf(']', s);
+ } else {
+ while (end < yaml.size() - 1 && yaml.at(end + 1) == ' ')
+ end = yaml.indexOf('\n', end + 1);
+ }
+ length = end - start;
+}
+
+bool YamlSection::contains(const char *keyword) const
+{
+ if (start < 0)
+ return false;
+ int idx = yaml.indexOf(keyword, start);
+ if (idx >= start && idx < start + length)
+ return true;
+ return false;
+}
+
+QList<QByteArray> YamlSection::keywords() const
+{
+ if (start < 0)
+ return QList<QByteArray>();
+
+ QByteArray content = yaml.mid(start, length);
+ QList<QByteArray> keywords;
+ if (shortSection) {
+ keywords = content.split(',');
+ } else {
+ const QList<QByteArray> list = content.split('\n');
+ for (const QByteArray &l : list) {
+ int i = 0;
+ while (i < l.size() && (l.at(i) == ' ' || l.at(i) == '-'))
+ ++i;
+ QByteArray entry = l.mid(i);
+ if (!entry.isEmpty())
+ keywords.append(entry);
+ }
+ }
+// qDebug() << "keywords:" << keywords;
+ return keywords;
+}
+
+
+void Test262Runner::parseYaml(const QByteArray &content, TestData *data)
+{
+ int start = content.indexOf("/*---");
+ if (start < 0)
+ return;
+ start += sizeof("/*---");
+
+ int end = content.indexOf("---*/");
+ if (end < 0)
+ return;
+
+ QByteArray yaml = content.mid(start, end - start);
+
+ if (yaml.contains("negative:"))
+ data->negative = true;
+
+ YamlSection flags(yaml, "flags:");
+ data->runInSloppyMode = !flags.contains("onlyStrict");
+ data->runInStrictMode = !flags.contains("noStrict") && !flags.contains("raw");
+ data->runAsModuleCode = flags.contains("module");
+ data->async = flags.contains("async");
+
+ if (data->runAsModuleCode) {
+ data->runInStrictMode = true;
+ data->runInSloppyMode = false;
+ }
+
+ YamlSection includes(yaml, "includes:");
+ data->includes = includes.keywords();
+
+ YamlSection features = YamlSection(yaml, "features:");
+
+ const char **f = excludedFeatures;
+ while (*f) {
+ if (features.contains(*f)) {
+ data->isExcluded = true;
+ break;
+ }
+ ++f;
+ }
+
+// qDebug() << "Yaml:\n" << yaml;
+}
+
+QByteArray Test262Runner::harness(const QByteArray &name)
+{
+ if (harnessFiles.contains(name))
+ return harnessFiles.value(name);
+
+ QFile h(testDir + QLatin1String("/harness/") + name);
+ if (!h.open(QFile::ReadOnly)) {
+ qWarning() << "Illegal test harness file" << name;
+ exit(1);
+ }
+
+ QByteArray content = h.readAll();
+ harnessFiles.insert(name, content);
+ return content;
+}
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.h b/tests/auto/qml/ecmascripttests/qjstest/test262runner.h
new file mode 100644
index 0000000000..e20d4a7bdd
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module 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$
+**
+****************************************************************************/
+#ifndef TEST262RUNNER_H
+#define TEST262RUNNER_H
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qset.h>
+#include <qmap.h>
+#include <qmutex.h>
+#include <qthreadpool.h>
+
+struct TestCase {
+ TestCase() = default;
+ TestCase(const QString &test)
+ : test(test) {}
+ enum Result {
+ Skipped,
+ Passes,
+ Fails,
+ Crashes
+ };
+ bool skipTestCase = false;
+ Result strictExpectation = Passes;
+ Result sloppyExpectation = Passes;
+ Result strictResult = Skipped;
+ Result sloppyResult = Skipped;
+
+ QString test;
+};
+
+struct TestData : TestCase {
+ TestData(const TestCase &testCase)
+ : TestCase(testCase) {}
+ // flags
+ bool negative = false;
+ bool runInStrictMode = true;
+ bool runInSloppyMode = true;
+ bool runAsModuleCode = false;
+ bool async = false;
+
+ bool isExcluded = false;
+
+ QList<QByteArray> includes;
+
+ QByteArray harness;
+ QByteArray content;
+};
+
+class Test262Runner
+{
+public:
+ Test262Runner(const QString &command, const QString &testDir);
+ ~Test262Runner();
+
+ enum Mode {
+ Sloppy = 0,
+ Strict = 1
+ };
+
+ enum Flags {
+ Verbose = 0x1,
+ Parallel = 0x2,
+ ForceBytecode = 0x4,
+ ForceJIT = 0x8,
+ WithTestExpectations = 0x10,
+ UpdateTestExpectations = 0x20,
+ WriteTestExpectations = 0x40,
+ };
+ void setFlags(int f) { flags = f; }
+
+ void setFilter(const QString &f) { filter = f; }
+
+ void cat();
+ bool run();
+
+ bool report();
+
+private:
+ friend class SingleTest;
+ bool loadTests();
+ void loadTestExpectations();
+ void updateTestExpectations();
+ void writeTestExpectations();
+ int runSingleTest(TestCase testCase);
+
+ TestData getTestData(const TestCase &testCase);
+ void parseYaml(const QByteArray &content, TestData *data);
+
+ QByteArray harness(const QByteArray &name);
+
+ void addResult(TestCase result);
+
+ QString command;
+ QString testDir;
+ int flags = 0;
+
+ QMutex mutex;
+ QString filter;
+
+ QMap<QString, TestCase> testCases;
+ QHash<QByteArray, QByteArray> harnessFiles;
+
+ QThreadPool *threadPool = nullptr;
+};
+
+
+#endif
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8
+Subproject 6b0c42c63c2492bd0a7a96d3179d122b5f71793
diff --git a/tests/auto/qml/ecmascripttests/test262.py b/tests/auto/qml/ecmascripttests/test262.py
index 9f0a7c1dee..19551e3ba2 100755
--- a/tests/auto/qml/ecmascripttests/test262.py
+++ b/tests/auto/qml/ecmascripttests/test262.py
@@ -1,39 +1,27 @@
#!/usr/bin/env python
#############################################################################
##
-## Copyright (C) 2015 The Qt Company Ltd.
-## Contact: http://www.qt.io/licensing/
+## Copyright (C) 2017 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
##
## This file is part of the test suite module of the Qt Toolkit.
##
-## $QT_BEGIN_LICENSE:BSD$
-## You may use this file under the terms of the BSD license as follows:
+## $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.
##
-## "Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions are
-## met:
-## * Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-## * Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in
-## the documentation and/or other materials provided with the
-## distribution.
-## * Neither the name of The Qt Company Ltd nor the names of its
-## contributors may be used to endorse or promote products derived
-## from this software without specific prior written permission.
-##
-##
-## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+## 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$
##
@@ -73,6 +61,35 @@ from parseTestRecord import parseTestRecord, stripHeader
from packagerConfig import *
+# excluded features that are still experimental and not part of any official standard
+# see also the features.txt file in test262/
+excludedFeatures = [
+ "BigInt",
+ "class-fields-public",
+ "class-fields-private",
+ "Promise.prototype.finally",
+ "async-iteration",
+ "Symbol.asyncIterator",
+ "object-rest",
+ "object-spread",
+ "optional-catch-binding",
+ "regexp-dotall",
+ "regexp-lookbehind",
+ "regexp-named-groups",
+ "regexp-unicode-property-escapes",
+ "Atomics",
+ "SharedArrayBuffer",
+ "Array.prototype.flatten",
+ "Array.prototype.flatMap",
+ "string-trimming",
+ "String.prototype.trimEnd",
+ "String.prototype.trimStart",
+ "numeric-separator-literal",
+
+ # optional features, not supported by us
+ "caller"
+]
+
# ############# Helpers needed for parallel multi-process test execution ############
def runTest(case, args):
@@ -107,19 +124,19 @@ class TestExpectations:
continue
record = line.split()
if len(record) == 1:
- self.testsToSkip.append(record[0])
+ self.failingTests.append(record[0])
else:
test = record[0]
expectation = record[1]
- if expectation == "failing":
- self.failingTests.append(test)
+ if expectation == "skip":
+ self.testsToSkip.append(test)
f.close()
def update(self, progress):
- unexpectedPasses = [c.case.name[-1] for c in progress.failed_tests if c.case.IsNegative()]
+ unexpectedPasses = [c.case.name for c in progress.failed_tests if c.case.IsNegative()]
# If a test fails that we expected to fail, then it actually passed unexpectedly.
- failures = [c.case.name[-1] for c in progress.failed_tests if not c.case.IsNegative()]
+ failures = [c.case.name for c in progress.failed_tests if not c.case.IsNegative()]
for failure in failures:
if failure in self.failingTests:
unexpectedPasses.append(failure)
@@ -128,7 +145,7 @@ class TestExpectations:
lines = f.read().splitlines()
oldLen = len(lines)
for result in unexpectedPasses:
- expectationLine = result + " failing"
+ expectationLine = result
try:
lines.remove(expectationLine)
except ValueError:
@@ -289,14 +306,17 @@ class TestCase(object):
f.close()
testRecord = parseTestRecord(self.contents, name)
self.test = testRecord["test"]
+ if 'features' in testRecord:
+ self.features = testRecord["features"];
+ else:
+ self.features = []
del testRecord["test"]
del testRecord["header"]
- del testRecord["commentary"]
self.testRecord = testRecord;
def GetName(self):
- return path.join(*self.name)
+ return self.name
def GetMode(self):
if self.strict_mode:
@@ -322,14 +342,20 @@ class TestCase(object):
def IsNoStrict(self):
return 'noStrict' in self.testRecord
+ def IsExperimental(self):
+ for f in self.features:
+ if excludedFeatures.count(f) >= 1:
+ return True;
+ return False
+
def GetSource(self):
# "var testDescrip = " + str(self.testRecord) + ';\n\n' + \
- source = self.suite.GetInclude("cth.js") + \
+ source = self.suite.GetInclude("assert.js") + \
self.suite.GetInclude("sta.js") + \
- self.suite.GetInclude("ed.js") + \
- self.suite.GetInclude("testBuiltInObject.js") + \
- self.suite.GetInclude("testIntl.js") + \
self.test + '\n'
+ if 'includes' in self.testRecord:
+ for inc in self.testRecord['includes']:
+ source += self.suite.GetInclude(inc);
if self.strict_mode:
source = '"use strict";\nvar strict_mode = true;\n' + source
@@ -415,14 +441,23 @@ class TestSuite(object):
def __init__(self, root, strict_only, non_strict_only, unmarked_default, load_expectations):
# TODO: derive from packagerConfig.py
- self.test_root = path.join(root, 'test', 'suite')
- self.lib_root = path.join(root, 'test', 'harness')
+ self.test_root = path.join(root, 'test')
+ self.lib_root = path.join(root, 'harness')
self.strict_only = strict_only
self.non_strict_only = non_strict_only
self.unmarked_default = unmarked_default
self.include_cache = { }
self.expectations = TestExpectations(load_expectations)
+ def IsExcludedTest(self, path):
+ if path.startswith('annexB'):
+ return True;
+ if path.startswith('harness'):
+ return True;
+ if path.startswith('intl402'):
+ return True;
+ return False;
+
def Validate(self):
if not path.exists(self.test_root):
ReportError("No test repository found")
@@ -471,25 +506,25 @@ class TestSuite(object):
else:
logging.warning("Unexpected path %s", full_path)
rel_path = full_path
- if self.ShouldRun(rel_path, tests) and not rel_path.startswith("intl402" + os.sep):
+ if self.ShouldRun(rel_path, tests) and not self.IsExcludedTest(rel_path):
basename = path.basename(full_path)[:-3]
- name = rel_path.split(path.sep)[:-1] + [basename]
- if EXCLUDE_LIST.count(basename) >= 1 or self.expectations.testsToSkip.count(basename) >= 1:
- print 'Excluded: ' + basename
+ name = rel_path.replace('.js', '')
+ if EXCLUDE_LIST.count(basename) >= 1 or self.expectations.testsToSkip.count(name) >= 1:
+ print 'Excluded: ' + rel_path
else:
if not self.non_strict_only:
strict_case = TestCase(self, name, full_path, True)
- if self.expectations.failingTests.count(basename) >= 1:
+ if self.expectations.failingTests.count(name) >= 1:
strict_case.NegateResult()
- if not strict_case.IsNoStrict():
+ if not strict_case.IsNoStrict() and not strict_case.IsExperimental():
if strict_case.IsOnlyStrict() or \
self.unmarked_default in ['both', 'strict']:
cases.append(strict_case)
if not self.strict_only:
non_strict_case = TestCase(self, name, full_path, False)
- if self.expectations.failingTests.count(basename) >= 1:
+ if self.expectations.failingTests.count(name) >= 1:
non_strict_case.NegateResult()
- if not non_strict_case.IsOnlyStrict():
+ if not non_strict_case.IsOnlyStrict() and not non_strict_case.IsExperimental():
if non_strict_case.IsNoStrict() or \
self.unmarked_default in ['both', 'non_strict']:
cases.append(non_strict_case)
@@ -564,10 +599,10 @@ class TestSuite(object):
def Main():
- # Some date tests rely on being run in pacific time.
# Uncomment the next line for more logging info.
#logging.basicConfig(level=logging.DEBUG)
- os.environ["TZ"] = "PST8PDT"
+ # Some date tests rely on being run in pacific time and the USA's locale:
+ os.environ["TZ"] = "America/Los_Angeles" # it *matters* that this is (7m8s) *East* of PST's nominal meridian !
os.environ["LANG"] = "en_US.UTF-8"
os.environ["LC_TIME"] = "en_US.UTF-8"
parser = BuildOptions()
diff --git a/tests/auto/qml/ecmascripttests/testcase.pro b/tests/auto/qml/ecmascripttests/testcase.pro
new file mode 100644
index 0000000000..5bf7ecd696
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/testcase.pro
@@ -0,0 +1,15 @@
+CONFIG += testcase
+TARGET = tst_ecmascripttests
+QT += testlib qml-private
+macos:CONFIG -= app_bundle
+SOURCES += tst_ecmascripttests.cpp qjstest/test262runner.cpp
+HEADERS += qjstest/test262runner.h
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+# The ES test suite takes approximately 5 mins to run, on a fairly
+# vanilla developer machine, so the default watchdog timer kills the
+# test some of the time. Fix by raising time-out to 400s when
+# invoking tst_ecmascripttests:
+checkenv.name = QTEST_FUNCTION_TIMEOUT
+checkenv.value = 500000
+QT_TOOL_ENV += checkenv
diff --git a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
index 5d7009e7c8..27d2822762 100644
--- a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
+++ b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
@@ -30,44 +30,36 @@
#include <QtTest/QtTest>
#include <QProcess>
#include <QLibraryInfo>
+#include <qjstest/test262runner.h>
class tst_EcmaScriptTests : public QObject
{
Q_OBJECT
+
private slots:
- void runTests_data();
- void runTests();
+ void runInterpreted();
+ void runJitted();
};
-void tst_EcmaScriptTests::runTests_data()
+void tst_EcmaScriptTests::runInterpreted()
{
- QTest::addColumn<QString>("qmljsParameter");
-
- QTest::newRow("jit") << QStringLiteral("--jit");
- // Not passing yet: QTest::newRow("interpreter") << QStringLiteral("--interpret");
+#if defined(Q_PROCESSOR_X86_64)
+ QDir::setCurrent(QLatin1String(SRCDIR));
+ Test262Runner runner(QString(), "test262");
+ runner.setFlags(Test262Runner::ForceBytecode|Test262Runner::WithTestExpectations|Test262Runner::Parallel|Test262Runner::Verbose);
+ bool result = runner.run();
+ QVERIFY(result);
+#endif
}
-void tst_EcmaScriptTests::runTests()
+void tst_EcmaScriptTests::runJitted()
{
-#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_X86_64)
- QFETCH(QString, qmljsParameter);
-
- QProcess process;
- process.setProcessChannelMode(QProcess::ForwardedChannels);
- process.setWorkingDirectory(QLatin1String(SRCDIR));
- process.setProgram("python");
- process.setArguments(QStringList() << "test262.py" << "--command=" + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs " + qmljsParameter << "--parallel" << "--with-test-expectations");
-
- qDebug() << "Going to run" << process.program() << process.arguments() << "in" << process.workingDirectory();
-
- process.start();
- QVERIFY(process.waitForStarted());
- const int timeoutInMSecs = 20 * 60 * 1000;
- QVERIFY2(process.waitForFinished(timeoutInMSecs), "Tests did not terminate in time -- see output above for details");
- QVERIFY2(process.exitStatus() == QProcess::NormalExit, "Running the test harness failed -- see output above for details");
- QVERIFY2(process.exitCode() == 0, "Tests failed -- see output above for details");
-#else
- QSKIP("Currently the ecmascript tests are only run on Linux/x86-64");
+#if defined(Q_PROCESSOR_X86_64)
+ QDir::setCurrent(QLatin1String(SRCDIR));
+ Test262Runner runner(QString(), "test262");
+ runner.setFlags(Test262Runner::ForceJIT|Test262Runner::WithTestExpectations|Test262Runner::Parallel|Test262Runner::Verbose);
+ bool result = runner.run();
+ QVERIFY(result);
#endif
}
diff --git a/tests/auto/qml/qjsengine/exporterror1.mjs b/tests/auto/qml/qjsengine/exporterror1.mjs
new file mode 100644
index 0000000000..9ce9aa3b83
--- /dev/null
+++ b/tests/auto/qml/qjsengine/exporterror1.mjs
@@ -0,0 +1,2 @@
+let dummy = 0;
+export { nothere } from "./testmodule.mjs";
diff --git a/tests/auto/qml/qjsengine/importerror1.mjs b/tests/auto/qml/qjsengine/importerror1.mjs
new file mode 100644
index 0000000000..be33753c56
--- /dev/null
+++ b/tests/auto/qml/qjsengine/importerror1.mjs
@@ -0,0 +1,2 @@
+let dummy = 0;
+import { nothere } from "./testmodule.mjs";
diff --git a/tests/auto/qml/qjsengine/modulewithlexicals.mjs b/tests/auto/qml/qjsengine/modulewithlexicals.mjs
new file mode 100644
index 0000000000..c31cb5aef3
--- /dev/null
+++ b/tests/auto/qml/qjsengine/modulewithlexicals.mjs
@@ -0,0 +1,9 @@
+class Point {
+ constructor() {}
+}
+
+
+export function main() {
+ (new Point());
+ return 10;
+}
diff --git a/tests/auto/qml/qjsengine/qjsengine.pro b/tests/auto/qml/qjsengine/qjsengine.pro
index c9d78e22a0..b412e37727 100644
--- a/tests/auto/qml/qjsengine/qjsengine.pro
+++ b/tests/auto/qml/qjsengine/qjsengine.pro
@@ -4,5 +4,6 @@ QT += qml qml-private widgets testlib gui-private
macx:CONFIG -= app_bundle
SOURCES += tst_qjsengine.cpp
RESOURCES += qjsengine.qrc
+RESOURCES += testmodule.mjs modulewithlexicals.mjs importerror1.mjs exporterror1.mjs
TESTDATA = script/*
diff --git a/tests/auto/qml/qjsengine/testmodule.mjs b/tests/auto/qml/qjsengine/testmodule.mjs
new file mode 100644
index 0000000000..df561c06a1
--- /dev/null
+++ b/tests/auto/qml/qjsengine/testmodule.mjs
@@ -0,0 +1,6 @@
+
+export var value = 42;
+
+export function sideEffect() {
+ value = value + 1
+}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index a3a2efd565..01b9465f58 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -39,6 +39,8 @@
#include <qqmlcomponent.h>
#include <stdlib.h>
#include <private/qv4alloca_p.h>
+#include <private/qjsvalue_p.h>
+#include <QScopeGuard>
#ifdef Q_CC_MSVC
#define NO_INLINE __declspec(noinline)
@@ -64,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();
@@ -92,6 +98,7 @@ private slots:
void valueConversion_basic2();
void valueConversion_dateTime();
void valueConversion_regExp();
+ void valueConversion_RegularExpression();
void castWithMultipleInheritance();
void collectGarbage();
void gcWithNestedDataStructure();
@@ -128,9 +135,13 @@ private slots:
void JSONparse();
void arraySort();
void lookupOnDisappearingProperty();
+ void arrayConcat();
+ void recursiveBoundFunctions();
void qRegExpInport_data();
void qRegExpInport();
+ void qRegularExpressionImport_data();
+ void qRegularExpressionImport();
void dateRoundtripJSQtJS();
void dateRoundtripQtJSQt();
void dateConversionJSQt();
@@ -145,6 +156,7 @@ private slots:
void array_join_QTBUG_53672();
void regexpLastMatch();
+ void regexpLastIndex();
void indexedAccesses();
void prototypeChainGc();
@@ -172,6 +184,8 @@ private slots:
void translateScriptUnicodeIdBased_data();
void translateScriptUnicodeIdBased();
void translateFromBuiltinCallback();
+ void translationFilePath_data();
+ void translationFilePath();
void installConsoleFunctions();
void logging();
@@ -198,8 +212,41 @@ private slots:
void basicBlockMergeAfterLoopPeeling();
+ void modulusCrash();
void malformedExpression();
+ void scriptScopes();
+
+ void binaryNumbers();
+ void octalNumbers();
+
+ void incrementAfterNewline();
+
+ void deleteInsideForIn();
+
+ void functionToString_data();
+ void functionToString();
+
+ void stringReplace();
+
+ void protoChanges_QTBUG68369();
+ void multilineStrings();
+
+ void throwError();
+ void throwErrorObject();
+ void returnError();
+ void mathMinMax();
+
+ void importModule();
+ void importModuleRelative();
+ void importModuleWithLexicallyScopedVars();
+ void importExportErrors();
+
+public:
+ Q_INVOKABLE QJSValue throwingCppMethod1();
+ Q_INVOKABLE void throwingCppMethod2();
+ Q_INVOKABLE QJSValue throwingCppMethod3();
+
signals:
void testSignal();
};
@@ -438,17 +485,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));
}
}
@@ -462,7 +589,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)"));
+ QCOMPARE(object.toString(), QString::fromLatin1("QPoint(10, 20)"));
}
}
@@ -480,23 +607,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);
- QCOMPARE(rexp.prototype().isRegExp(), 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 RegExp]"));
- QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
-
- QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
+ 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());
+ }
}
void tst_QJSEngine::jsRegExp()
@@ -519,8 +650,7 @@ void tst_QJSEngine::jsRegExp()
QVERIFY(r2.strictlyEquals(r));
QJSValue r3 = rxCtor.call(QJSValueList() << r << "gim");
- QVERIFY(r3.isError());
- QVERIFY(r3.toString().contains(QString::fromLatin1("TypeError"))); // Cannot supply flags when constructing one RegExp from another
+ QVERIFY(!r3.isError());
QJSValue r4 = rxCtor.call(QJSValueList() << "foo" << "gim");
QVERIFY(r4.isRegExp());
@@ -528,9 +658,7 @@ void tst_QJSEngine::jsRegExp()
QJSValue r5 = rxCtor.callAsConstructor(QJSValueList() << r);
QVERIFY(r5.isRegExp());
QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
- // In JSC, constructing a RegExp from another produces the same identical object.
- // This is different from SpiderMonkey and old back-end.
- QVERIFY(!r5.strictlyEquals(r));
+ QVERIFY(r5.strictlyEquals(r));
// See ECMA-262 Section 15.10.4.1, "new RegExp(pattern, flags)".
QJSValue r6 = rxCtor.callAsConstructor(QJSValueList() << "foo" << "bar");
@@ -612,10 +740,10 @@ void tst_QJSEngine::newQObject()
QObject temp;
{
- QJSValue qobject = eng.newQObject(0);
+ QJSValue qobject = eng.newQObject(nullptr);
QCOMPARE(qobject.isNull(), true);
QCOMPARE(qobject.isObject(), false);
- QCOMPARE(qobject.toQObject(), (QObject *)0);
+ QCOMPARE(qobject.toQObject(), (QObject *)nullptr);
}
{
QJSValue qobject = eng.newQObject(&temp);
@@ -636,7 +764,7 @@ void tst_QJSEngine::newQObject_ownership()
QJSEngine eng;
{
QPointer<QObject> ptr = new QObject();
- QVERIFY(ptr != 0);
+ QVERIFY(ptr != nullptr);
{
QJSValue v = eng.newQObject(ptr);
}
@@ -647,7 +775,7 @@ void tst_QJSEngine::newQObject_ownership()
}
{
QPointer<QObject> ptr = new QObject(this);
- QVERIFY(ptr != 0);
+ QVERIFY(ptr != nullptr);
{
QJSValue v = eng.newQObject(ptr);
}
@@ -662,11 +790,11 @@ void tst_QJSEngine::newQObject_ownership()
QJSValue v = eng.newQObject(child);
QCOMPARE(v.toQObject(), child);
delete parent;
- QCOMPARE(v.toQObject(), (QObject *)0);
+ QCOMPARE(v.toQObject(), (QObject *)nullptr);
}
{
QPointer<QObject> ptr = new QObject();
- QVERIFY(ptr != 0);
+ QVERIFY(ptr != nullptr);
{
QJSValue v = eng.newQObject(ptr);
}
@@ -679,18 +807,18 @@ void tst_QJSEngine::newQObject_ownership()
{
QObject *parent = new QObject();
QPointer<QObject> child = new QObject(parent);
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
{
QJSValue v = eng.newQObject(child);
}
eng.collectGarbage();
// has parent, so it should be like QtOwnership
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
delete parent;
}
{
QPointer<QObject> ptr = new QObject();
- QVERIFY(ptr != 0);
+ QVERIFY(ptr != nullptr);
{
QQmlEngine::setObjectOwnership(ptr.data(), QQmlEngine::CppOwnership);
QJSValue v = eng.newQObject(ptr);
@@ -732,23 +860,18 @@ public:
};
Q_ENUMS(Enum1 Enum2)
- Q_INVOKABLE TestQMetaObject()
- : m_called(1) {
- }
+ Q_INVOKABLE TestQMetaObject() {}
Q_INVOKABLE TestQMetaObject(int)
- : m_called(2) {
- }
+ : m_called(2) {}
Q_INVOKABLE TestQMetaObject(QString)
- : m_called(3) {
- }
+ : m_called(3) {}
Q_INVOKABLE TestQMetaObject(QString, int)
- : m_called(4) {
- }
+ : m_called(4) {}
int called() const {
return m_called;
}
private:
- int m_called;
+ int m_called = 1;
};
void tst_QJSEngine::newQObjectPropertyCache()
@@ -939,12 +1062,14 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "decodeURIComponent"
<< "Date"
<< "Array"
+ << "Symbol"
<< "escape"
<< "unescape"
<< "SyntaxError"
<< "undefined"
<< "JSON"
<< "ArrayBuffer"
+ << "SharedArrayBuffer"
<< "DataView"
<< "Int8Array"
<< "Uint8Array"
@@ -955,6 +1080,14 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "Uint32Array"
<< "Float32Array"
<< "Float64Array"
+ << "WeakSet"
+ << "Set"
+ << "WeakMap"
+ << "Map"
+ << "Reflect"
+ << "Proxy"
+ << "Atomics"
+ << "Promise"
;
QSet<QString> actualNames;
{
@@ -1297,8 +1430,8 @@ void tst_QJSEngine::errorMessage_QT679()
struct Foo {
public:
- int x, y;
- Foo() : x(-1), y(-1) { }
+ int x = -1, y = -1;
+ Foo() {}
};
Q_DECLARE_METATYPE(Foo)
@@ -1374,7 +1507,7 @@ void tst_QJSEngine::valueConversion_basic()
QCOMPARE(eng.fromScriptValue<QChar>(eng.toScriptValue(c)), c);
}
- QVERIFY(eng.toScriptValue(static_cast<void *>(0)).isNull());
+ QVERIFY(eng.toScriptValue(static_cast<void *>(nullptr)).isNull());
}
void tst_QJSEngine::valueConversion_QVariant()
@@ -1454,13 +1587,13 @@ void tst_QJSEngine::valueConversion_QVariant()
{
QVariant var = qVariantFromValue(QPoint(123, 456));
QJSValue val = eng.toScriptValue(var);
- QVERIFY(val.isVariant());
+ QVERIFY(!val.isVariant());
QCOMPARE(val.toVariant(), var);
}
QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123));
- QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull());
+ QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, nullptr)).isNull());
QVERIFY(eng.toScriptValue(QVariant::fromValue(nullptr)).isNull());
{
@@ -1560,6 +1693,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)
@@ -1571,7 +1726,7 @@ class Klazz : public QWidget,
Q_INTERFACES(QGraphicsItem)
Q_OBJECT
public:
- Klazz(QWidget *parent = 0) : QWidget(parent) { }
+ Klazz(QWidget *parent = nullptr) : QWidget(parent) { }
virtual QRectF boundingRect() const { return QRectF(); }
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
};
@@ -1600,7 +1755,7 @@ void tst_QJSEngine::collectGarbage()
a = eng.newObject();
a = eng.newObject();
QPointer<QObject> ptr = new QObject();
- QVERIFY(ptr != 0);
+ QVERIFY(ptr != nullptr);
(void)eng.newQObject(ptr);
eng.collectGarbage();
if (ptr)
@@ -1720,6 +1875,22 @@ void tst_QJSEngine::stacktrace()
QJSValue result2 = eng.evaluate(script2, fileName);
QVERIFY(!result2.isError());
QVERIFY(result2.isString());
+
+ {
+ QString script3 = QString::fromLatin1(
+ "'use strict'\n"
+ "function throwUp() { throw new Error('up') }\n"
+ "function indirectlyThrow() { return throwUp() }\n"
+ "indirectlyThrow()\n"
+ );
+ QJSValue result3 = eng.evaluate(script3);
+ QVERIFY(result3.isError());
+ QJSValue stack = result3.property("stack");
+ QVERIFY(stack.isString());
+ QString stackTrace = stack.toString();
+ QVERIFY(!stackTrace.contains(QStringLiteral("indirectlyThrow")));
+ QVERIFY(stackTrace.contains(QStringLiteral("elide")));
+ }
}
void tst_QJSEngine::numberParsing_data()
@@ -2893,6 +3064,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);
@@ -2997,7 +3170,7 @@ void tst_QJSEngine::arraySort()
void tst_QJSEngine::lookupOnDisappearingProperty()
{
QJSEngine eng;
- QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"function(obj) { return obj.someProperty; }\")})()");
+ QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"(function(obj) { return obj.someProperty; })\")})()");
QVERIFY(func.isCallable());
QJSValue o = eng.newObject();
@@ -3010,6 +3183,31 @@ void tst_QJSEngine::lookupOnDisappearingProperty()
QVERIFY(func.call(QJSValueList()<< o).isUndefined());
}
+void tst_QJSEngine::arrayConcat()
+{
+ QJSEngine eng;
+ QJSValue v = eng.evaluate("var x = [1, 2, 3, 4, 5, 6];"
+ "var y = [];"
+ "for (var i = 0; i < 5; ++i)"
+ " x.shift();"
+ "for (var i = 10; i < 13; ++i)"
+ " x.push(i);"
+ "x.toString();");
+ QCOMPARE(v.toString(), QString::fromLatin1("6,10,11,12"));
+}
+
+void tst_QJSEngine::recursiveBoundFunctions()
+{
+
+ QJSEngine eng;
+ QJSValue v = eng.evaluate("function foo(x, y, z)"
+ "{ return this + x + y + z; }"
+ "var bar = foo.bind(-1, 10);"
+ "var baz = bar.bind(-2, 20);"
+ "baz(30)");
+ QCOMPARE(v.toInt(), 59);
+}
+
static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
void tst_QJSEngine::qRegExpInport_data()
@@ -3063,6 +3261,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
@@ -3072,7 +3320,7 @@ void tst_QJSEngine::dateRoundtripJSQtJS()
#ifdef Q_OS_WIN
QSKIP("This test fails on Windows due to a bug in QDateTime.");
#endif
- uint secs = QDateTime(QDate(2009, 1, 1)).toUTC().toTime_t();
+ qint64 secs = QDateTime(QDate(2009, 1, 1)).toUTC().toSecsSinceEpoch();
QJSEngine eng;
for (int i = 0; i < 8000; ++i) {
QJSValue jsDate = eng.evaluate(QString::fromLatin1("new Date(%0)").arg(secs * 1000.0));
@@ -3105,7 +3353,7 @@ void tst_QJSEngine::dateConversionJSQt()
#ifdef Q_OS_WIN
QSKIP("This test fails on Windows due to a bug in QDateTime.");
#endif
- uint secs = QDateTime(QDate(2009, 1, 1)).toUTC().toTime_t();
+ qint64 secs = QDateTime(QDate(2009, 1, 1)).toUTC().toSecsSinceEpoch();
QJSEngine eng;
for (int i = 0; i < 8000; ++i) {
QJSValue jsDate = eng.evaluate(QString::fromLatin1("new Date(%0)").arg(secs * 1000.0));
@@ -3153,10 +3401,9 @@ class ThreadedTestEngine : public QThread {
Q_OBJECT;
public:
- int result;
+ int result = 0;
- ThreadedTestEngine()
- : result(0) {}
+ ThreadedTestEngine() {}
void run() {
QJSEngine firstEngine;
@@ -3180,9 +3427,7 @@ void tst_QJSEngine::threadedEngine()
void tst_QJSEngine::functionDeclarationsInConditionals()
{
- // Even though this is bad practice (and test262 covers it with best practices test cases),
- // we do allow for function declarations in if and while statements, as unfortunately that's
- // real world JavaScript. (QTBUG-33064 for example)
+ // Visibility of function declarations inside blocks is limited to the block
QJSEngine eng;
QJSValue result = eng.evaluate("if (true) {\n"
" function blah() { return false; }\n"
@@ -3190,8 +3435,7 @@ void tst_QJSEngine::functionDeclarationsInConditionals()
" function blah() { return true; }\n"
"}\n"
"blah();");
- QVERIFY(result.isBool());
- QCOMPARE(result.toBool(), true);
+ QVERIFY(result.isError());
}
void tst_QJSEngine::arrayPop_QTBUG_35979()
@@ -3289,6 +3533,28 @@ void tst_QJSEngine::regexpLastMatch()
}
+void tst_QJSEngine::regexpLastIndex()
+{
+ QJSEngine eng;
+ QJSValue result;
+ result = eng.evaluate("function test(text, rx) {"
+ " var res;"
+ " while (res = rx.exec(text)) { "
+ " return true;"
+ " }"
+ " return false;"
+ " }"
+ "function tester(text) {"
+ " return test(text, /,\\s*/g);"
+ "}");
+ QVERIFY(!result.isError());
+
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+}
+
void tst_QJSEngine::indexedAccesses()
{
QJSEngine engine;
@@ -3308,7 +3574,7 @@ void tst_QJSEngine::prototypeChainGc()
QJSValue getProto = engine.evaluate("Object.getPrototypeOf");
- QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }");
+ QJSValue factory = engine.evaluate("(function() { return Object.create(Object.create({})); })");
QVERIFY(factory.isCallable());
QJSValue obj = factory.call();
engine.collectGarbage();
@@ -3347,7 +3613,7 @@ void tst_QJSEngine::dynamicProperties()
QQmlEngine qmlEngine;
QQmlComponent component(&qmlEngine);
component.setData("import QtQml 2.0; QtObject { property QtObject subObject: QtObject {} }", QUrl());
- QObject *root = component.create(0);
+ QObject *root = component.create(nullptr);
QVERIFY(root);
QVERIFY(qmlContext(root));
@@ -3578,7 +3844,7 @@ void tst_QJSEngine::translateScript()
QJSEngine engine;
TranslationScope tranScope(":/translations/translatable_la");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
}
@@ -3587,7 +3853,7 @@ void tst_QJSEngine::translateScript_crossScript()
{
QJSEngine engine;
TranslationScope tranScope(":/translations/translatable_la");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QString fileName = QString::fromLatin1("translatable.js");
QString fileName2 = QString::fromLatin1("translatable2.js");
@@ -3609,7 +3875,7 @@ void tst_QJSEngine::translateScript_trNoOp()
{
QJSEngine engine;
TranslationScope tranScope(":/translations/translatable_la");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined());
QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One"));
@@ -3623,7 +3889,7 @@ void tst_QJSEngine::translateScript_callQsTrFromCpp()
{
QJSEngine engine;
TranslationScope tranScope(":/translations/translatable_la");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
// There is no context, but it shouldn't crash
QCOMPARE(engine.globalObject().property("qsTr").call(QJSValueList() << "One").toString(), QString::fromLatin1("One"));
@@ -3656,7 +3922,7 @@ void tst_QJSEngine::translateWithInvalidArgs()
QFETCH(QString, expression);
QFETCH(QString, expectedError);
QJSEngine engine;
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QJSValue result = engine.evaluate(expression);
QVERIFY(result.isError());
QCOMPARE(result.toString(), expectedError);
@@ -3692,7 +3958,7 @@ void tst_QJSEngine::translationContext()
TranslationScope tranScope(":/translations/translatable_la");
QJSEngine engine;
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QFETCH(QString, path);
QFETCH(QString, text);
@@ -3707,7 +3973,7 @@ void tst_QJSEngine::translateScriptIdBased()
QJSEngine engine;
TranslationScope tranScope(":/translations/idtranslatable_la");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QString fileName = QString::fromLatin1("idtranslatable.js");
@@ -3789,7 +4055,7 @@ void tst_QJSEngine::translateScriptUnicode()
QJSEngine engine;
TranslationScope tranScope(":/translations/translatable-unicode");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QCOMPARE(engine.evaluate(expression, fileName).toString(), expectedTranslation);
}
@@ -3819,7 +4085,7 @@ void tst_QJSEngine::translateScriptUnicodeIdBased()
QJSEngine engine;
TranslationScope tranScope(":/translations/idtranslatable-unicode");
- engine.installTranslatorFunctions();
+ engine.installExtensions(QJSEngine::TranslationExtension);
QCOMPARE(engine.evaluate(expression).toString(), expectedTranslation);
}
@@ -3827,7 +4093,7 @@ void tst_QJSEngine::translateScriptUnicodeIdBased()
void tst_QJSEngine::translateFromBuiltinCallback()
{
QJSEngine eng;
- eng.installTranslatorFunctions();
+ eng.installExtensions(QJSEngine::TranslationExtension);
// Callback has no translation context.
eng.evaluate("function foo() { qsTr('foo'); }");
@@ -3839,6 +4105,73 @@ void tst_QJSEngine::translateFromBuiltinCallback()
eng.evaluate("[10,20].forEach(foo)", "script.js");
}
+void tst_QJSEngine::translationFilePath_data()
+{
+ QTest::addColumn<QString>("filename");
+
+ QTest::newRow("relative") << QStringLiteral("script.js");
+ QTest::newRow("absolute unix") << QStringLiteral("/script.js");
+ QTest::newRow("absolute /windows/") << QStringLiteral("c:/script.js");
+#ifdef Q_OS_WIN
+ QTest::newRow("absolute \\windows\\") << QStringLiteral("c:\\script.js");
+#endif
+ QTest::newRow("relative url") << QStringLiteral("file://script.js");
+ QTest::newRow("absolute url unix") << QStringLiteral("file:///script.js");
+ QTest::newRow("absolute url windows") << QStringLiteral("file://c:/script.js");
+}
+
+class DummyTranslator : public QTranslator
+{
+ Q_OBJECT
+
+public:
+ DummyTranslator(const char *sourceText)
+ : srcTxt(sourceText)
+ {}
+
+ QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override
+ {
+ Q_UNUSED(disambiguation);
+ Q_UNUSED(n);
+
+ if (srcTxt == sourceText)
+ ctxt = QByteArray(context);
+
+ return QString(sourceText);
+ }
+
+ bool isEmpty() const override
+ {
+ return false;
+ }
+
+ const char *sourceText() const
+ { return srcTxt.constData(); }
+
+ QByteArray context() const
+ { return ctxt; }
+
+private:
+ QByteArray srcTxt;
+ mutable QByteArray ctxt;
+};
+
+void tst_QJSEngine::translationFilePath()
+{
+ QFETCH(QString, filename);
+
+ DummyTranslator translator("some text");
+ QCoreApplication::installTranslator(&translator);
+ QByteArray scriptContent = QByteArray("qsTr('%1')").replace("%1", translator.sourceText());
+
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::TranslationExtension);
+ QJSValue result = engine.evaluate(scriptContent, filename);
+ QCOMPARE(translator.context(), QByteArray("script"));
+
+ QCoreApplication::removeTranslator(&translator);
+}
+
void tst_QJSEngine::installConsoleFunctions()
{
QJSEngine engine;
@@ -4033,9 +4366,9 @@ class TestObject : public QObject
{
Q_OBJECT
public:
- TestObject() : called(false) {}
+ TestObject() {}
- bool called;
+ bool called = false;
Q_INVOKABLE void callMe(QQmlV4Function *) {
called = true;
@@ -4089,12 +4422,372 @@ void tst_QJSEngine::basicBlockMergeAfterLoopPeeling()
}
+void tst_QJSEngine::modulusCrash()
+{
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(
+ "var a = -2147483648; var b = -1; var c = a % b; c;"
+ );
+ QVERIFY(result.isNumber() && result.toNumber() == 0.);
+}
+
void tst_QJSEngine::malformedExpression()
{
QJSEngine engine;
engine.evaluate("5%55555&&5555555\n7-0");
}
+void tst_QJSEngine::scriptScopes()
+{
+ QJSEngine engine;
+
+ QJSValue def = engine.evaluate("'use strict'; function foo() { return 42 }");
+ QVERIFY(!def.isError());
+ QJSValue globalObject = engine.globalObject();
+ QJSValue foo = globalObject.property("foo");
+ QVERIFY(foo.isObject());
+ QVERIFY(foo.isCallable());
+
+ QJSValue use = engine.evaluate("'use strict'; foo()");
+ QVERIFY(use.isNumber());
+ QCOMPARE(use.toInt(), 42);
+}
+
+void tst_QJSEngine::binaryNumbers()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("0b1001");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0B1001");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0b2");
+ QVERIFY(result.isError());
+}
+
+void tst_QJSEngine::octalNumbers()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("0o11");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0O11");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0o9");
+ QVERIFY(result.isError());
+}
+
+void tst_QJSEngine::incrementAfterNewline()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("var x = 0; if (\n++x) x; else -x;");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 1);
+
+ result = engine.evaluate("var x = 0; if (\n--x) x; else -x;");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == -1);
+}
+
+void tst_QJSEngine::deleteInsideForIn()
+{
+ QJSEngine engine;
+
+ QJSValue iterationCount = engine.evaluate(
+ "var o = { a: 1, b: 2, c: 3, d: 4};\n"
+ "var count = 0;\n"
+ "for (var prop in o) { count++; delete o[prop]; }\n"
+ "count");
+ QVERIFY(iterationCount.isNumber());
+ QCOMPARE(iterationCount.toInt(), 4);
+}
+
+void tst_QJSEngine::functionToString_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("expectedString");
+
+ QTest::newRow("named function") << QString::fromLatin1("function f() {}; f.toString()")
+ << QString::fromLatin1("function f() { [native code] }");
+ QTest::newRow("anonymous function") << QString::fromLatin1("(function() {}).toString()")
+ << QString::fromLatin1("function() { [native code] }");
+}
+
+// Tests that function.toString() prints the function's name.
+void tst_QJSEngine::functionToString()
+{
+ QFETCH(QString, source);
+ QFETCH(QString, expectedString);
+
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::AllExtensions);
+ QJSValue evaluationResult = engine.evaluate(source);
+ QVERIFY(!evaluationResult.isError());
+ QCOMPARE(evaluationResult.toString(), expectedString);
+}
+
+void tst_QJSEngine::stringReplace()
+{
+ QJSEngine engine;
+
+ QJSValue val = engine.evaluate("'x'.replace('x', '$1')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$1"));
+
+ val = engine.evaluate("'x'.replace('x', '$10')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$10"));
+
+ val = engine.evaluate("'x'.replace('x', '$01')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$01"));
+
+ val = engine.evaluate("'x'.replace('x', '$0')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$0"));
+
+ val = engine.evaluate("'x'.replace('x', '$00')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$00"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$1')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("x"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$01')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("x"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$2')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$2"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$02')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$02"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$0')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$0"));
+
+ val = engine.evaluate("'x'.replace(/(x)/, '$00')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("$00"));
+
+ val = engine.evaluate("'x'.replace(/()()()()()()()()()(x)/, '$11')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("1"));
+
+ val = engine.evaluate("'x'.replace(/()()()()()()()()()(x)/, '$10')");
+ QVERIFY(val.isString());
+ QCOMPARE(val.toString(), QString("x"));
+}
+
+void tst_QJSEngine::protoChanges_QTBUG68369()
+{
+ QJSEngine engine;
+ QJSValue ok = engine.evaluate(
+ "var o = { x: true };"
+ "var p1 = {};"
+ "var p2 = {};"
+ "o.__proto__ = p1;"
+ "o.__proto__ = p2;"
+ "o.__proto__ = p1;"
+ "p1.y = true;"
+ "o.y"
+ );
+ QVERIFY(ok.toBool() == true);
+}
+
+void tst_QJSEngine::multilineStrings()
+{
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(
+ "var x = `a\nb`; x;"
+ );
+ QVERIFY(result.isString());
+ QVERIFY(result.toString() == QStringLiteral("a\nb"));
+
+}
+
+void tst_QJSEngine::throwError()
+{
+ QJSEngine engine;
+ QJSValue wrappedThis = engine.newQObject(this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ engine.globalObject().setProperty("testCase", wrappedThis);
+
+ QJSValue result = engine.evaluate(
+ "function test(){\n"
+ "try {\n"
+ " return testCase.throwingCppMethod1();\n"
+ "} catch (error) {\n"
+ " return error;\n"
+ "}\n"
+ "return \"not reached!\";\n"
+ "}\n"
+ "test();"
+ );
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::GenericError);
+ QCOMPARE(result.property("lineNumber").toString(), "3");
+ QCOMPARE(result.property("message").toString(), "blub");
+ QVERIFY(!result.property("stack").isUndefined());
+}
+
+void tst_QJSEngine::throwErrorObject()
+{
+ QJSEngine engine;
+ QJSValue wrappedThis = engine.newQObject(this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ engine.globalObject().setProperty("testCase", wrappedThis);
+
+ QJSValue result = engine.evaluate(
+ "function test(){\n"
+ " try {\n"
+ " testCase.throwingCppMethod2();\n"
+ " } catch (error) {\n"
+ " if (error instanceof TypeError) {\n"
+ " return error;\n"
+ " }\n"
+ " }\n"
+ " return null;\n"
+ "}\n"
+ "test();"
+ );
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::TypeError);
+ QCOMPARE(result.property("lineNumber").toString(), "3");
+ QCOMPARE(result.property("message").toString(), "Wrong type");
+ QVERIFY(!result.property("stack").isUndefined());
+}
+
+void tst_QJSEngine::returnError()
+{
+ QJSEngine engine;
+ QJSValue wrappedThis = engine.newQObject(this);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ engine.globalObject().setProperty("testCase", wrappedThis);
+
+ QJSValue result = engine.evaluate("testCase.throwingCppMethod3()");
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::EvalError);
+ QCOMPARE(result.property("lineNumber").toString(), "1");
+ QCOMPARE(result.property("message").toString(), "Something is wrong");
+ QVERIFY(!result.property("stack").isUndefined());
+}
+
+QJSValue tst_QJSEngine::throwingCppMethod1()
+{
+ qjsEngine(this)->throwError("blub");
+ return QJSValue(47);
+}
+
+void tst_QJSEngine::throwingCppMethod2()
+{
+ qjsEngine(this)->throwError(QJSValue::TypeError, "Wrong type");
+}
+
+QJSValue tst_QJSEngine::throwingCppMethod3()
+{
+ return qjsEngine(this)->newErrorObject(QJSValue::EvalError, "Something is wrong");
+}
+
+void tst_QJSEngine::mathMinMax()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("var a = .5; Math.min(1, 2, 3.5 + a, '5')");
+ QCOMPARE(result.toNumber(), 1.0);
+ QVERIFY(QJSValuePrivate::getValue(&result) != nullptr);
+ QVERIFY(QJSValuePrivate::getValue(&result)->isInteger());
+
+ result = engine.evaluate("var a = .5; Math.max('0', 1, 2, 3.5 + a)");
+ QCOMPARE(result.toNumber(), 4.0);
+ QVERIFY(QJSValuePrivate::getValue(&result) != nullptr);
+ QVERIFY(QJSValuePrivate::getValue(&result)->isInteger());
+}
+
+void tst_QJSEngine::importModule()
+{
+ // This is just a basic test for the API. Primary test coverage is via the ES test suite.
+ QJSEngine engine;
+ QJSValue ns = engine.importModule(QStringLiteral(":/testmodule.mjs"));
+ QCOMPARE(ns.property("value").toInt(), 42);
+ ns.property("sideEffect").call();
+
+ // Make sure that importing a second time will return the same instance.
+ QJSValue secondNamespace = engine.importModule(QStringLiteral(":/testmodule.mjs"));
+ QCOMPARE(secondNamespace.property("value").toInt(), 43);
+}
+
+void tst_QJSEngine::importModuleRelative()
+{
+ const QString oldWorkingDirectory = QDir::currentPath();
+ auto workingDirectoryGuard = qScopeGuard([oldWorkingDirectory]{
+ QDir::setCurrent(oldWorkingDirectory);
+ });
+
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+ QDir::setCurrent(tempDir.path());
+
+ {
+ QFile f(QStringLiteral("relativemodule.mjs"));
+ QVERIFY(f.open(QIODevice::WriteOnly|QIODevice::Truncate));
+ f.write(QByteArrayLiteral("var value = 100; export { value }; export function change() { value = value + 1 }"));
+ }
+
+ QJSEngine engine;
+
+ {
+ QJSValue module = engine.importModule(QStringLiteral("relativemodule.mjs"));
+ QVERIFY2(!module.isError(), qPrintable(module.toString()));
+ QCOMPARE(module.property("value").toInt(), 100);
+
+ module.property("change").call();
+ }
+
+ {
+ QJSValue sameModule = engine.importModule(tempDir.filePath(QStringLiteral("relativemodule.mjs")));
+ QVERIFY2(!sameModule.isError(), qPrintable(sameModule.toString()));
+ QCOMPARE(sameModule.property("value").toInt(), 101);
+ }
+}
+
+void tst_QJSEngine::importModuleWithLexicallyScopedVars()
+{
+ QJSEngine engine;
+ QJSValue ns = engine.importModule(QStringLiteral(":/modulewithlexicals.mjs"));
+ QVERIFY2(!ns.isError(), qPrintable(ns.toString()));
+ QCOMPARE(ns.property("main").call().toInt(), 10);
+}
+
+void tst_QJSEngine::importExportErrors()
+{
+ {
+ QJSEngine engine;
+ QJSValue result = engine.importModule(QStringLiteral(":/importerror1.mjs"));
+ QVERIFY(result.isError());
+ QCOMPARE(result.property("lineNumber").toInt(), 2);
+ }
+ {
+ QJSEngine engine;
+ QJSValue result = engine.importModule(QStringLiteral(":/exporterror1.mjs"));
+ QVERIFY(result.isError());
+ QCOMPARE(result.property("lineNumber").toInt(), 2);
+ }
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qjsonbinding/qjsonbinding.pro b/tests/auto/qml/qjsonbinding/qjsonbinding.pro
index 75b48aa854..f7a185d27a 100644
--- a/tests/auto/qml/qjsonbinding/qjsonbinding.pro
+++ b/tests/auto/qml/qjsonbinding/qjsonbinding.pro
@@ -3,7 +3,6 @@ TARGET = tst_qjsonbinding
macx:CONFIG -= app_bundle
SOURCES += tst_qjsonbinding.cpp
-INCLUDEPATH += ../../shared
include (../../shared/util.pri)
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index 12c33909cf..2b80970559 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -30,7 +30,7 @@
#include <QtWidgets/QPushButton>
tst_QJSValue::tst_QJSValue()
- : engine(0)
+ : engine(nullptr)
{
}
@@ -45,7 +45,7 @@ void tst_QJSValue::ctor_invalid()
{
QJSValue v;
QVERIFY(v.isUndefined());
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
}
@@ -111,7 +111,7 @@ void tst_QJSValue::ctor_int()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
}
@@ -141,7 +141,7 @@ void tst_QJSValue::ctor_uint()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
}
@@ -171,7 +171,7 @@ void tst_QJSValue::ctor_float()
QCOMPARE(v.isNumber(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toNumber(), 1.0);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
}
@@ -196,7 +196,7 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
{
QJSValue v("ciao");
@@ -204,7 +204,7 @@ void tst_QJSValue::ctor_string()
QCOMPARE(v.isString(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toString(), QLatin1String("ciao"));
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
}
@@ -246,7 +246,7 @@ void tst_QJSValue::ctor_undefined()
QJSValue v(QJSValue::UndefinedValue);
QVERIFY(v.isUndefined());
QCOMPARE(v.isObject(), false);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
void tst_QJSValue::ctor_null()
@@ -255,7 +255,7 @@ void tst_QJSValue::ctor_null()
QVERIFY(!v.isUndefined());
QCOMPARE(v.isNull(), true);
QCOMPARE(v.isObject(), false);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
void tst_QJSValue::ctor_bool()
@@ -266,7 +266,7 @@ void tst_QJSValue::ctor_bool()
QCOMPARE(v.isBool(), true);
QCOMPARE(v.isObject(), false);
QCOMPARE(v.toBool(), false);
- QCOMPARE(v.engine(), (QJSEngine *)0);
+ QCOMPARE(v.engine(), (QJSEngine *)nullptr);
}
void tst_QJSValue::ctor_copyAndAssign()
@@ -274,12 +274,12 @@ void tst_QJSValue::ctor_copyAndAssign()
QJSValue v(1.0);
QJSValue v2(v);
QCOMPARE(v2.strictlyEquals(v), true);
- QCOMPARE(v2.engine(), (QJSEngine *)0);
+ QCOMPARE(v2.engine(), (QJSEngine *)nullptr);
QJSValue v3(v);
QCOMPARE(v3.strictlyEquals(v), true);
QCOMPARE(v3.strictlyEquals(v2), true);
- QCOMPARE(v3.engine(), (QJSEngine *)0);
+ QCOMPARE(v3.engine(), (QJSEngine *)nullptr);
QJSValue v4(2.0);
QCOMPARE(v4.strictlyEquals(v), false);
@@ -404,8 +404,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)"));
+ QVERIFY(!variant.isVariant());
+ QCOMPARE(variant.toString(), QString::fromLatin1("QPoint(10, 20)"));
variant = eng.toScriptValue(QUrl());
QVERIFY(variant.isVariant());
QVERIFY(variant.toString().isEmpty());
@@ -970,10 +970,6 @@ void tst_QJSValue::toUInt()
QCOMPARE(qjsvalue_cast<quint32>(inv), quint32(0));
}
-#if defined Q_CC_MSVC && _MSC_VER < 1300
-Q_DECLARE_METATYPE(QVariant)
-#endif
-
void tst_QJSValue::toVariant()
{
QJSEngine eng;
@@ -1031,6 +1027,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));
}
@@ -1111,16 +1121,16 @@ 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*)0));
- QTest::newRow("newQObject(0)") << engine->newQObject(0);
+ QTest::newRow("variant((QObject*)0)") << engine->toScriptValue(qVariantFromValue((QObject*)nullptr));
+ QTest::newRow("newQObject(0)") << engine->newQObject(nullptr);
}
void tst_QJSValue::toQObject_nonQObject()
{
QFETCH(QJSValue, value);
- QCOMPARE(value.toQObject(), (QObject *)0);
- QCOMPARE(qjsvalue_cast<QObject*>(value), (QObject *)0);
+ QCOMPARE(value.toQObject(), (QObject *)nullptr);
+ QCOMPARE(qjsvalue_cast<QObject*>(value), (QObject *)nullptr);
}
// unfortunately, this is necessary in order to do qscriptvalue_cast<QPushButton*>(...)
@@ -1134,7 +1144,7 @@ void tst_QJSValue::toQObject()
QJSValue qobject = eng.newQObject(&temp);
QCOMPARE(qobject.toQObject(), (QObject *)&temp);
QCOMPARE(qjsvalue_cast<QObject*>(qobject), (QObject *)&temp);
- QCOMPARE(qjsvalue_cast<QWidget*>(qobject), (QWidget *)0);
+ QCOMPARE(qjsvalue_cast<QWidget*>(qobject), (QWidget *)nullptr);
QWidget widget;
QJSValue qwidget = eng.newQObject(&widget);
@@ -1198,6 +1208,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();
@@ -1263,7 +1299,7 @@ void tst_QJSValue::isError_propertiesOfGlobalObject()
for (int i = 0; i < errors.size(); ++i) {
QJSValue ctor = eng.globalObject().property(errors.at(i));
QVERIFY(ctor.isCallable());
- QVERIFY(ctor.property("prototype").isError());
+ QVERIFY(ctor.property("prototype").isObject());
}
}
@@ -1598,7 +1634,7 @@ void tst_QJSValue::getSetProperty()
QCOMPARE(object.property("baz").toNumber(), num.toNumber());
QJSValue strstr = QJSValue("bar");
- QCOMPARE(strstr.engine(), (QJSEngine *)0);
+ QCOMPARE(strstr.engine(), (QJSEngine *)nullptr);
object.setProperty("foo", strstr);
QCOMPARE(object.property("foo").toString(), strstr.toString());
QCOMPARE(strstr.engine(), &eng); // the value has been bound to the engine
@@ -1642,7 +1678,7 @@ void tst_QJSValue::getSetPrototype_evalCyclicPrototype()
QJSEngine eng;
QJSValue ret = eng.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o");
QCOMPARE(ret.isError(), true);
- QCOMPARE(ret.toString(), QLatin1String("TypeError: Cyclic __proto__ value"));
+ QCOMPARE(ret.toString(), QLatin1String("TypeError: Could not change prototype."));
}
void tst_QJSValue::getSetPrototype_eval()
@@ -2099,7 +2135,7 @@ void tst_QJSValue::equals()
QJSValue qobj1 = eng.newQObject(&temp);
QJSValue qobj2 = eng.newQObject(&temp);
- QJSValue qobj3 = eng.newQObject(0);
+ QJSValue qobj3 = eng.newQObject(nullptr);
// FIXME: No ScriptOwnership: QJSValue qobj4 = eng.newQObject(new QObject(), QScriptEngine::ScriptOwnership);
QJSValue qobj4 = eng.newQObject(new QObject());
@@ -2252,8 +2288,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));
}
{
@@ -2285,7 +2321,7 @@ void tst_QJSValue::castToPointer()
QColor c(123, 210, 231);
QJSValue v = eng.toScriptValue(c);
QColor *cp = qjsvalue_cast<QColor*>(v);
- QVERIFY(cp != 0);
+ QVERIFY(cp != nullptr);
QCOMPARE(*cp, c);
QBrush *bp = qjsvalue_cast<QBrush*>(v);
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
index b8b9f4403c..9532b1f10e 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
@@ -76,6 +76,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 59566ad927..86f36286d9 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
+QT_FOR_CONFIG += qml
METATYPETESTS += \
qqmlmetatype
@@ -7,8 +8,9 @@ PUBLICTESTS += \
parserstress \
qjsvalueiterator \
qjsonbinding \
+ qqmlfile \
+ qqmlfileselector
-!boot2qt {
PUBLICTESTS += \
qmlmin \
qqmlcomponent \
@@ -24,21 +26,19 @@ PUBLICTESTS += \
qqmlnotifier \
qqmlqt \
qqmlxmlhttprequest \
+ qqmlpromise \
qtqmlmodules \
qquickfolderlistmodel \
qqmlapplicationengine \
qqmlsettings \
qqmlstatemachine \
qmldiskcache
-}
PRIVATETESTS += \
qqmlcpputils \
qqmldirparser \
- v4misc \
qmlcachegen
-!boot2qt {
PRIVATETESTS += \
animation \
qqmlecmascript \
@@ -70,21 +70,29 @@ PRIVATETESTS += \
qqmltranslation \
qqmlimport \
qqmlobjectmodel \
+ qqmltablemodel \
+ qv4assembler \
qv4mm \
- ecmascripttests
-}
+ qv4identifiertable \
+ qv4regexp \
+ ecmascripttests \
+ bindingdependencyapi \
+ v4misc
qtHaveModule(widgets) {
PUBLICTESTS += \
qjsengine \
- qjsvalue
+ qjsvalue \
+# qwidgetsinqml
}
SUBDIRS += $$PUBLICTESTS
SUBDIRS += $$METATYPETESTS
-qtConfig(process):!boot2qt {
- !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
- SUBDIRS += qmllint qmlplugindump
+qtConfig(process) {
+ qtConfig(qml-debug): SUBDIRS += debugger
+ !boot2qt {
+ SUBDIRS += qmllint qmlplugindump
+ }
}
qtConfig(library) {
@@ -97,3 +105,7 @@ qtConfig(private_tests): \
qtNomakeTools( \
qmlplugindump \
)
+
+QtConfig(qml_tracing) {
+ PRIVATETESTS += v4traced
+}
diff --git a/tests/auto/qml/qmlcachegen/Enums.qml b/tests/auto/qml/qmlcachegen/Enums.qml
new file mode 100644
index 0000000000..830babb73e
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/Enums.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+QtObject {
+ enum Test {
+ First = 100,
+ Second = 200
+ }
+ property int value: 0
+ Component.onCompleted: value = Enums.Second
+}
diff --git a/tests/auto/qml/qmlcachegen/Retain.qml b/tests/auto/qml/qmlcachegen/Retain.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/Retain.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/qml/qmlcachegen/jsimport.qml b/tests/auto/qml/qmlcachegen/jsimport.qml
new file mode 100644
index 0000000000..9c40878e60
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/jsimport.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import "script.js" as Script
+
+QtObject {
+ property int value: Script.getter()
+}
diff --git a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml b/tests/auto/qml/qmlcachegen/jsmoduleimport.qml
new file mode 100644
index 0000000000..c1fad7fee2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/jsmoduleimport.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import "script.mjs" as Script
+
+QtObject {
+ property bool ok: Script.ok()
+}
diff --git a/tests/auto/qml/qmlcachegen/library.js b/tests/auto/qml/qmlcachegen/library.js
new file mode 100644
index 0000000000..51fb41dc23
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/library.js
@@ -0,0 +1,4 @@
+
+function getter() {
+ return 42;
+}
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
index 8d8b37be15..c7820ac1cd 100644
--- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -1,7 +1,27 @@
-CONFIG += testcase
+CONFIG += testcase qtquickcompiler
TARGET = tst_qmlcachegen
macos:CONFIG -= app_bundle
SOURCES += tst_qmlcachegen.cpp
+workerscripts_test.files = worker.js worker.qml
+workerscripts_test.prefix = /workerscripts
+RESOURCES += workerscripts_test
+
+RESOURCES += versionchecks.qml
+
+RESOURCES += trickypaths.qrc
+
+RESOURCES += jsimport.qml script.js library.js
+
+RESOURCES += Enums.qml
+
+# QTBUG-46375
+!win32: RESOURCES += trickypaths_umlaut.qrc
+
+RESOURCES += jsmoduleimport.qml script.mjs
+
+RESOURCES += retain.qrc
+QTQUICK_COMPILER_RETAINED_RESOURCES += retain.qrc
+
QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmlcachegen/retain.qrc b/tests/auto/qml/qmlcachegen/retain.qrc
new file mode 100644
index 0000000000..af042b25d8
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/retain.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>Retain.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qml/qmlcachegen/script.js b/tests/auto/qml/qmlcachegen/script.js
new file mode 100644
index 0000000000..fa55f9069e
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/script.js
@@ -0,0 +1,6 @@
+
+.import "library.js" as Library
+
+function getter() {
+ return Library.getter()
+}
diff --git a/tests/auto/qml/qmlcachegen/script.mjs b/tests/auto/qml/qmlcachegen/script.mjs
new file mode 100644
index 0000000000..459c336125
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/script.mjs
@@ -0,0 +1,4 @@
+
+export function ok() {
+ return true
+}
diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qml b/tests/auto/qml/qmlcachegen/trickypaths.qml
new file mode 100644
index 0000000000..0836808dc2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/trickypaths.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc
new file mode 100644
index 0000000000..57977ccf6d
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/directory with spaces">
+<file alias="file name with spaces.qml">trickypaths.qml</file>
+<file>versionStyleSuffix-1.2-core-yc.qml</file>
+<file>versionStyleSuffix-1.2-more.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc
new file mode 100644
index 0000000000..9ca889d692
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+<file alias="Bäh.qml">umlaut.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index b7e616a050..8cfa4cb6af 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -32,7 +32,11 @@
#include <QQmlEngine>
#include <QProcess>
#include <QLibraryInfo>
+#include <QStandardPaths>
#include <QSysInfo>
+#include <QLoggingCategory>
+#include <private/qqmlcomponent_p.h>
+#include <qtranslator.h>
class tst_qmlcachegen: public QObject
{
@@ -43,6 +47,25 @@ private slots:
void loadGeneratedFile();
void translationExpressionSupport();
+ void signalHandlerParameters();
+ void errorOnArgumentsInSignalHandler();
+ void aheadOfTimeCompilation();
+ void functionExpressions();
+ void versionChecksForAheadOfTimeUnits();
+ void retainedResources();
+
+ void workerScripts();
+
+ void trickyPaths_data();
+ void trickyPaths();
+
+ void qrcScriptImport();
+ void fsScriptImport();
+ void moduleScriptImport();
+
+ void enums();
+
+ void sourceFileIndices();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -67,15 +90,20 @@ public:
}
};
-static bool generateCache(const QString &qmlFileName)
+static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr = nullptr)
{
QProcess proc;
- proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ if (capturedStderr == nullptr)
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
- proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
+ proc.setArguments(QStringList() << qmlFileName);
proc.start();
if (!proc.waitForFinished())
return false;
+
+ if (capturedStderr)
+ *capturedStderr = proc.readAllStandardError();
+
if (proc.exitStatus() != QProcess::NormalExit)
return false;
return proc.exitCode() == 0;
@@ -84,6 +112,13 @@ static bool generateCache(const QString &qmlFileName)
void tst_qmlcachegen::initTestCase()
{
qputenv("QML_FORCE_DISK_CACHE", "1");
+ QStandardPaths::setTestModeEnabled(true);
+
+ // make sure there's no pre-existing cache dir
+ QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ if (!cacheDir.isEmpty())
+ //QDir(cacheDir).removeRecursively();
+ qDebug() << cacheDir;
}
void tst_qmlcachegen::loadGeneratedFile()
@@ -108,6 +143,17 @@ void tst_qmlcachegen::loadGeneratedFile()
const QString cacheFilePath = testFilePath + QLatin1Char('c');
QVERIFY(QFile::exists(cacheFilePath));
+
+ {
+ QFile cache(cacheFilePath);
+ QVERIFY(cache.open(QIODevice::ReadOnly));
+ const QV4::CompiledData::Unit *cacheUnit = reinterpret_cast<const QV4::CompiledData::Unit *>(cache.map(/*offset*/0, sizeof(QV4::CompiledData::Unit)));
+ QVERIFY(cacheUnit);
+ QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::StaticData);
+ QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+ QCOMPARE(uint(cacheUnit->sourceFileIndex), uint(0));
+ }
+
QVERIFY(QFile::remove(testFilePath));
QQmlEngine engine;
@@ -115,13 +161,36 @@ void tst_qmlcachegen::loadGeneratedFile()
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
+
+ auto componentPrivate = QQmlComponentPrivate::get(&component);
+ QVERIFY(componentPrivate);
+ auto compilationUnit = componentPrivate->compilationUnit;
+ QVERIFY(compilationUnit);
+ auto unitData = compilationUnit->unitData();
+ QVERIFY(unitData);
+ QVERIFY(unitData->flags & QV4::CompiledData::Unit::StaticData);
}
+class QTestTranslator : public QTranslator
+{
+public:
+ QString translate(const char *context, const char *sourceText, const char */*disambiguation*/, int /*n*/) const override
+ {
+ m_lastContext = QString::fromUtf8(context);
+ return QString::fromUtf8(sourceText).toUpper();
+ }
+ bool isEmpty() const override { return true; }
+ mutable QString m_lastContext;
+};
+
void tst_qmlcachegen::translationExpressionSupport()
{
QTemporaryDir tempDir;
QVERIFY(tempDir.isValid());
+ QTestTranslator translator;
+ qApp->installTranslator(&translator);
+
const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
QFile f(tempDir.path() + '/' + fileName);
const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
@@ -155,7 +224,395 @@ void tst_qmlcachegen::translationExpressionSupport()
CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
- QCOMPARE(obj->property("text").toString(), QString("All Ok"));
+ QCOMPARE(obj->property("text").toString(), QString("ALL Ok"));
+ QCOMPARE(translator.m_lastContext, QStringLiteral("test"));
+}
+
+void tst_qmlcachegen::signalHandlerParameters()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n"
+ "QtObject {\n"
+ " property real result: 0\n"
+ " signal testMe(real value);\n"
+ " onTestMe: result = value;\n"
+ " function runTest() { testMe(42); }\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ {
+ QFile cache(cacheFilePath);
+ QVERIFY(cache.open(QIODevice::ReadOnly));
+ const QV4::CompiledData::Unit *cacheUnit = reinterpret_cast<const QV4::CompiledData::Unit *>(cache.map(/*offset*/0, sizeof(QV4::CompiledData::Unit)));
+ QVERIFY(cacheUnit);
+ }
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QMetaObject::invokeMethod(obj.data(), "runTest");
+ QCOMPARE(obj->property("result").toInt(), 42);
+
+ {
+ auto componentPrivate = QQmlComponentPrivate::get(&component);
+ QVERIFY(componentPrivate);
+ auto compilationUnit = componentPrivate->compilationUnit;
+ QVERIFY(compilationUnit);
+ QVERIFY(compilationUnit->unitData());
+
+ // Verify that the QML objects don't come from the original data.
+ QVERIFY(compilationUnit->objectAt(0) != compilationUnit->unitData()->qmlUnit()->objectAt(0));
+
+ // Typically the final file name is one of those strings that is not in the original
+ // pre-compiled qml file's string table, while for example the signal parameter
+ // name ("value") is.
+ const auto isStringIndexInStringTable = [compilationUnit](uint index) {
+ return index < compilationUnit->unitData()->stringTableSize;
+ };
+
+ QVERIFY(isStringIndexInStringTable(compilationUnit->objectAt(0)->signalAt(0)->parameterAt(0)->nameIndex));
+ QVERIFY(!compilationUnit->dynamicStrings.isEmpty());
+ }
+}
+
+void tst_qmlcachegen::errorOnArgumentsInSignalHandler()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.2\n"
+ "QtObject {\n"
+ " signal mySignal(var arguments);\n"
+ " onMySignal: console.log(arguments);\n"
+ "}");
+
+
+ QByteArray errorOutput;
+ QVERIFY(!generateCache(testFilePath, &errorOutput));
+ QVERIFY2(errorOutput.contains("error: The use of eval() or the use of the arguments object in signal handlers is"), errorOutput);
+}
+
+void tst_qmlcachegen::aheadOfTimeCompilation()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n"
+ "QtObject {\n"
+ " function runTest() { var x = 0; while (x < 42) { ++x }; return x; }\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVariant result;
+ QMetaObject::invokeMethod(obj.data(), "runTest", Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result.toInt(), 42);
+}
+
+static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr;
+
+void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
+{
+ QVERIFY(QFile::exists(":/versionchecks.qml"));
+ QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0);
+
+ Q_ASSERT(!temporaryModifiedCachedUnit);
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error);
+ QVERIFY(originalUnit);
+ QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->unitSize);
+ memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit), originalUnit->unitSize);
+ tweakedUnit->version = QV4_DATA_STRUCTURE_VERSION - 1;
+ temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr};
+
+ auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * {
+ if (url == QUrl("qrc:/versionchecks.qml"))
+ return temporaryModifiedCachedUnit;
+ return nullptr;
+ };
+ QQmlMetaType::prependCachedUnitLookupFunction(testHandler);
+
+ {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error));
+ QCOMPARE(error, QQmlMetaType::CachedUnitLookupError::VersionMismatch);
+ }
+
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc:/versionchecks.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Error);
+ QCOMPARE(component.errorString(), QString("qrc:/versionchecks.qml:-1 File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile\n"));
+ }
+
+ Q_ASSERT(temporaryModifiedCachedUnit);
+ free(const_cast<QV4::CompiledData::Unit *>(temporaryModifiedCachedUnit->qmlData));
+ delete temporaryModifiedCachedUnit;
+ temporaryModifiedCachedUnit = nullptr;
+
+ QQmlMetaType::removeCachedUnitLookupFunction(testHandler);
+}
+
+void tst_qmlcachegen::retainedResources()
+{
+ QFile file(":/Retain.qml");
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QVERIFY(file.readAll().startsWith("import QtQml 2.0"));
+}
+
+void tst_qmlcachegen::workerScripts()
+{
+ QVERIFY(QFile::exists(":/workerscripts/worker.js"));
+ QVERIFY(QFile::exists(":/workerscripts/worker.qml"));
+ QCOMPARE(QFileInfo(":/workerscripts/worker.js").size(), 0);
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/worker.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success").toBool());
+}
+
+void tst_qmlcachegen::functionExpressions()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile(
+ "test.qml",
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " id: di\n"
+ " \n"
+ " property var f\n"
+ " property bool f_called: false\n"
+ " f : function() { f_called = true }\n"
+ " \n"
+ " signal g\n"
+ " property bool g_handler_called: false\n"
+ " onG: function() { g_handler_called = true }\n"
+ " \n"
+ " signal h(int i)\n"
+ " property bool h_connections_handler_called: false\n"
+ " Connections {\n"
+ " target: di\n"
+ " onH: function(magic) { h_connections_handler_called = (magic == 42)\n }\n"
+ " }\n"
+ " \n"
+ " function runTest() { \n"
+ " f()\n"
+ " g()\n"
+ " h(42)\n"
+ " }\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QCOMPARE(obj->property("f_called").toBool(), false);
+ QCOMPARE(obj->property("g_handler_called").toBool(), false);
+ QCOMPARE(obj->property("h_connections_handler_called").toBool(), false);
+
+ QMetaObject::invokeMethod(obj.data(), "runTest");
+
+ QCOMPARE(obj->property("f_called").toBool(), true);
+ QCOMPARE(obj->property("g_handler_called").toBool(), true);
+ QCOMPARE(obj->property("h_connections_handler_called").toBool(), true);
+}
+
+void tst_qmlcachegen::trickyPaths_data()
+{
+ QTest::addColumn<QString>("filePath");
+ QTest::newRow("path with spaces") << QStringLiteral(":/directory with spaces/file name with spaces.qml");
+ QTest::newRow("version style suffix 1") << QStringLiteral(":/directory with spaces/versionStyleSuffix-1.2-core-yc.qml");
+ QTest::newRow("version style suffix 2") << QStringLiteral(":/directory with spaces/versionStyleSuffix-1.2-more.qml");
+
+ // QTBUG-46375
+#if !defined(Q_OS_WIN)
+ QTest::newRow("path with umlaut") << QStringLiteral(":/Bäh.qml");
+#endif
+}
+
+void tst_qmlcachegen::trickyPaths()
+{
+ QFETCH(QString, filePath);
+ QVERIFY2(QFile::exists(filePath), qPrintable(filePath));
+ QCOMPARE(QFileInfo(filePath).size(), 0);
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc" + filePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("success").toInt(), 42);
+}
+
+void tst_qmlcachegen::qrcScriptImport()
+{
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsimport.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QTRY_COMPARE(obj->property("value").toInt(), 42);
+}
+
+void tst_qmlcachegen::fsScriptImport()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile(
+ "test.qml",
+ "import QtQml 2.0\n"
+ "import \"test.js\" as ScriptTest\n"
+ "QtObject {\n"
+ " property int value: ScriptTest.value\n"
+ "}\n");
+
+ const QString scriptFilePath = writeTempFile(
+ "test.js",
+ "var value = 42"
+ );
+
+ QVERIFY(generateCache(scriptFilePath));
+ QVERIFY(generateCache(testFilePath));
+
+ const QString scriptCacheFilePath = scriptFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(scriptFilePath));
+
+ {
+ QFile cache(scriptCacheFilePath);
+ QVERIFY(cache.open(QIODevice::ReadOnly));
+ const QV4::CompiledData::Unit *cacheUnit = reinterpret_cast<const QV4::CompiledData::Unit *>(cache.map(/*offset*/0, sizeof(QV4::CompiledData::Unit)));
+ QVERIFY(cacheUnit);
+ QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::StaticData);
+ QVERIFY(!(cacheUnit->flags & QV4::CompiledData::Unit::PendingTypeCompilation));
+ QCOMPARE(uint(cacheUnit->sourceFileIndex), uint(0));
+ }
+
+ // Remove source code to make sure that when loading succeeds, it is because we loaded
+ // the existing cache files.
+ QVERIFY(QFile::remove(testFilePath));
+ QVERIFY(QFile::remove(scriptFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+}
+
+void tst_qmlcachegen::moduleScriptImport()
+{
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsmoduleimport.qml"));
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("ok").toBool());
+
+ QVERIFY(QFile::exists(":/script.mjs"));
+ QCOMPARE(QFileInfo(":/script.mjs").size(), 0);
+
+ {
+ auto componentPrivate = QQmlComponentPrivate::get(&component);
+ QVERIFY(componentPrivate);
+ auto compilationUnit = componentPrivate->compilationUnit->dependentScripts.first()->compilationUnit();
+ QVERIFY(compilationUnit);
+ auto unitData = compilationUnit->unitData();
+ QVERIFY(unitData);
+ QVERIFY(unitData->flags & QV4::CompiledData::Unit::StaticData);
+ QVERIFY(unitData->flags & QV4::CompiledData::Unit::IsESModule);
+
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/script.mjs"), &error);
+ QVERIFY(unitFromResources);
+
+ QCOMPARE(unitFromResources, compilationUnit->unitData());
+ }
+}
+
+void tst_qmlcachegen::enums()
+{
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:///Enums.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QTRY_COMPARE(obj->property("value").toInt(), 200);
+}
+
+void tst_qmlcachegen::sourceFileIndices()
+{
+ QVERIFY(QFile::exists(":/versionchecks.qml"));
+ QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0);
+
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error);
+ QVERIFY(unitFromResources);
+ QVERIFY(unitFromResources->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+ QCOMPARE(uint(unitFromResources->sourceFileIndex), uint(0));
}
QTEST_GUILESS_MAIN(tst_qmlcachegen)
diff --git a/tests/auto/qml/qmlcachegen/umlaut.qml b/tests/auto/qml/qmlcachegen/umlaut.qml
new file mode 100644
index 0000000000..0836808dc2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/umlaut.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml
new file mode 100644
index 0000000000..0836808dc2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml
new file mode 100644
index 0000000000..0836808dc2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/qml/qmlcachegen/versionchecks.qml b/tests/auto/qml/qmlcachegen/versionchecks.qml
new file mode 100644
index 0000000000..77d67e7da4
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/versionchecks.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property bool ok: true
+}
diff --git a/tests/auto/qml/qmlcachegen/worker.js b/tests/auto/qml/qmlcachegen/worker.js
new file mode 100644
index 0000000000..dd2d0b843d
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/worker.js
@@ -0,0 +1,3 @@
+WorkerScript.onMessage = function(message) {
+ WorkerScript.sendMessage({ reply: message });
+}
diff --git a/tests/auto/qml/qmlcachegen/worker.qml b/tests/auto/qml/qmlcachegen/worker.qml
new file mode 100644
index 0000000000..1f1c9d1ac7
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/worker.qml
@@ -0,0 +1,12 @@
+import QtQml 2.0
+import QtQuick 2.0
+QtObject {
+ property bool success: false
+ property WorkerScript worker: WorkerScript {
+ source: "worker.js"
+ onMessage: {
+ success = true
+ }
+ }
+ Component.onCompleted: worker.sendMessage("Hello")
+}
diff --git a/tests/auto/qml/qmldiskcache/importmodule.qml b/tests/auto/qml/qmldiskcache/importmodule.qml
new file mode 100644
index 0000000000..f890d4cb5c
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/importmodule.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import "module.mjs" as Module
+QtObject {
+ property bool ok: Module.ok()
+}
diff --git a/tests/auto/qml/qmldiskcache/module.mjs b/tests/auto/qml/qmldiskcache/module.mjs
new file mode 100644
index 0000000000..32e0651b8b
--- /dev/null
+++ b/tests/auto/qml/qmldiskcache/module.mjs
@@ -0,0 +1,2 @@
+
+export function ok() { return true; }
diff --git a/tests/auto/qml/qmldiskcache/qmldiskcache.pro b/tests/auto/qml/qmldiskcache/qmldiskcache.pro
index f98a157b6a..74aefa6944 100644
--- a/tests/auto/qml/qmldiskcache/qmldiskcache.pro
+++ b/tests/auto/qml/qmldiskcache/qmldiskcache.pro
@@ -4,6 +4,6 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qmldiskcache.cpp
-RESOURCES += test.qml
+RESOURCES += test.qml importmodule.qml module.mjs
QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 3402aeebc1..70a5a73e0f 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -30,10 +30,10 @@
#include <private/qv4compileddata_p.h>
#include <private/qv4compiler_p.h>
-#include <private/qv4jsir_p.h>
-#include <private/qv4isel_p.h>
#include <private/qv8engine_p.h>
#include <private/qv4engine_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qqmlcomponent_p.h>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQmlFileSelector>
@@ -48,7 +48,9 @@ class tst_qmldiskcache: public QObject
private slots:
void initTestCase();
+ void cleanupTestCase();
+ void loadLocalAsFallback();
void regenerateAfterChange();
void registerImportForImplicitComponent();
void basicVersionChecks();
@@ -59,6 +61,11 @@ private slots:
void cacheResources();
void stableOrderOfDependentCompositeTypes();
void singletonDependency();
+ void cppRegisteredSingletonDependency();
+ void cacheModuleScripts();
+
+private:
+ QDir m_qmlCacheDirectory;
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -89,7 +96,13 @@ static void waitForFileSystem()
// the newly written file has a modification date newer than an existing cache file, we must
// wait.
// Similar effects of lacking precision have been observed on some Linux systems.
- QThread::sleep(1);
+ static const bool fsHasSubSecondResolution = []() {
+ QDateTime mtime = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)).lastModified();
+ // 1:1000 chance of a false negative
+ return mtime.toMSecsSinceEpoch() % 1000;
+ }();
+ if (!fsHasSubSecondResolution)
+ QThread::sleep(1);
}
struct TestCompiler
@@ -106,7 +119,7 @@ struct TestCompiler
{
closeMapping();
testFilePath = baseDirectory + QStringLiteral("/test.qml");
- cacheFilePath = baseDirectory + QStringLiteral("/test.qmlc");
+ cacheFilePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
mappedFile.setFileName(cacheFilePath);
}
@@ -173,9 +186,8 @@ struct TestCompiler
bool verify()
{
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
- return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), v4->iselFactory.data(), &lastErrorString);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
+ return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), &lastErrorString);
}
void closeMapping()
@@ -205,6 +217,58 @@ struct TestCompiler
void tst_qmldiskcache::initTestCase()
{
qputenv("QML_FORCE_DISK_CACHE", "1");
+ QStandardPaths::setTestModeEnabled(true);
+
+ const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ m_qmlCacheDirectory.setPath(cacheDirectory + QLatin1String("/qmlcache"));
+ if (m_qmlCacheDirectory.exists())
+ QVERIFY(m_qmlCacheDirectory.removeRecursively());
+ QVERIFY(QDir::root().mkpath(m_qmlCacheDirectory.absolutePath()));
+}
+
+void tst_qmldiskcache::cleanupTestCase()
+{
+ m_qmlCacheDirectory.removeRecursively();
+}
+
+void tst_qmldiskcache::loadLocalAsFallback()
+{
+ QQmlEngine engine;
+ TestCompiler testCompiler(&engine);
+
+ QVERIFY(testCompiler.tempDir.isValid());
+
+ const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n"
+ "QtObject {\n"
+ " property string blah: Qt.platform;\n"
+ "}");
+
+ QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
+
+ // Create an invalid side-by-side .qmlc
+ {
+ QFile f(testCompiler.tempDir.path() + "/test.qmlc");
+ QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
+ QV4::CompiledData::Unit unit = {};
+ memcpy(unit.magic, QV4::CompiledData::magic_str, sizeof(unit.magic));
+ unit.version = QV4_DATA_STRUCTURE_VERSION;
+ unit.qtVersion = QT_VERSION;
+ unit.sourceTimeStamp = testCompiler.mappedFile.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch();
+ unit.unitSize = ~0U; // make the size a silly number
+ // write something to the library hash that should cause it not to be loaded
+ memset(unit.libraryVersionHash, 'z', sizeof(unit.libraryVersionHash));
+ memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
+
+ // leave the other fields unset, since they don't matter
+
+ 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(),
+ &testCompiler.lastErrorString);
+ QVERIFY2(loaded, qPrintable(testCompiler.lastErrorString));
+ QCOMPARE(unit->objectCount(), 1);
}
void tst_qmldiskcache::regenerateAfterChange()
@@ -225,17 +289,21 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
- QCOMPARE(quint32(testUnit->nObjects), quint32(1));
+ const QV4::CompiledData::QmlUnit *qmlUnit = testUnit->qmlUnit();
+
+ QCOMPARE(quint32(qmlUnit->nObjects), quint32(1));
- const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(1));
QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script));
- QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1));
+ QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(0));
- QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
+ QCOMPARE(quint32(testUnit->functionTableSize), quint32(1));
- const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
- QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);
+ const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(0);
+ QCOMPARE(testUnit->stringAtInternal(bindingFunction->nameIndex), QString("expression for blah")); // check if we have the correct function
+ QVERIFY(bindingFunction->codeSize > 0);
+ QVERIFY(bindingFunction->codeOffset < testUnit->unitSize);
}
{
@@ -249,17 +317,21 @@ void tst_qmldiskcache::regenerateAfterChange()
const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
- QCOMPARE(quint32(testUnit->nObjects), quint32(1));
+ const QV4::CompiledData::QmlUnit *qmlUnit = testUnit->qmlUnit();
- const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ QCOMPARE(quint32(qmlUnit->nObjects), quint32(1));
+
+ 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(), double(42));
+ QCOMPARE(obj->bindingTable()->valueAsNumber(reinterpret_cast<const QV4::Value *>(testUnit->constants())), double(42));
- QCOMPARE(quint32(testUnit->functionTableSize), quint32(2));
+ QCOMPARE(quint32(testUnit->functionTableSize), quint32(1));
- const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1);
- QVERIFY(bindingFunction->codeOffset > testUnit->unitSize);
+ const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(0);
+ QCOMPARE(testUnit->stringAtInternal(bindingFunction->nameIndex), QString("expression for blah")); // check if we have the correct function
+ QVERIFY(bindingFunction->codeSize > 0);
+ QVERIFY(bindingFunction->codeOffset < testUnit->unitSize);
}
}
@@ -280,22 +352,23 @@ void tst_qmldiskcache::registerImportForImplicitComponent()
const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit();
QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString));
- QCOMPARE(quint32(testUnit->nImports), quint32(2));
- QCOMPARE(testUnit->stringAt(testUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick"));
+ const QV4::CompiledData::QmlUnit *qmlUnit = testUnit->qmlUnit();
+ QCOMPARE(quint32(qmlUnit->nImports), quint32(2));
+ QCOMPARE(testUnit->stringAtInternal(qmlUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick"));
- QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
+ QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->uriIndex), QString(componentType->module()));
- QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals"));
+ QCOMPARE(testUnit->stringAtInternal(qmlUnit->importAt(1)->uriIndex), QString(componentType.module()));
+ QCOMPARE(testUnit->stringAtInternal(qmlUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals"));
- QCOMPARE(quint32(testUnit->nObjects), quint32(3));
+ QCOMPARE(quint32(qmlUnit->nObjects), quint32(3));
- const QV4::CompiledData::Object *obj = testUnit->objectAt(0);
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0);
QCOMPARE(quint32(obj->nBindings), quint32(1));
QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object));
- const QV4::CompiledData::Object *implicitComponent = testUnit->objectAt(obj->bindingTable()->value.objectIndex);
- QCOMPARE(testUnit->stringAt(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType->elementName());
+ const QV4::CompiledData::Object *implicitComponent = qmlUnit->objectAt(obj->bindingTable()->value.objectIndex);
+ QCOMPARE(testUnit->stringAtInternal(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType.elementName());
}
}
@@ -341,30 +414,6 @@ void tst_qmldiskcache::basicVersionChecks()
QVERIFY(!testCompiler.verify());
QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16));
}
-
- {
- testCompiler.clearCache();
- QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
-
- testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
- header->architectureIndex = 0;
- });
-
- QVERIFY(!testCompiler.verify());
- QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi()));
- }
-
- {
- testCompiler.clearCache();
- QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
-
- testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) {
- header->codeGeneratorIndex = 0;
- });
-
- QVERIFY(!testCompiler.verify());
- QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName));
- }
}
class TypeVersion1 : public QObject
@@ -468,6 +517,10 @@ void tst_qmldiskcache::recompileAfterDirectoryChange()
testCompiler.clearCache();
QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString));
QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString));
+ const QV4::CompiledData::Unit *unit = testCompiler.mapUnit();
+ QVERIFY(unit->sourceFileIndex != 0);
+ const QString expectedPath = QUrl::fromLocalFile(testCompiler.testFilePath).toString();
+ QCOMPARE(unit->stringAtInternal(unit->sourceFileIndex), expectedPath);
testCompiler.closeMapping();
}
@@ -520,7 +573,7 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
- QFile cacheFile(testFilePath + "c");
+ QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
@@ -535,7 +588,7 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 100);
- QFile cacheFile(selectedTestFilePath + "c");
+ QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(selectedTestFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
}
@@ -585,14 +638,8 @@ void tst_qmldiskcache::localAliases()
void tst_qmldiskcache::cacheResources()
{
- const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
- QVERIFY(QDir::root().mkpath(cacheDirectory));
-
- const QString qmlCacheDirectory = cacheDirectory + QLatin1String("/qmlcache/");
- QVERIFY(QDir(qmlCacheDirectory).removeRecursively());
- QVERIFY(QDir::root().mkpath(qmlCacheDirectory));
- QVERIFY(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot).isEmpty());
-
+ const QSet<QString> existingFiles =
+ m_qmlCacheDirectory.entryList(QDir::Files | QDir::NoDotAndDotDot).toSet();
QQmlEngine engine;
@@ -603,13 +650,14 @@ void tst_qmldiskcache::cacheResources()
QCOMPARE(obj->property("value").toInt(), 20);
}
- const QStringList entries = QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files);
+ const QSet<QString> entries =
+ m_qmlCacheDirectory.entryList(QDir::NoDotAndDotDot | QDir::Files).toSet().subtract(existingFiles);
QCOMPARE(entries.count(), 1);
QDateTime cacheFileTimeStamp;
{
- QFile cacheFile(qmlCacheDirectory + QLatin1Char('/') + entries.constFirst());
+ QFile cacheFile(m_qmlCacheDirectory.absoluteFilePath(*entries.cbegin()));
QVERIFY2(cacheFile.open(QIODevice::ReadOnly), qPrintable(cacheFile.errorString()));
QV4::CompiledData::Unit unit;
QVERIFY(cacheFile.read(reinterpret_cast<char *>(&unit), sizeof(unit)) == sizeof(unit));
@@ -632,10 +680,12 @@ void tst_qmldiskcache::cacheResources()
}
{
- const QStringList entries = QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files);
+ const QSet<QString> entries =
+ m_qmlCacheDirectory.entryList(QDir::NoDotAndDotDot | QDir::Files).toSet().subtract(existingFiles);
QCOMPARE(entries.count(), 1);
- QCOMPARE(QFileInfo(qmlCacheDirectory + QLatin1Char('/') + entries.constFirst()).lastModified().toMSecsSinceEpoch(), cacheFileTimeStamp.toMSecsSinceEpoch());
+ QCOMPARE(QFileInfo(m_qmlCacheDirectory.absoluteFilePath(*entries.cbegin())).lastModified().toMSecsSinceEpoch(),
+ cacheFileTimeStamp.toMSecsSinceEpoch());
}
}
@@ -688,7 +738,7 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes()
QVERIFY2(firstDependentTypeClassName.contains("QMLTYPE"), firstDependentTypeClassName.constData());
QVERIFY2(secondDependentTypeClassName.contains("QMLTYPE"), secondDependentTypeClassName.constData());
- const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -766,7 +816,7 @@ void tst_qmldiskcache::singletonDependency()
QCOMPARE(obj->property("value").toInt(), 42);
}
- const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -790,6 +840,107 @@ void tst_qmldiskcache::singletonDependency()
}
}
+void tst_qmldiskcache::cppRegisteredSingletonDependency()
+{
+ qmlClearTypeRegistrations();
+ QScopedPointer<QQmlEngine> engine(new QQmlEngine);
+
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }");
+
+ qmlRegisterSingletonType(QUrl::fromLocalFile(tempDir.path() + QLatin1String("/MySingleton.qml")), "CppRegisteredSingletonDependency", 1, 0, "Singly");
+
+ const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport CppRegisteredSingletonDependency 1.0\nQtObject {\n"
+ " function getValue() { return Singly.value; }\n"
+ "}");
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 42);
+ }
+
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+
+ engine.reset(new QQmlEngine);
+ waitForFileSystem();
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }");
+ waitForFileSystem();
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ {
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+ QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString()));
+ }
+
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 100);
+ }
+}
+
+void tst_qmldiskcache::cacheModuleScripts()
+{
+ const QSet<QString> existingFiles =
+ m_qmlCacheDirectory.entryList(QDir::Files | QDir::NoDotAndDotDot).toSet();
+
+ QQmlEngine engine;
+
+ {
+ CleanlyLoadingComponent component(&engine, QUrl("qrc:/importmodule.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("ok").toBool());
+
+ auto componentPrivate = QQmlComponentPrivate::get(&component);
+ QVERIFY(componentPrivate);
+ auto compilationUnit = componentPrivate->compilationUnit->dependentScripts.first()->compilationUnit();
+ QVERIFY(compilationUnit);
+ auto unitData = compilationUnit->unitData();
+ QVERIFY(unitData);
+ QVERIFY(unitData->flags & QV4::CompiledData::Unit::StaticData);
+ QVERIFY(unitData->flags & QV4::CompiledData::Unit::IsESModule);
+ QVERIFY(!compilationUnit->backingFile.isNull());
+ }
+
+ const QSet<QString> entries =
+ m_qmlCacheDirectory.entryList(QStringList("*.mjsc")).toSet().subtract(existingFiles);
+
+ QCOMPARE(entries.count(), 1);
+
+ QDateTime cacheFileTimeStamp;
+
+ {
+ QFile cacheFile(m_qmlCacheDirectory.absoluteFilePath(*entries.cbegin()));
+ QVERIFY2(cacheFile.open(QIODevice::ReadOnly), qPrintable(cacheFile.errorString()));
+ QV4::CompiledData::Unit unit;
+ QVERIFY(cacheFile.read(reinterpret_cast<char *>(&unit), sizeof(unit)) == sizeof(unit));
+
+ QVERIFY(unit.flags & QV4::CompiledData::Unit::IsESModule);
+ }
+}
+
QTEST_MAIN(tst_qmldiskcache)
#include "tst_qmldiskcache.moc"
diff --git a/tests/auto/qml/qmlmin/qmlmin.pro b/tests/auto/qml/qmlmin/qmlmin.pro
index 6af6653270..93e5caabcf 100644
--- a/tests/auto/qml/qmlmin/qmlmin.pro
+++ b/tests/auto/qml/qmlmin/qmlmin.pro
@@ -6,5 +6,7 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qmlmin.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\"
-
-cross_compile: DEFINES += QTEST_CROSS_COMPILED
+# Boot2qt is cross compiled but it has sources available
+!boot2qt {
+ cross_compile: DEFINES += QTEST_CROSS_COMPILED
+}
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
index 171c2bda8a..c393149f59 100644
--- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -98,6 +98,8 @@ void tst_qmlmin::initTestCase()
invalidFiles << "tests/auto/qml/qqmllanguage/data/insertedSemicolon.1.qml";
invalidFiles << "tests/auto/qml/qqmllanguage/data/nonexistantProperty.5.qml";
invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidRoot.1.qml";
+ invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml";
+ invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml";
invalidFiles << "tests/auto/qml/qquickfolderlistmodel/data/dummy.qml";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/qtbug_22843.js";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js";
@@ -123,6 +125,9 @@ void tst_qmlmin::initTestCase()
invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.6.qml";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.1.qml";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.2.qml";
+ invalidFiles << "tests/auto/qml/parserstress/tests/ecma_3/FunExpr/fe-001.js";
+ invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js";
+ invalidFiles << "tests/auto/qml/debugger/qqmlpreview/data/broken.qml";
}
QStringList tst_qmlmin::findFiles(const QDir &d)
diff --git a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/Singleton.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/Singleton.qml
index b47d2e98f4..b47d2e98f4 100644
--- a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/Singleton.qml
+++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/Singleton.qml
diff --git a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/qmldir
index 8df57f6d47..c08e74db2e 100644
--- a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/qmldir
+++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/qmldir
@@ -1,3 +1,3 @@
-module tests.dumper.CompositeSingleton
+module dumper.CompositeSingleton
singleton Singleton 1.0 Singleton.qml
depends QtQuick 2.0
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml
new file mode 100644
index 0000000000..b1055b6992
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Composite.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property int test: 0
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml
new file mode 100644
index 0000000000..e81b2b6cb5
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/Singleton.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQuick 2.0
+
+QtObject {
+ property Composite test: Composite {}
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir
new file mode 100644
index 0000000000..5a9cb1bd96
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeWithinSingleton/qmldir
@@ -0,0 +1,4 @@
+module dumper.CompositeWithinSingleton
+singleton Singleton 1.0 Singleton.qml
+Composite 1.0 Composite.qml
+depends QtQuick 2.0
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.cpp
new file mode 100644
index 0000000000..689ea4aa53
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** 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 "dummy.h"
+
+Dummy::Dummy(QObject *parent):
+ QObject(parent)
+{
+}
+
+Dummy::~Dummy()
+{
+}
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.h b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.h
new file mode 100644
index 0000000000..7011f72523
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef DUMMY_H
+#define DUMMY_H
+
+#include <QObject>
+
+class Dummy : public QObject
+{
+ Q_OBJECT
+
+public:
+ Dummy(QObject *parent = nullptr);
+ ~Dummy();
+};
+
+#endif // DUMMY_H
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.pro b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.pro
new file mode 100644
index 0000000000..9f5bc927b4
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy.pro
@@ -0,0 +1,23 @@
+TEMPLATE = lib
+TARGET = Dummy
+QT += qml
+CONFIG += qt plugin
+
+CONFIG -= debug_and_release_target
+!build_pass:qtConfig(debug_and_release): CONFIG += release
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+SOURCES += \
+ dummy_plugin.cpp \
+ dummy.cpp
+
+HEADERS += \
+ dummy_plugin.h \
+ dummy.h
+
+!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
+ cp.files = qmldir plugins.qmltypes
+ cp.path = $$OUT_PWD
+ COPIES += cp
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.cpp
new file mode 100644
index 0000000000..763604daf0
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.cpp
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** 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 "dummy_plugin.h"
+#include "dummy.h"
+
+#include <qqml.h>
+
+void DummyPlugin::registerTypes(const char *uri)
+{
+ // @uri dumper.dummy
+ qmlRegisterType<Dummy>(uri, 1, 0, "Dummy");
+}
+
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.h b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.h
new file mode 100644
index 0000000000..86e80e6a08
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/dummy_plugin.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef DUMMY_PLUGIN_H
+#define DUMMY_PLUGIN_H
+
+#include <QQmlExtensionPlugin>
+
+class DummyPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif // DUMMY_PLUGIN_H
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/plugins.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/plugins.qmltypes
new file mode 100644
index 0000000000..da0f2f24e4
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/plugins.qmltypes
@@ -0,0 +1,17 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick dumper.Dummy 1.0 .'
+
+Module {
+ dependencies: []
+ Component {
+ name: "Dummy"
+ prototype: "QObject"
+ exports: ["dumper.Dummy/Dummy 1.0"]
+ exportMetaObjectRevisions: [0]
+ }
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Dummy/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/qmldir
new file mode 100644
index 0000000000..7d4107c040
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Dummy/qmldir
@@ -0,0 +1,3 @@
+module dumper.Dummy
+plugin Dummy
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/extendedtype.pro b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/extendedtype.pro
new file mode 100644
index 0000000000..24243aa622
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/extendedtype.pro
@@ -0,0 +1,22 @@
+TEMPLATE = lib
+TARGET = ExtendedType
+QT += qml
+CONFIG += qt plugin
+
+CONFIG -= debug_and_release_target
+!build_pass:qtConfig(debug_and_release): CONFIG += release
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+SOURCES += \
+ plugin.cpp
+
+HEADERS += \
+ plugin.h \
+ types.h
+
+!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
+ cp.files = qmldir plugins.qmltypes
+ cp.path = $$OUT_PWD
+ COPIES += cp
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.cpp b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.cpp
new file mode 100644
index 0000000000..423fbc1f4c
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.cpp
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 "plugin.h"
+#include "types.h"
+
+#include <qqml.h>
+
+void Plugin::registerTypes(const char *uri)
+{
+ // @uri dumper.ExtendedType
+ qmlRegisterType<Type>(uri, 1, 0, "Type");
+ qmlRegisterExtendedType<Type, ExtendedType>(uri, 1, 1, "Type");
+ qmlRegisterType<DerivedType2>(uri, 1, 1, "DerivedType");
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.h b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.h
new file mode 100644
index 0000000000..b677fe2940
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugin.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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$
+**
+****************************************************************************/
+
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include <QQmlExtensionPlugin>
+
+class Plugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif // PLUGIN_H
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugins.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugins.qmltypes
new file mode 100644
index 0000000000..d84eb0011a
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/plugins.qmltypes
@@ -0,0 +1,35 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick dumper.ExtendedType 1.1 .'
+
+Module {
+ dependencies: []
+ Component {
+ name: "DerivedType1"
+ prototype: "Type"
+ Property { name: "m_exendedProperty2"; type: "int" }
+ }
+ Component {
+ name: "DerivedType2"
+ prototype: "DerivedType1"
+ exports: ["dumper.ExtendedType/DerivedType 1.1"]
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "Type"
+ defaultProperty: "data"
+ prototype: "QObject"
+ exports: [
+ "dumper.ExtendedType/Type 1.0",
+ "dumper.ExtendedType/Type 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 101]
+ Property { name: "baseProperty"; type: "int" }
+ Property { name: "extendedProperty"; revision: 101; type: "int" }
+ Property { name: "data"; revision: 101; type: "QObject"; isList: true; isReadonly: true }
+ }
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/qmldir
new file mode 100644
index 0000000000..6693f403d9
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/qmldir
@@ -0,0 +1,3 @@
+module dumper.ExtendedType
+plugin ExtendedType
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/types.h b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/types.h
new file mode 100644
index 0000000000..dfba55a094
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/ExtendedType/types.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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$
+**
+****************************************************************************/
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <QObject>
+#include <QQmlListProperty>
+
+class Type : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int baseProperty MEMBER m_baseProperty)
+
+public:
+ Type(QObject *parent = nullptr)
+ : QObject(parent) {}
+
+private:
+ int m_baseProperty;
+};
+
+class ExtendedType : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int extendedProperty MEMBER m_extendedProperty)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ ExtendedType(QObject *parent = nullptr)
+ : QObject(parent) {}
+ QQmlListProperty<QObject> data() { return QQmlListProperty<QObject>(this, m_data); }
+
+private:
+ QList<QObject *> m_data;
+ int m_extendedProperty;
+};
+
+class DerivedType1 : public Type
+{
+ Q_OBJECT
+ Q_PROPERTY(int m_exendedProperty2 MEMBER m_extendedProperty2)
+
+public:
+ DerivedType1(QObject *parent = nullptr)
+ : Type(parent) {}
+
+private:
+ int m_extendedProperty2;
+};
+
+class DerivedType2 : public DerivedType1
+{
+ Q_OBJECT
+public:
+ DerivedType2(QObject *parent = nullptr)
+ : DerivedType1(parent) {}
+};
+
+#endif // TYPES_H
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/CompositeImports.qml b/tests/auto/qml/qmlplugindump/data/dumper/Imports/CompositeImports.qml
new file mode 100644
index 0000000000..b1055b6992
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/CompositeImports.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property int test: 0
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.cpp
new file mode 100644
index 0000000000..a923fade2a
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** 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 "imports.h"
+
+Imports::Imports(QObject *parent):
+ QObject(parent)
+{
+}
+
+Imports::~Imports()
+{
+}
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.h b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.h
new file mode 100644
index 0000000000..d2b9036e4d
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef IMPORTS_H
+#define IMPORTS_H
+
+#include <QObject>
+
+class Imports : public QObject
+{
+ Q_OBJECT
+
+public:
+ Imports(QObject *parent = nullptr);
+ ~Imports();
+};
+
+#endif // IMPORTS_H
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro
new file mode 100644
index 0000000000..d20ea967ea
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports.pro
@@ -0,0 +1,24 @@
+TEMPLATE = lib
+TARGET = Imports
+QT += qml
+CONFIG += qt plugin
+
+CONFIG -= debug_and_release_target
+!build_pass:qtConfig(debug_and_release): CONFIG += release
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+SOURCES += \
+ imports_plugin.cpp \
+ imports.cpp
+
+HEADERS += \
+ imports_plugin.h \
+ imports.h
+
+!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
+ cp.files = qmldir plugins.qmltypes CompositeImports.qml
+ cp.path = $$OUT_PWD
+ COPIES += cp
+}
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.cpp
new file mode 100644
index 0000000000..183ba56ac1
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.cpp
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** 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 "imports_plugin.h"
+#include "imports.h"
+
+#include <qqml.h>
+
+void ImportsPlugin::registerTypes(const char *uri)
+{
+ // @uri dumper.imports
+ qmlRegisterType<Imports>(uri, 1, 0, "Imports");
+}
+
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.h b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.h
new file mode 100644
index 0000000000..fd09584d47
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/imports_plugin.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef IMPORTS_PLUGIN_H
+#define IMPORTS_PLUGIN_H
+
+#include <QQmlExtensionPlugin>
+
+class ImportsPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif // IMPORTS_PLUGIN_H
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes
new file mode 100644
index 0000000000..937dd60a9e
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/plugins.qmltypes
@@ -0,0 +1,17 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick dumper.Imports 1.0 .'
+
+Module {
+ dependencies: ["QtQuick 2.0"]
+ Component {
+ name: "Imports"
+ prototype: "QObject"
+ exports: ["dumper.Imports/Imports 1.0"]
+ exportMetaObjectRevisions: [0]
+ }
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir
new file mode 100644
index 0000000000..c9058a7f95
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Imports/qmldir
@@ -0,0 +1,3 @@
+module dumper.Imports
+plugin Imports
+CompositeImports 1.0 CompositeImports.qml
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Singleton/CompositeSingleton.qml b/tests/auto/qml/qmlplugindump/data/dumper/Singleton/CompositeSingleton.qml
new file mode 100644
index 0000000000..b47d2e98f4
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Singleton/CompositeSingleton.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQuick 2.0
+
+QtObject {
+ property int test: 0
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Singleton/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/Singleton/qmldir
new file mode 100644
index 0000000000..6ed6d6f1d4
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Singleton/qmldir
@@ -0,0 +1,2 @@
+module dumper.Singleton
+singleton CompositeSingleton 1.0 CompositeSingleton.qml
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugin.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugin.qmltypes
new file mode 100644
index 0000000000..3a33590139
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugin.qmltypes
@@ -0,0 +1,23 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick dumper.Versions 1.1 .'
+
+Module {
+ dependencies: []
+ Component {
+ name: "Versions"
+ prototype: "QObject"
+ exports: [
+ "dumper.Versions/Versions 1.0",
+ "dumper.Versions/Versions 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
+ Property { name: "foo"; type: "int" }
+ Property { name: "bar"; revision: 1; type: "int" }
+ Property { name: "baz"; revision: 2; type: "int" }
+ }
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugins.qmltypes b/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugins.qmltypes
new file mode 100644
index 0000000000..3a33590139
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/plugins.qmltypes
@@ -0,0 +1,23 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick dumper.Versions 1.1 .'
+
+Module {
+ dependencies: []
+ Component {
+ name: "Versions"
+ prototype: "QObject"
+ exports: [
+ "dumper.Versions/Versions 1.0",
+ "dumper.Versions/Versions 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
+ Property { name: "foo"; type: "int" }
+ Property { name: "bar"; revision: 1; type: "int" }
+ Property { name: "baz"; revision: 2; type: "int" }
+ }
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/Versions/qmldir
new file mode 100644
index 0000000000..a47a2a4573
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/qmldir
@@ -0,0 +1,3 @@
+module dumper.Versions
+plugin Versions
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.cpp
new file mode 100644
index 0000000000..3422275d78
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** 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 "versions.h"
+
+Versions::Versions(QObject *parent):
+ QObject(parent)
+{
+}
+
+Versions::~Versions()
+{
+}
+
diff --git a/tests/auto/qml/debugger/shared/qqmlinspectorclient.h b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.h
index bfb489c8f7..ba88f478ca 100644
--- a/tests/auto/qml/debugger/shared/qqmlinspectorclient.h
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.h
@@ -25,35 +25,37 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QQMLINSPECTORCLIENT_H
-#define QQMLINSPECTORCLIENT_H
-#include <private/qqmldebugclient_p.h>
+#ifndef VERSIONS_H
+#define VERSIONS_H
-class QQmlInspectorClient : public QQmlDebugClient
+#include <QObject>
+
+class Versions : public QObject
{
Q_OBJECT
+ Q_PROPERTY(int foo READ foo WRITE setFoo NOTIFY fooChanged)
+ Q_PROPERTY(int bar READ bar WRITE setBar NOTIFY barChanged REVISION 1)
+ Q_PROPERTY(int baz READ baz WRITE setBaz NOTIFY bazChanged REVISION 2)
public:
- QQmlInspectorClient(QQmlDebugConnection *connection);
-
- int setInspectToolEnabled(bool enabled);
- int setShowAppOnTop(bool showOnTop);
- int setAnimationSpeed(qreal speed);
- int select(const QList<int> &objectIds);
- int createObject(const QString &qml, int parentId, const QStringList &imports,
- const QString &filename);
- int moveObject(int childId, int newParentId);
- int destroyObject(int objectId);
-
+ Versions(QObject *parent = nullptr);
+ ~Versions();
+ int foo() const { return m_foo; }
+ void setFoo(int value) { m_foo = value; }
+ int bar() const { return m_bar; }
+ void setBar(int value) { m_bar = value; }
+ int baz() const { return m_baz; }
+ void setBaz(int value) { m_baz = value; }
signals:
- void responseReceived(int requestId, bool result);
-
-protected:
- void messageReceived(const QByteArray &message);
-
+ void fooChanged();
+ void barChanged();
+ void bazChanged();
private:
- int m_lastRequestId;
+ int m_foo;
+ int m_bar;
+ int m_baz;
};
-#endif // QQMLINSPECTORCLIENT_H
+#endif // VERSIONS_H
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.pro b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.pro
new file mode 100644
index 0000000000..6bbb9e556b
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions.pro
@@ -0,0 +1,23 @@
+TEMPLATE = lib
+TARGET = Versions
+QT += qml
+CONFIG += qt plugin
+
+CONFIG -= debug_and_release_target
+!build_pass:qtConfig(debug_and_release): CONFIG += release
+
+TARGET = $$qtLibraryTarget($$TARGET)
+
+SOURCES += \
+ versions_plugin.cpp \
+ versions.cpp
+
+HEADERS += \
+ versions_plugin.h \
+ versions.h
+
+!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
+ cpqmldir.files = qmldir plugins.qmltypes
+ cpqmldir.path = $$OUT_PWD
+ COPIES += cpqmldir
+}
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.cpp b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.cpp
new file mode 100644
index 0000000000..4bd290aff1
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "versions_plugin.h"
+#include "versions.h"
+
+#include <qqml.h>
+
+void VersionsPlugin::registerTypes(const char *uri)
+{
+ // @uri dumper.versions
+ qmlRegisterType<Versions>(uri, 1, 0, "Versions");
+ qmlRegisterType<Versions, 1>(uri, 1, 1, "Versions");
+}
+
+
diff --git a/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.h b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.h
new file mode 100644
index 0000000000..4ba68a8125
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/data/dumper/Versions/versions_plugin.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef VERSIONS_PLUGIN_H
+#define VERSIONS_PLUGIN_H
+
+#include <QQmlExtensionPlugin>
+
+class VersionsPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif // VERSIONS_PLUGIN_H
+
diff --git a/tests/auto/qml/qmlplugindump/qmlplugindump.pro b/tests/auto/qml/qmlplugindump/qmlplugindump.pro
index c713edc541..34eb58c981 100644
--- a/tests/auto/qml/qmlplugindump/qmlplugindump.pro
+++ b/tests/auto/qml/qmlplugindump/qmlplugindump.pro
@@ -1,6 +1,8 @@
-CONFIG += testcase
-TARGET = tst_qmlplugindump
-QT += testlib gui-private
-macx:CONFIG -= app_bundle
+TEMPLATE = subdirs
-SOURCES += tst_qmlplugindump.cpp
+SUBDIRS += \
+ tst_qmlplugindump.pro \
+ data/dumper/Dummy/dummy.pro \
+ data/dumper/Imports/imports.pro \
+ data/dumper/Versions/versions.pro \
+ data/dumper/ExtendedType/extendedtype.pro
diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
index 68e11e3551..17766a89b5 100644
--- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
+++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
@@ -26,6 +26,8 @@
**
****************************************************************************/
+#include "util.h"
+
#include <qtest.h>
#include <QLibraryInfo>
#include <QDir>
@@ -33,7 +35,7 @@
#include <QDebug>
#include <cstdlib>
-class tst_qmlplugindump : public QObject
+class tst_qmlplugindump : public QQmlDataTest
{
Q_OBJECT
public:
@@ -43,6 +45,10 @@ private slots:
void initTestCase();
void builtins();
void singleton();
+ void compositeWithinSingleton();
+
+ void plugin_data();
+ void plugin();
private:
QString qmlplugindumpPath;
@@ -54,6 +60,7 @@ tst_qmlplugindump::tst_qmlplugindump()
void tst_qmlplugindump::initTestCase()
{
+ QQmlDataTest::initTestCase();
qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
#if defined(Q_OS_WIN)
@@ -102,8 +109,8 @@ void tst_qmlplugindump::singleton()
{
QProcess dumper;
QStringList args;
- args << QLatin1String("tests.dumper.CompositeSingleton") << QLatin1String("1.0")
- << QLatin1String(".");
+ args << QLatin1String("dumper.CompositeSingleton") << QLatin1String("1.0")
+ << QLatin1String(QT_QMLTEST_DIR "/data");
dumper.start(qmlplugindumpPath, args);
QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
@@ -113,6 +120,54 @@ void tst_qmlplugindump::singleton()
QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result));
}
+void tst_qmlplugindump::compositeWithinSingleton()
+{
+ QProcess dumper;
+ QStringList args;
+ args << QLatin1String("dumper.CompositeWithinSingleton") << QLatin1String("1.0")
+ << QLatin1String(QT_QMLTEST_DIR "/data");
+ dumper.start(qmlplugindumpPath, args);
+ QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
+ QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
+
+ const QString &result = dumper.readAllStandardOutput();
+ QVERIFY2(result.contains(QLatin1String("exports: [\"Composite 1.0\"]")), qPrintable(result));
+ QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result));
+}
+
+void tst_qmlplugindump::plugin_data()
+{
+ QTest::addColumn<QString>("import");
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<QString>("expectedPath");
+
+ QTest::newRow("dumper.Dummy") << "dumper.Dummy" << "1.0" << testFile("dumper/Dummy/plugins.qmltypes");
+ QTest::newRow("dumper.Imports") << "dumper.Imports" << "1.0" << testFile("dumper/Imports/plugins.qmltypes");
+ QTest::newRow("dumper.Versions") << "dumper.Versions" << "1.1" << testFile("dumper/Versions/plugins.qmltypes");
+ QTest::newRow("dumper.ExtendedType") << "dumper.ExtendedType"
+ << "1.1" << testFile("dumper/ExtendedType/plugins.qmltypes");
+}
+
+void tst_qmlplugindump::plugin()
+{
+ QFETCH(QString, import);
+ QFETCH(QString, version);
+ QFETCH(QString, expectedPath);
+
+ QProcess dumper;
+ dumper.setWorkingDirectory(dataDirectory());
+ QStringList args = { QLatin1String("-nonrelocatable"), QLatin1String("-noforceqtquick"), import, version, QLatin1String(".") };
+ dumper.start(qmlplugindumpPath, args);
+ QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
+ QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
+
+ const QString &result = dumper.readAllStandardOutput();
+ QFile expectedFile(expectedPath);
+ QVERIFY2(expectedFile.open(QIODevice::ReadOnly), qPrintable(expectedFile.errorString()));
+ const QString expected = expectedFile.readAll();
+ QCOMPARE(result, expected);
+}
+
QTEST_MAIN(tst_qmlplugindump)
#include "tst_qmlplugindump.moc"
diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.pro b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.pro
new file mode 100644
index 0000000000..be0a0a49b6
--- /dev/null
+++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.pro
@@ -0,0 +1,9 @@
+QT += testlib gui-private qml
+macx:CONFIG -= app_bundle
+
+CONFIG += testcase
+
+include(../../shared/util.pri)
+
+DEFINES += QT_QMLTEST_DIR=\\\"$${_PRO_FILE_PWD_}\\\"
+SOURCES += tst_qmlplugindump.cpp
diff --git a/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro b/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro
index 4a2dde7c47..3adad3759b 100644
--- a/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro
+++ b/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro
@@ -1,3 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS = tst_qqmlapplicationengine.pro \
- testapp
+SUBDIRS = testapp \
+ tst_qqmlapplicationengine.pro
+
+CONFIG += ordered
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/delayedExit.qml b/tests/auto/qml/qqmlapplicationengine/testapp/delayedExit.qml
new file mode 100644
index 0000000000..3d67c958bb
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/delayedExit.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property Timer t: Timer { interval: 1; running: true; onTriggered: Qt.exit(0); }
+ property Connections c: Connections {
+ target: Qt.application
+ onAboutToQuit: console.log("End");
+ }
+ Component.onCompleted: console.log("Start: " + Qt.application.arguments[1]);
+}
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/main.qml b/tests/auto/qml/qqmlapplicationengine/testapp/delayedQuit.qml
index c75485a7f7..c75485a7f7 100644
--- a/tests/auto/qml/qqmlapplicationengine/testapp/main.qml
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/delayedQuit.qml
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/immediateExit.qml b/tests/auto/qml/qqmlapplicationengine/testapp/immediateExit.qml
new file mode 100644
index 0000000000..46634f3f51
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/immediateExit.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ Component.onCompleted: {
+ console.log("End: " + Qt.application.arguments[1]);
+ Qt.exit(0)
+ }
+}
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/immediateQuit.qml b/tests/auto/qml/qqmlapplicationengine/testapp/immediateQuit.qml
new file mode 100644
index 0000000000..1da9d1201a
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/immediateQuit.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ Component.onCompleted: {
+ console.log("End: " + Qt.application.arguments[1]);
+ Qt.quit()
+ }
+}
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/main.cpp b/tests/auto/qml/qqmlapplicationengine/testapp/main.cpp
index a57889fe86..be0d98a2df 100644
--- a/tests/auto/qml/qqmlapplicationengine/testapp/main.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/main.cpp
@@ -32,6 +32,6 @@
int main (int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- QQmlApplicationEngine e(QUrl("qrc:///main.qml"));
+ QQmlApplicationEngine e(QUrl(QString("qrc:///") + argv[1]));
return app.exec();
}
diff --git a/tests/auto/qml/qqmlapplicationengine/testapp/main.qrc b/tests/auto/qml/qqmlapplicationengine/testapp/main.qrc
index 5f6483ac33..82b695bbd8 100644
--- a/tests/auto/qml/qqmlapplicationengine/testapp/main.qrc
+++ b/tests/auto/qml/qqmlapplicationengine/testapp/main.qrc
@@ -1,5 +1,8 @@
<RCC>
<qresource prefix="/">
- <file>main.qml</file>
+ <file>immediateQuit.qml</file>
+ <file>immediateExit.qml</file>
+ <file>delayedQuit.qml</file>
+ <file>delayedExit.qml</file>
</qresource>
</RCC>
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index daeb9b5455..ce654dc45e 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -46,6 +46,7 @@ private slots:
void initTestCase();
void basicLoading();
void testNonResolvedPath();
+ void application_data();
void application();
void applicationProperties();
void removeObjectsWhenDestroyed();
@@ -111,35 +112,56 @@ void tst_qqmlapplicationengine::testNonResolvedPath()
}
}
+void tst_qqmlapplicationengine::application_data()
+{
+ QTest::addColumn<QByteArray>("qmlFile");
+ QTest::addColumn<QByteArray>("expectedStdErr");
+
+ QTest::newRow("delayed quit") << QByteArray("delayedQuit.qml")
+ << QByteArray("qml: Start: delayedQuit.qml\nqml: End\n");
+ QTest::newRow("delayed exit") << QByteArray("delayedExit.qml")
+ << QByteArray("qml: Start: delayedExit.qml\nqml: End\n");
+ QTest::newRow("immediate quit") << QByteArray("immediateQuit.qml")
+ << QByteArray("qml: End: immediateQuit.qml\n");
+ QTest::newRow("immediate exit") << QByteArray("immediateExit.qml")
+ << QByteArray("qml: End: immediateExit.qml\n");
+}
+
void tst_qqmlapplicationengine::application()
{
/* This test batches together some tests about running an external application
written with QQmlApplicationEngine. The application tests the following functionality
which is easier to do by watching a separate process:
- -Loads relative paths from the working directory
- -quits when quit is called
- -emits aboutToQuit after quit is called
- -has access to application command line arguments
+ - Loads relative paths from the working directory
+ - Quits when quit is called
+ - Exits when exit is called
+ - Emits aboutToQuit after quit is called
+ - Has access to application command line arguments
Note that checking the output means that on builds with extra debugging, this might fail with a false positive.
Also the testapp is automatically built and installed in shadow builds, so it does NOT use testData
*/
+
+ QFETCH(QByteArray, qmlFile);
+ QFETCH(QByteArray, expectedStdErr);
+
#if QT_CONFIG(process)
QDir::setCurrent(buildDir);
QProcess *testProcess = new QProcess(this);
QStringList args;
- args << QLatin1String("testData");
+ args << qmlFile; // QML file passed as an argument is going to be run by testapp.
testProcess->start(QLatin1String("testapp/testapp"), args);
QVERIFY(testProcess->waitForFinished(5000));
QCOMPARE(testProcess->exitCode(), 0);
- QByteArray test_stdout = testProcess->readAllStandardOutput();
- QByteArray test_stderr = testProcess->readAllStandardError();
- QByteArray test_stderr_target("qml: Start: testData\nqml: End\n");
+ QByteArray testStdOut = testProcess->readAllStandardOutput();
+ QByteArray testStdErr = testProcess->readAllStandardError();
#ifdef Q_OS_WIN
- test_stderr_target.replace('\n', QByteArray("\r\n"));
+ expectedStdErr.replace('\n', QByteArray("\r\n"));
#endif
- QCOMPARE(test_stdout, QByteArray(""));
- QVERIFY(QString(test_stderr).endsWith(QString(test_stderr_target)));
+ QCOMPARE(testStdOut, QByteArray(""));
+ QVERIFY2(QString(testStdErr).endsWith(QString(expectedStdErr)),
+ QByteArray("\nExpected ending:\n") + expectedStdErr
+ + QByteArray("\nActual output:\n") + testStdErr);
delete testProcess;
QDir::setCurrent(srcDir);
#else // process
diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
index 4b485d2ce8..34cf21024d 100644
--- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
+++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
@@ -65,10 +65,10 @@ void tst_qqmlbinding::binding()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("test-binding.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
QQmlBind *binding3 = qobject_cast<QQmlBind*>(rect->findChild<QQmlBind*>("binding3"));
- QVERIFY(binding3 != 0);
+ QVERIFY(binding3 != nullptr);
QCOMPARE(rect->color(), QColor("yellow"));
QCOMPARE(rect->property("text").toString(), QString("Hello"));
@@ -80,7 +80,7 @@ void tst_qqmlbinding::binding()
QCOMPARE(binding3->when(), true);
QQmlBind *binding = qobject_cast<QQmlBind*>(rect->findChild<QQmlBind*>("binding1"));
- QVERIFY(binding != 0);
+ QVERIFY(binding != nullptr);
QCOMPARE(binding->object(), qobject_cast<QObject*>(rect));
QCOMPARE(binding->property(), QLatin1String("text"));
QCOMPARE(binding->value().toString(), QLatin1String("Hello"));
@@ -94,7 +94,7 @@ void tst_qqmlbinding::whenAfterValue()
QQmlComponent c(&engine, testFileUrl("test-binding2.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
QCOMPARE(rect->color(), QColor("yellow"));
QCOMPARE(rect->property("text").toString(), QString("Hello"));
@@ -109,10 +109,10 @@ void tst_qqmlbinding::restoreBinding()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBinding.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
- QVERIFY(myItem != 0);
+ QVERIFY(myItem != nullptr);
myItem->setY(25);
QCOMPARE(myItem->x(), qreal(100-25));
@@ -139,10 +139,10 @@ void tst_qqmlbinding::restoreBindingWithLoop()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBindingWithLoop.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
- QVERIFY(myItem != 0);
+ QVERIFY(myItem != nullptr);
myItem->setY(25);
QCOMPARE(myItem->x(), qreal(25 + 100));
@@ -175,10 +175,10 @@ void tst_qqmlbinding::restoreBindingWithoutCrash()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("restoreBindingWithoutCrash.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
QQuickRectangle *myItem = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("myItem"));
- QVERIFY(myItem != 0);
+ QVERIFY(myItem != nullptr);
myItem->setY(25);
QCOMPARE(myItem->x(), qreal(100-25));
@@ -215,9 +215,9 @@ void tst_qqmlbinding::deletedObject()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("deletedObject.qml"));
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
- QVERIFY(rect != 0);
+ QVERIFY(rect != nullptr);
- QGuiApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QGuiApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
//don't crash
rect->setProperty("activateBinding", true);
@@ -289,7 +289,7 @@ void tst_qqmlbinding::delayed()
QQmlComponent c(&engine, testFileUrl("delayed.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
// update on creation
QCOMPARE(item->property("changeCount").toInt(), 1);
diff --git a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
index da7956a5fb..f12c3432c2 100644
--- a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
+++ b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp
@@ -26,6 +26,7 @@
**
****************************************************************************/
#include <qtest.h>
+#include <qrandom.h>
#include <private/qqmlchangeset_p.h>
class tst_qqmlchangeset : public QObject
@@ -1462,23 +1463,19 @@ void tst_qqmlchangeset::debug()
void tst_qqmlchangeset::random_data()
{
- QTest::addColumn<int>("seed");
QTest::addColumn<int>("combinations");
QTest::addColumn<int>("depth");
- QTest::newRow("1*5") << 32 << 1 << 5;
- QTest::newRow("2*2") << 32 << 2 << 2;
- QTest::newRow("3*2") << 32 << 3 << 2;
- QTest::newRow("3*5") << 32 << 3 << 5;
+ QTest::newRow("1*5") << 1 << 5;
+ QTest::newRow("2*2") << 2 << 2;
+ QTest::newRow("3*2") << 3 << 2;
+ QTest::newRow("3*5") << 3 << 5;
}
void tst_qqmlchangeset::random()
{
- QFETCH(int, seed);
QFETCH(int, combinations);
QFETCH(int, depth);
- qsrand(seed);
-
int failures = 0;
for (int i = 0; i < 20000; ++i) {
QQmlChangeSet accumulatedSet;
@@ -1490,27 +1487,27 @@ void tst_qqmlchangeset::random()
for (int j = 0; j < combinations; ++j) {
QQmlChangeSet set;
for (int k = 0; k < depth; ++k) {
- switch (-(qrand() % 3)) {
+ switch (-QRandomGenerator::global()->bounded(3)) {
case InsertOp: {
- int index = qrand() % (modelCount + 1);
- int count = qrand() % 5 + 1;
+ int index = QRandomGenerator::global()->bounded(modelCount + 1);
+ int count = QRandomGenerator::global()->bounded(5) + 1;
set.insert(index, count);
input.append(Insert(index, count));
modelCount += count;
break;
}
case RemoveOp: {
- const int index = qrand() % (modelCount + 1);
- const int count = qrand() % (modelCount - index + 1);
+ const int index = QRandomGenerator::global()->bounded(modelCount + 1);
+ const int count = QRandomGenerator::global()->bounded(modelCount - index + 1);
set.remove(index, count);
input.append(Remove(index, count));
modelCount -= count;
break;
}
case MoveOp: {
- const int from = qrand() % (modelCount + 1);
- const int count = qrand() % (modelCount - from + 1);
- const int to = qrand() % (modelCount - count + 1);
+ const int from = QRandomGenerator::global()->bounded(modelCount + 1);
+ const int count = QRandomGenerator::global()->bounded(modelCount - from + 1);
+ const int to = QRandomGenerator::global()->bounded(modelCount - count + 1);
const int moveId = moveCount++;
set.move(from, to, count, moveId);
input.append(Move(from, to, count, moveId));
diff --git a/tests/auto/qml/qqmlcomponent/data/InitialPropertyTest.qml b/tests/auto/qml/qqmlcomponent/data/InitialPropertyTest.qml
new file mode 100644
index 0000000000..7de276f2d8
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/InitialPropertyTest.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property bool ok: false
+}
diff --git a/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml
new file mode 100644
index 0000000000..431c659424
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent#2.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+
+QtObject {}
diff --git a/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml
new file mode 100644
index 0000000000..431c659424
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/QtObjectComponent.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+
+QtObject {}
diff --git a/tests/auto/qml/qqmlcomponent/data/nonExistentInitialProperty.qml b/tests/auto/qml/qqmlcomponent/data/nonExistentInitialProperty.qml
new file mode 100644
index 0000000000..ef89e46088
--- /dev/null
+++ b/tests/auto/qml/qqmlcomponent/data/nonExistentInitialProperty.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+QtObject {
+ property Component factory: Qt.createComponent(Qt.resolvedUrl("InitialPropertyTest.qml"), Component.PreferSynchronous)
+ property var incubator
+ function startIncubation()
+ {
+ incubator = factory.incubateObject(null, { ok: true, nonExistent: 42 }, Qt.Asynchronous)
+ }
+}
diff --git a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
index 9f8c8a4e24..54012e050c 100644
--- a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
+++ b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro
@@ -2,12 +2,13 @@ CONFIG += testcase
TARGET = tst_qqmlcomponent
macx:CONFIG -= app_bundle
-INCLUDEPATH += ../../shared/
SOURCES += tst_qqmlcomponent.cpp \
../../shared/testhttpserver.cpp
HEADERS += ../../shared/testhttpserver.h
+RESOURCES += data/QtObjectComponent.qml
+
include (../../shared/util.pri)
TESTDATA = data/*
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index f2b0b9973e..7c7c7d3bd0 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -89,7 +89,7 @@ public slots:
static void gc(QQmlEngine &engine)
{
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
@@ -116,7 +116,11 @@ private slots:
void onDestructionCount();
void recursion();
void recursionContinuation();
+ void partialComponentCreation();
void callingContextForInitialProperties();
+ void setNonExistentInitialProperty();
+ void relativeUrl_data();
+ void relativeUrl();
private:
QQmlEngine engine;
@@ -155,7 +159,7 @@ void tst_qqmlcomponent::qmlIncubateObject()
{
QQmlComponent component(&engine, testFileUrl("incubateObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), false);
@@ -169,8 +173,8 @@ void tst_qqmlcomponent::qmlCreateWindow()
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(testFileUrl("createWindow.qml"));
- QQuickWindow* window = qobject_cast<QQuickWindow *>(component.create());
- QVERIFY(window);
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
}
void tst_qqmlcomponent::qmlCreateObjectAutoParent_data()
@@ -188,8 +192,8 @@ void tst_qqmlcomponent::qmlCreateObjectAutoParent()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(testFile));
- QQuickItem *root = qobject_cast<QQuickItem *>(component.create());
- QVERIFY(root);
+ QScopedPointer<QObject> root(qobject_cast<QQuickItem *>(component.create()));
+ QVERIFY(!root.isNull());
QObject *qtobjectParent = root->property("qtobjectParent").value<QObject*>();
QQuickItem *itemParent = qobject_cast<QQuickItem *>(root->property("itemParent").value<QObject*>());
QQuickWindow *windowParent = qobject_cast<QQuickWindow *>(root->property("windowParent").value<QObject*>());
@@ -234,8 +238,8 @@ void tst_qqmlcomponent::qmlCreateObjectAutoParent()
QCOMPARE(window_item->parent(), windowParent);
QCOMPARE(window_window->parent(), windowParent);
- QCOMPARE(qobject_cast<QQuickItem *>(qtobject_item)->parentItem(), (QQuickItem *)0);
- QCOMPARE(qobject_cast<QQuickWindow *>(qtobject_window)->transientParent(), (QQuickWindow *)0);
+ QCOMPARE(qobject_cast<QQuickItem *>(qtobject_item)->parentItem(), (QQuickItem *)nullptr);
+ QCOMPARE(qobject_cast<QQuickWindow *>(qtobject_window)->transientParent(), (QQuickWindow *)nullptr);
QCOMPARE(qobject_cast<QQuickItem *>(item_item)->parentItem(), itemParent);
QCOMPARE(qobject_cast<QQuickWindow *>(item_window)->transientParent(), itemParent->window());
QCOMPARE(qobject_cast<QQuickItem *>(window_item)->parentItem(), windowParent->contentItem());
@@ -247,45 +251,52 @@ void tst_qqmlcomponent::qmlCreateObjectWithProperties()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createObjectWithScript.qml"));
QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8());
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QObject *testObject1 = object->property("declarativerectangle").value<QObject*>();
- QVERIFY(testObject1);
- QCOMPARE(testObject1->parent(), object);
- QCOMPARE(testObject1->property("x").value<int>(), 17);
- QCOMPARE(testObject1->property("y").value<int>(), 17);
- QCOMPARE(testObject1->property("color").value<QColor>(), QColor(255,255,255));
- QCOMPARE(QQmlProperty::read(testObject1,"border.width").toInt(), 3);
- QCOMPARE(QQmlProperty::read(testObject1,"innerRect.border.width").toInt(), 20);
- delete testObject1;
-
- QObject *testObject2 = object->property("declarativeitem").value<QObject*>();
- QVERIFY(testObject2);
- QCOMPARE(testObject2->parent(), object);
- //QCOMPARE(testObject2->metaObject()->className(), "QDeclarativeItem_QML_2");
- QCOMPARE(testObject2->property("x").value<int>(), 17);
- QCOMPARE(testObject2->property("y").value<int>(), 17);
- QCOMPARE(testObject2->property("testBool").value<bool>(), true);
- QCOMPARE(testObject2->property("testInt").value<int>(), 17);
- QCOMPARE(testObject2->property("testObject").value<QObject*>(), object);
- delete testObject2;
-
- QObject *testBindingObj = object->property("bindingTestObject").value<QObject*>();
- QVERIFY(testBindingObj);
- QCOMPARE(testBindingObj->parent(), object);
- QCOMPARE(testBindingObj->property("testValue").value<int>(), 300);
- object->setProperty("width", 150);
- QCOMPARE(testBindingObj->property("testValue").value<int>(), 150 * 3);
- delete testBindingObj;
-
- QObject *testBindingThisObj = object->property("bindingThisTestObject").value<QObject*>();
- QVERIFY(testBindingThisObj);
- QCOMPARE(testBindingThisObj->parent(), object);
- QCOMPARE(testBindingThisObj->property("testValue").value<int>(), 900);
- testBindingThisObj->setProperty("width", 200);
- QCOMPARE(testBindingThisObj->property("testValue").value<int>(), 200 * 3);
- delete testBindingThisObj;
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ {
+ QScopedPointer<QObject> testObject1(object->property("declarativerectangle")
+ .value<QObject*>());
+ QVERIFY(testObject1);
+ QCOMPARE(testObject1->parent(), object.data());
+ QCOMPARE(testObject1->property("x").value<int>(), 17);
+ QCOMPARE(testObject1->property("y").value<int>(), 17);
+ QCOMPARE(testObject1->property("color").value<QColor>(), QColor(255,255,255));
+ QCOMPARE(QQmlProperty::read(testObject1.data(),"border.width").toInt(), 3);
+ QCOMPARE(QQmlProperty::read(testObject1.data(),"innerRect.border.width").toInt(), 20);
+ }
+
+ {
+ QScopedPointer<QObject> testObject2(object->property("declarativeitem").value<QObject*>());
+ QVERIFY(testObject2);
+ QCOMPARE(testObject2->parent(), object.data());
+ //QCOMPARE(testObject2->metaObject()->className(), "QDeclarativeItem_QML_2");
+ QCOMPARE(testObject2->property("x").value<int>(), 17);
+ QCOMPARE(testObject2->property("y").value<int>(), 17);
+ QCOMPARE(testObject2->property("testBool").value<bool>(), true);
+ QCOMPARE(testObject2->property("testInt").value<int>(), 17);
+ QCOMPARE(testObject2->property("testObject").value<QObject*>(), object.data());
+ }
+
+ {
+ QScopedPointer<QObject> testBindingObj(object->property("bindingTestObject")
+ .value<QObject*>());
+ QVERIFY(testBindingObj);
+ QCOMPARE(testBindingObj->parent(), object.data());
+ QCOMPARE(testBindingObj->property("testValue").value<int>(), 300);
+ object->setProperty("width", 150);
+ QCOMPARE(testBindingObj->property("testValue").value<int>(), 150 * 3);
+ }
+
+ {
+ QScopedPointer<QObject> testBindingThisObj(object->property("bindingThisTestObject")
+ .value<QObject*>());
+ QVERIFY(testBindingThisObj);
+ QCOMPARE(testBindingThisObj->parent(), object.data());
+ QCOMPARE(testBindingThisObj->property("testValue").value<int>(), 900);
+ testBindingThisObj->setProperty("width", 200);
+ QCOMPARE(testBindingThisObj->property("testValue").value<int>(), 200 * 3);
+ }
}
void tst_qqmlcomponent::qmlCreateParentReference()
@@ -299,7 +310,7 @@ void tst_qqmlcomponent::qmlCreateParentReference()
QQmlComponent component(&engine, testFileUrl("createParentReference.qml"));
QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(QMetaObject::invokeMethod(object, "createChild"));
delete object;
@@ -325,7 +336,7 @@ void tst_qqmlcomponent::async()
QCOMPARE(watcher.error, 0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -346,7 +357,7 @@ void tst_qqmlcomponent::asyncHierarchy()
QCOMPARE(watcher.error, 0);
QObject *root = component.create();
- QVERIFY(root != 0);
+ QVERIFY(root != nullptr);
// ensure that the parent-child relationship hierarchy is correct
// (use QQuickItem* for all children rather than types which are not publicly exported)
@@ -411,7 +422,7 @@ void tst_qqmlcomponent::componentUrlCanonicalization()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
}
@@ -421,7 +432,7 @@ void tst_qqmlcomponent::componentUrlCanonicalization()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.2.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
}
@@ -430,7 +441,7 @@ void tst_qqmlcomponent::componentUrlCanonicalization()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.3.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
}
@@ -439,7 +450,7 @@ void tst_qqmlcomponent::componentUrlCanonicalization()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("componentUrlCanonicalization.4.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
}
@@ -459,7 +470,7 @@ void tst_qqmlcomponent::onDestructionLookup()
QQmlComponent component(&engine, testFileUrl("onDestructionLookup.qml"));
QScopedPointer<QObject> object(component.create());
gc(engine);
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
}
@@ -475,7 +486,7 @@ void tst_qqmlcomponent::onDestructionCount()
QTest::ignoreMessage(QtWarningMsg, warning.data());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
// Warning should not be emitted any further
@@ -485,7 +496,7 @@ void tst_qqmlcomponent::onDestructionCount()
{
QQmlTestMessageHandler messageHandler;
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
warnings = messageHandler.messages();
}
@@ -503,7 +514,7 @@ void tst_qqmlcomponent::recursion()
QTest::ignoreMessage(QtWarningMsg, QLatin1String("QQmlComponent: Component creation is recursing - aborting").data());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// Sub-object creation does not succeed
QCOMPARE(object->property("success").toBool(), false);
@@ -518,12 +529,35 @@ void tst_qqmlcomponent::recursionContinuation()
QTest::ignoreMessage(QtWarningMsg, QLatin1String("QQmlComponent: Component creation is recursing - aborting").data());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// Eventual sub-object creation succeeds
QVERIFY(object->property("success").toBool());
}
+void tst_qqmlcomponent::partialComponentCreation()
+{
+ const int maxCount = 17;
+ QQmlEngine engine;
+ QScopedPointer<QQmlComponent> components[maxCount];
+ QScopedPointer<QObject> objects[maxCount];
+ QQmlTestMessageHandler messageHandler;
+
+ QCOMPARE(engine.outputWarningsToStandardError(), true);
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i].reset(new QQmlComponent(&engine, testFileUrl("QtObjectComponent.qml")));
+ objects[i].reset(components[i]->beginCreate(engine.rootContext()));
+ QVERIFY(objects[i].isNull() == false);
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i]->completeCreate();
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+}
+
class CallingContextCheckingClass : public QObject
{
Q_OBJECT
@@ -536,13 +570,13 @@ public:
int value() const { return m_value; }
void setValue(int v) {
scopeObject.clear();
- callingContextData.setContextData(0);
+ callingContextData.setContextData(nullptr);
m_value = v;
QJSEngine *jsEngine = qjsEngine(this);
if (!jsEngine)
return;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(jsEngine);
+ QV4::ExecutionEngine *v4 = jsEngine->handle();
if (!v4)
return;
QV4::Scope scope(v4);
@@ -581,6 +615,45 @@ void tst_qqmlcomponent::callingContextForInitialProperties()
QVERIFY(checker->scopeObject->metaObject()->indexOfProperty("incubatedObject") != -1);
}
+void tst_qqmlcomponent::setNonExistentInitialProperty()
+{
+ QQmlIncubationController controller;
+ QQmlEngine engine;
+ engine.setIncubationController(&controller);
+ QQmlComponent component(&engine, testFileUrl("nonExistentInitialProperty.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QMetaObject::invokeMethod(obj.data(), "startIncubation");
+ QJSValue incubatorStatus = obj->property("incubator").value<QJSValue>();
+ incubatorStatus.property("forceCompletion").callWithInstance(incubatorStatus);
+ QJSValue objectWrapper = incubatorStatus.property("object");
+ QVERIFY(objectWrapper.isQObject());
+ QPointer<QObject> object(objectWrapper.toQObject());
+ QVERIFY(object->property("ok").toBool());
+}
+
+void tst_qqmlcomponent::relativeUrl_data()
+{
+ QTest::addColumn<QUrl>("url");
+
+ QTest::addRow("fromLocalFile") << QUrl::fromLocalFile("data/QtObjectComponent.qml");
+ QTest::addRow("fromLocalFileHash") << QUrl::fromLocalFile("data/QtObjectComponent#2.qml");
+ QTest::addRow("constructor") << QUrl("data/QtObjectComponent.qml");
+ QTest::addRow("absolute") << QUrl::fromLocalFile(QFINDTESTDATA("data/QtObjectComponent.qml"));
+ QTest::addRow("qrc") << QUrl("qrc:/data/QtObjectComponent.qml");
+}
+
+void tst_qqmlcomponent::relativeUrl()
+{
+ QFETCH(QUrl, url);
+
+ QQmlComponent component(&engine);
+ // Shouldn't assert in QQmlTypeLoader; we want QQmlComponent to assume that
+ // data/QtObjectComponent.qml refers to the data/QtObjectComponent.qml in the current working directory.
+ component.loadUrl(url);
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+}
+
QTEST_MAIN(tst_qqmlcomponent)
#include "tst_qqmlcomponent.moc"
diff --git a/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml b/tests/auto/qml/qqmlconnections/data/override-proxy-type.qml
new file mode 100644
index 0000000000..80e459966b
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/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
+ onSomeSignal: testEnum = Proxy.EnumValue;
+ }
+
+ Component.onCompleted: someSignal()
+}
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index 22e9724c61..dc29363fcf 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -55,6 +55,7 @@ private slots:
void disabledAtStart();
void clearImplicitTarget();
void onWithoutASignal();
+ void noAcceleratedGlobalLookup();
private:
QQmlEngine engine;
@@ -70,7 +71,7 @@ void tst_qqmlconnections::defaultValues()
QQmlComponent c(&engine, testFileUrl("test-connection3.qml"));
QQmlConnections *item = qobject_cast<QQmlConnections*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QVERIFY(!item->target());
delete item;
@@ -82,9 +83,9 @@ void tst_qqmlconnections::properties()
QQmlComponent c(&engine, testFileUrl("test-connection2.qml"));
QQmlConnections *item = qobject_cast<QQmlConnections*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QCOMPARE(item->target(), item);
delete item;
@@ -96,7 +97,7 @@ void tst_qqmlconnections::connection()
QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QCOMPARE(item->property("tested").toBool(), false);
QCOMPARE(item->width(), 50.);
@@ -113,7 +114,7 @@ void tst_qqmlconnections::trimming()
QQmlComponent c(&engine, testFileUrl("trimming.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("tested").toString(), QString(""));
int index = object->metaObject()->indexOfSignal("testMe(int,QString)");
@@ -133,7 +134,7 @@ void tst_qqmlconnections::targetChanged()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("connection-targetchange.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QQmlConnections *connections = item->findChild<QQmlConnections*>("connections");
QVERIFY(connections);
@@ -178,7 +179,7 @@ void tst_qqmlconnections::unknownSignals()
QQmlEngine engine;
QQmlComponent c(&engine, url);
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// check that connection is created (they are all runtime errors)
QQmlConnections *connections = object->findChild<QQmlConnections*>("connections");
@@ -222,7 +223,7 @@ class TestObject : public QObject
Q_PROPERTY(bool ran READ ran WRITE setRan)
public:
- TestObject(QObject *parent = 0) : QObject(parent), m_ran(false) {}
+ TestObject(QObject *parent = nullptr) : QObject(parent), m_ran(false) {}
~TestObject() {}
bool ran() const { return m_ran; }
@@ -244,7 +245,7 @@ void tst_qqmlconnections::rewriteErrors()
QQmlComponent c(&engine, testFileUrl("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 != 0);
+ QVERIFY(obj != nullptr);
obj->unnamedArgumentSignal(1, .5, "hello");
QCOMPARE(obj->ran(), false);
@@ -256,7 +257,7 @@ void tst_qqmlconnections::rewriteErrors()
QQmlComponent c(&engine, testFileUrl("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 != 0);
+ QVERIFY(obj != nullptr);
obj->signalWithGlobalName(10);
QCOMPARE(obj->ran(), false);
@@ -272,7 +273,7 @@ Q_OBJECT
Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged)
public:
- MyTestSingletonType(QObject *parent = 0) : QObject(parent), m_intProp(0), m_changeCount(0) {}
+ MyTestSingletonType(QObject *parent = nullptr) : QObject(parent), m_intProp(0), m_changeCount(0) {}
~MyTestSingletonType() {}
Q_INVOKABLE int otherMethod(int val) { return val + 4; }
@@ -307,7 +308,7 @@ void tst_qqmlconnections::singletonTypeTarget()
qmlRegisterSingletonType<MyTestSingletonType>("MyTestSingletonType", 1, 0, "Api", module_api_factory);
QQmlComponent component(&engine, testFileUrl("singletontype-target.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("moduleIntPropChangedCount").toInt(), 0);
QCOMPARE(object->property("moduleOtherSignalCount").toInt(), 0);
@@ -333,7 +334,7 @@ void tst_qqmlconnections::enableDisable_QTBUG_36350()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("test-connection.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QQmlConnections *connections = item->findChild<QQmlConnections*>("connections");
QVERIFY(connections);
@@ -361,7 +362,7 @@ void tst_qqmlconnections::disabledAtStart()
QQmlComponent c(&engine, testFileUrl("disabled-at-start.qml"));
QObject * const object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("tested").toBool(), false);
const int index = object->metaObject()->indexOfSignal("testMe()");
@@ -379,7 +380,7 @@ void tst_qqmlconnections::clearImplicitTarget()
QQmlComponent c(&engine, testFileUrl("test-connection-implicit.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
// normal case: fire Connections
item->setWidth(100.);
@@ -389,7 +390,7 @@ void tst_qqmlconnections::clearImplicitTarget()
// clear the implicit target
QQmlConnections *connections = item->findChild<QQmlConnections*>();
QVERIFY(connections);
- connections->setTarget(0);
+ connections->setTarget(nullptr);
// target cleared: no longer fire Connections
item->setWidth(150.);
@@ -407,6 +408,30 @@ void tst_qqmlconnections::onWithoutASignal()
QVERIFY(item == nullptr); // should parse error, and not give us an item (or crash).
}
+class Proxy : public QObject
+{
+ Q_OBJECT
+public:
+ enum MyEnum { EnumValue = 20, AnotherEnumValue };
+ Q_ENUM(MyEnum)
+
+signals:
+ void someSignal();
+};
+
+void tst_qqmlconnections::noAcceleratedGlobalLookup()
+{
+ qRegisterMetaType<Proxy::MyEnum>();
+ qmlRegisterType<Proxy>("test.proxy", 1, 0, "Proxy");
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("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.toInt(), int(Proxy::EnumValue));
+}
+
QTEST_MAIN(tst_qqmlconnections)
#include "tst_qqmlconnections.moc"
diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
index d19b6ecc41..d593f0dfa1 100644
--- a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml
@@ -37,7 +37,7 @@
**
****************************************************************************/
-import QtQuick 2.8
+import QtQuick 2.12
Item {
id:root
@@ -48,6 +48,12 @@ Item {
}
LoggingCategory {
+ id: testCategoryStartingFromWarning
+ name: "qt.test.warning"
+ defaultLogLevel: LoggingCategory.Warning
+ }
+
+ LoggingCategory {
id: emptyCategory
}
@@ -57,8 +63,14 @@ Item {
console.info(testCategory, "console.info");
console.warn(testCategory, "console.warn");
console.error(testCategory, "console.error");
+ console.debug(testCategoryStartingFromWarning, "console.debug");
+ console.log(testCategoryStartingFromWarning, "console.log");
+ console.info(testCategoryStartingFromWarning, "console.info");
+ console.warn(testCategoryStartingFromWarning, "console.warn");
+ console.error(testCategoryStartingFromWarning, "console.error");
testCategory.name = "qt.test2";
+ testCategory.defaultLogLevel = LoggingCategory.Debug;
console.error(emptyCategory, "console.error");
}
diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml
index d55c99bcbd..1f929d311b 100644
--- a/tests/auto/qml/qqmlconsole/data/logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/logging.qml
@@ -67,6 +67,10 @@ QtObject {
console.log(1, "pong!", new Object);
console.log(1, ["ping","pong"], new Object, 2);
+ console.log(contextStringListProperty);
+ console.log(customObject);
+ console.log([[1,2,3,[2,2,2,2],4],[5,6,7,8]]);
+
try {
console.log(exception);
} catch (e) {
diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
index f832143935..b157314071 100644
--- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
+++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
@@ -29,6 +29,7 @@
#include <QDebug>
#include <QQmlEngine>
#include <QQmlComponent>
+#include <QQmlContext>
#include <QLoggingCategory>
#include "../../shared/util.h"
@@ -50,6 +51,15 @@ private:
QQmlEngine engine;
};
+struct CustomObject {};
+
+QDebug operator<<(QDebug dbg, const CustomObject &)
+{
+ return dbg << "MY OBJECT";
+}
+
+Q_DECLARE_METATYPE(CustomObject)
+
void tst_qqmlconsole::logging()
{
QUrl testUrl = testFileUrl("logging.qml");
@@ -74,18 +84,28 @@ void tst_qqmlconsole::logging()
QTest::ignoreMessage(QtDebugMsg, "{\"a\":\"hello\",\"d\":1}");
QTest::ignoreMessage(QtDebugMsg, "undefined");
QTest::ignoreMessage(QtDebugMsg, "12");
- QTest::ignoreMessage(QtDebugMsg, "function() { [code] }");
+ QTest::ignoreMessage(QtDebugMsg, "function e() { [native code] }");
QTest::ignoreMessage(QtDebugMsg, "true");
// Printing QML object prints out the class/type of QML object with the memory address
// QTest::ignoreMessage(QtDebugMsg, "QtObject_QML_0(0xABCD..)");
// QTest::ignoreMessage(QtDebugMsg, "[object Object]");
QTest::ignoreMessage(QtDebugMsg, "1 pong! [object Object]");
QTest::ignoreMessage(QtDebugMsg, "1 [ping,pong] [object Object] 2");
+ QTest::ignoreMessage(QtDebugMsg, "[Hello,World]");
+ QTest::ignoreMessage(QtDebugMsg, "QVariant(CustomObject, MY OBJECT)");
+ QTest::ignoreMessage(QtDebugMsg, "[[1,2,3,[2,2,2,2],4],[5,6,7,8]]");
+
+ QScopedPointer<QQmlContext> loggingContext(new QQmlContext(engine.rootContext()));
+ QStringList stringList; stringList << QStringLiteral("Hello") << QStringLiteral("World");
+ loggingContext->setContextProperty("contextStringListProperty", stringList);
+
+ CustomObject customObject;
+ QVERIFY(QMetaType::registerDebugStreamOperator<CustomObject>());
+ loggingContext->setContextProperty("customObject", QVariant::fromValue(customObject));
QQmlComponent component(&engine, testUrl);
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
+ QScopedPointer<QObject> object(component.create(loggingContext.data()));
+ QVERIFY(object != nullptr);
}
void tst_qqmlconsole::categorized_logging()
@@ -102,13 +122,18 @@ void tst_qqmlconsole::categorized_logging()
QQmlComponent component(&engine, testUrl);
QObject *object = component.create();
- QVERIFY2(object != 0, component.errorString().toUtf8());
+ QVERIFY2(object != nullptr, component.errorString().toUtf8());
QVERIFY(messageHandler.messages().contains("qt.test: console.info"));
QVERIFY(messageHandler.messages().contains("qt.test: console.warn"));
QVERIFY(messageHandler.messages().contains("qt.test: console.error"));
+ QVERIFY(!messageHandler.messages().contains("qt.test.warning: console.debug"));
+ QVERIFY(!messageHandler.messages().contains("qt.test.warning: console.log"));
+ QVERIFY(!messageHandler.messages().contains("qt.test.warning: console.info"));
+ QVERIFY(messageHandler.messages().contains("qt.test.warning: console.warn"));
+ QVERIFY(messageHandler.messages().contains("qt.test.warning: console.error"));
- QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) +
+ QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(56).arg(5) +
"QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !";
QVERIFY(messageHandler.messages().contains(emptyCategory));
@@ -116,7 +141,11 @@ void tst_qqmlconsole::categorized_logging()
"QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created";
QVERIFY(messageHandler.messages().contains(changedCategory));
- QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) +
+ QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) +
+ "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created";
+ QVERIFY(messageHandler.messages().contains(changedDefaultLogLevel));
+
+ QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(75) +
"Error: A QmlLoggingCatgory was provided without a valid name";
QVERIFY(messageHandler.messages().contains(useEmptyCategory));
@@ -135,7 +164,7 @@ void tst_qqmlconsole::tracing()
QQmlComponent component(&engine, testUrl);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -149,7 +178,7 @@ void tst_qqmlconsole::profiling()
QQmlComponent component(&engine, testUrl);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -170,7 +199,7 @@ void tst_qqmlconsole::testAssert()
QQmlComponent component(&engine, testUrl);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -191,7 +220,7 @@ void tst_qqmlconsole::exception()
QQmlComponent component(&engine, testUrl);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
diff --git a/tests/auto/qml/qqmlcontext/data/ContextLeak.js b/tests/auto/qml/qqmlcontext/data/ContextLeak.js
new file mode 100644
index 0000000000..e43b1bb230
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/ContextLeak.js
@@ -0,0 +1 @@
+var value = 42
diff --git a/tests/auto/qml/qqmlcontext/data/Drawer.qml b/tests/auto/qml/qqmlcontext/data/Drawer.qml
new file mode 100644
index 0000000000..b35d5c8d34
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/Drawer.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.12
+import QtQuick.Window 2.11
+
+Rectangle {
+ parent: Window.contentItem
+}
diff --git a/tests/auto/qml/qqmlcontext/data/MyItem.qml b/tests/auto/qml/qqmlcontext/data/MyItem.qml
new file mode 100644
index 0000000000..2ffd984dfa
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/MyItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ Component.onCompleted: 5 + 5
+}
diff --git a/tests/auto/qml/qqmlcontext/data/Singleton.qml b/tests/auto/qml/qqmlcontext/data/Singleton.qml
new file mode 100644
index 0000000000..68ef5850e3
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/Singleton.qml
@@ -0,0 +1,5 @@
+pragma Singleton
+import QtQml 2.0
+QtObject {
+ readonly property string song: "Highway to Hell"
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextLeak.qml b/tests/auto/qml/qqmlcontext/data/contextLeak.qml
new file mode 100644
index 0000000000..515b3a1aa2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextLeak.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import "ContextLeak.js" as ContextLeak
+QtObject {
+ property int value: ContextLeak.value
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextObjectHierarchy.qml b/tests/auto/qml/qqmlcontext/data/contextObjectHierarchy.qml
new file mode 100644
index 0000000000..91978d98a0
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextObjectHierarchy.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.6
+import QtQuick.Window 2.2
+
+Window {
+ Drawer {}
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
new file mode 100644
index 0000000000..2e0e6f20e2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+
+import constants 1.0
+
+QtObject {
+ function createClosure() {
+ return function() { return Sing.song; }
+ }
+ function createComponentFactory() {
+ return function(parentObj) {
+ return Qt.createQmlObject('import QtQml 2.0; QtObject { property string test: "ok"; }', parentObj);
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlcontext/data/outerContextObject.qml b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml
new file mode 100644
index 0000000000..992b760915
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml
@@ -0,0 +1,18 @@
+import QtQml 2.2
+
+QtObject {
+ id: window
+
+ property Component itemComponent: Qt.createComponent("MyItem.qml")
+ property MyItem item
+
+ property Timer timer: Timer {
+ running: true
+ interval: 10
+ repeat: true
+ onTriggered: {
+ item = itemComponent.createObject(null, {});
+ gc();
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index f49fd391ac..cb4bee0d3a 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -28,11 +28,14 @@
#include <qtest.h>
#include <QDebug>
+#include <QTimer>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQmlComponent>
#include <QQmlExpression>
#include <private/qqmlcontext_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4object_p.h>
#include "../../shared/util.h"
class tst_qqmlcontext : public QQmlDataTest
@@ -47,6 +50,7 @@ private slots:
void engineMethod();
void parentContext();
void setContextProperty();
+ void setContextProperties();
void setContextObject();
void destruction();
void idAsContextProperty();
@@ -62,6 +66,11 @@ private slots:
void evalAfterInvalidate();
void qobjectDerived();
void qtbug_49232();
+ void contextViaClosureAfterDestruction();
+ void contextLeak();
+
+ void outerContextObject();
+ void contextObjectHierarchy();
private:
QQmlEngine engine;
@@ -111,7 +120,7 @@ void tst_qqmlcontext::resolvedUrl()
QQmlContext ctxt2(ctxt);
QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl("http://www.qt-project.org/main2.qml"));
- delete ctxt; ctxt = 0;
+ delete ctxt; ctxt = nullptr;
QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl());
}
@@ -139,7 +148,7 @@ void tst_qqmlcontext::engineMethod()
QCOMPARE(ctxt3.engine(), engine);
QCOMPARE(ctxt4.engine(), engine);
- delete engine; engine = 0;
+ delete engine; engine = nullptr;
QCOMPARE(ctxt.engine(), engine);
QCOMPARE(ctxt2.engine(), engine);
@@ -151,7 +160,7 @@ void tst_qqmlcontext::parentContext()
{
QQmlEngine *engine = new QQmlEngine;
- QCOMPARE(engine->rootContext()->parentContext(), (QQmlContext *)0);
+ QCOMPARE(engine->rootContext()->parentContext(), (QQmlContext *)nullptr);
QQmlContext *ctxt = new QQmlContext(engine);
QQmlContext *ctxt2 = new QQmlContext(ctxt);
@@ -169,23 +178,23 @@ void tst_qqmlcontext::parentContext()
QCOMPARE(ctxt6->parentContext(), engine->rootContext());
QCOMPARE(ctxt7->parentContext(), engine->rootContext());
- delete ctxt2; ctxt2 = 0;
+ delete ctxt2; ctxt2 = nullptr;
QCOMPARE(ctxt->parentContext(), engine->rootContext());
- QCOMPARE(ctxt3->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt4->parentContext(), (QQmlContext *)0);
+ QCOMPARE(ctxt3->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt4->parentContext(), (QQmlContext *)nullptr);
QCOMPARE(ctxt5->parentContext(), ctxt);
QCOMPARE(ctxt6->parentContext(), engine->rootContext());
QCOMPARE(ctxt7->parentContext(), engine->rootContext());
- delete engine; engine = 0;
+ delete engine; engine = nullptr;
- QCOMPARE(ctxt->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt3->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt4->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt5->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt6->parentContext(), (QQmlContext *)0);
- QCOMPARE(ctxt7->parentContext(), (QQmlContext *)0);
+ QCOMPARE(ctxt->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt3->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt4->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt5->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt6->parentContext(), (QQmlContext *)nullptr);
+ QCOMPARE(ctxt7->parentContext(), (QQmlContext *)nullptr);
delete ctxt7;
delete ctxt6;
@@ -362,6 +371,32 @@ void tst_qqmlcontext::setContextProperty()
}
}
+void tst_qqmlcontext::setContextProperties()
+{
+ QQmlContext ctxt(&engine);
+
+ TestObject obj1;
+ obj1.setA(3345);
+ TestObject obj2;
+ obj2.setA(-19);
+
+ QVector<QQmlContext::PropertyPair> properties;
+
+ properties.append({QString("a"), QVariant(10)});
+ properties.append({QString("b"), QVariant(19)});
+ properties.append({QString("d"), QVariant::fromValue<TestObject*>(&obj2)});
+ properties.append({QString("c"), QVariant(QString("Hello World!"))});
+ properties.append({QString("e"), QVariant::fromValue<TestObject*>(&obj1)});
+
+ ctxt.setContextProperties(properties);
+
+ TEST_CONTEXT_PROPERTY(&ctxt, a, QVariant(10));
+ TEST_CONTEXT_PROPERTY(&ctxt, b, QVariant(19));
+ TEST_CONTEXT_PROPERTY(&ctxt, c, QVariant(QString("Hello World!")));
+ TEST_CONTEXT_PROPERTY(&ctxt, d.a, QVariant(-19));
+ TEST_CONTEXT_PROPERTY(&ctxt, e.a, QVariant(3345));
+}
+
void tst_qqmlcontext::setContextObject()
{
QQmlContext ctxt(&engine);
@@ -422,12 +457,12 @@ void tst_qqmlcontext::destruction()
QObject obj;
QQmlEngine::setContextForObject(&obj, ctxt);
- QQmlExpression expr(ctxt, 0, "a");
+ QQmlExpression expr(ctxt, nullptr, "a");
QCOMPARE(ctxt, QQmlEngine::contextForObject(&obj));
QCOMPARE(ctxt, expr.context());
- delete ctxt; ctxt = 0;
+ delete ctxt; ctxt = nullptr;
QCOMPARE(ctxt, QQmlEngine::contextForObject(&obj));
QCOMPARE(ctxt, expr.context());
@@ -476,7 +511,7 @@ void tst_qqmlcontext::readOnlyContexts()
QCOMPARE(context->contextProperty("hello"), QVariant());
QTest::ignoreMessage(QtWarningMsg, "QQmlContext: Cannot set context object for internal context.");
- context->setContextObject(0);
+ context->setContextObject(nullptr);
QCOMPARE(context->contextObject(), obj);
delete obj;
@@ -504,7 +539,7 @@ void tst_qqmlcontext::nameForObject()
component.setData("import QtQuick 2.0; QtObject { id: root; property QtObject o: QtObject { id: nested } }", QUrl());
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(qmlContext(o)->nameForObject(o), QString("root"));
QCOMPARE(qmlContext(o)->nameForObject(qvariant_cast<QObject*>(o->property("o"))), QString("nested"));
@@ -517,12 +552,12 @@ class DeleteCommand : public QObject
{
Q_OBJECT
public:
- DeleteCommand() : object(0) {}
+ DeleteCommand() : object(nullptr) {}
QObject *object;
public slots:
- void doCommand() { if (object) delete object; object = 0; }
+ void doCommand() { if (object) delete object; object = nullptr; }
};
// Calling refresh expressions would crash if an expression or context was deleted during
@@ -655,7 +690,7 @@ void tst_qqmlcontext::skipExpressionRefresh_qtbug_53431()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_53431.qml"));
- QScopedPointer<QObject> object(component.create(0));
+ QScopedPointer<QObject> object(component.create(nullptr));
QVERIFY(!object.isNull());
QCOMPARE(object->property("value").toInt(), 1);
object->setProperty("value", 10);
@@ -682,7 +717,7 @@ void tst_qqmlcontext::evalAfterInvalidate()
QQmlComponent component(&engine, testFileUrl("evalAfterInvalidate.qml"));
QScopedPointer<QObject> o(component.create());
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
@@ -723,6 +758,140 @@ void tst_qqmlcontext::qtbug_49232()
QCOMPARE(obj->property("valueTwo"), QVariant(97));
}
+void tst_qqmlcontext::contextViaClosureAfterDestruction()
+{
+ qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "constants", 1, 0, "Sing");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextViaClosureAfterDestruction.qml"));
+ QJSValue valueClosure;
+ QJSValue componentFactoryClosure;
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ // meta-calls don't support QJSValue return types, so do the call "by hand"
+ valueClosure = engine.newQObject(obj.data()).property(QStringLiteral("createClosure")).call();
+ QVERIFY(valueClosure.isCallable());
+ componentFactoryClosure = engine.newQObject(obj.data()).property(QStringLiteral("createComponentFactory")).call();
+ QVERIFY(componentFactoryClosure.isCallable());
+ }
+ QCOMPARE(valueClosure.call().toString(), QLatin1String("Highway to Hell"));
+
+ QScopedPointer<QObject> parent(new QObject);
+ QJSValue parentWrapper = engine.newQObject(parent.data());
+ QQmlEngine::setObjectOwnership(parent.data(), QQmlEngine::CppOwnership);
+
+ QJSValue subObject = componentFactoryClosure.callWithInstance(componentFactoryClosure, QJSValueList() << parentWrapper);
+ QVERIFY(subObject.isError());
+ QCOMPARE(subObject.toString(), QLatin1String("Error: Qt.createQmlObject(): Cannot create a component in an invalid context"));
+}
+
+void tst_qqmlcontext::contextLeak()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextLeak.qml"));
+
+ QQmlGuardedContextData scriptContext;
+
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+
+ QQmlData *ddata = QQmlData::get(obj.data());
+ QVERIFY(ddata);
+ QQmlContextData *context = ddata->context;
+ QVERIFY(context);
+ QVERIFY(!context->importedScripts.isNullOrUndefined());
+ QCOMPARE(int(context->importedScripts.valueRef()->as<QV4::Object>()->getLength()), 1);
+
+ {
+ QV4::Scope scope(ddata->jsWrapper.engine());
+ QV4::ScopedValue scriptContextWrapper(scope);
+ scriptContextWrapper = context->importedScripts.valueRef()->as<QV4::Object>()->get(uint(0));
+ scriptContext = scriptContextWrapper->as<QV4::QQmlContextWrapper>()->getContext();
+ }
+ }
+
+ engine.collectGarbage();
+
+ // Each time a JS file (non-pragma-shared) is imported, we create a QQmlContext(Data) for it.
+ // Make sure that context does not leak.
+ QVERIFY(scriptContext.isNull());
+}
+
+
+static bool buildObjectList(QQmlContext *ctxt)
+{
+ static QHash<QObject *, QString> deletedObjects;
+ QQmlContextData *p = QQmlContextData::get(ctxt);
+ QObject *object = p->contextObject;
+ if (object) {
+ // If the object was actually deleted this is likely to crash in one way or another.
+ // Either the memory is still intact, then we will probably find the objectName, or it is
+ // not, then the connect() below is likely to fail.
+ if (deletedObjects.contains(object) && deletedObjects[object] == object->objectName())
+ return false;
+ QObject::connect(object, &QObject::destroyed, [object]() {
+ object->setObjectName(QString::number(deletedObjects.size()));
+ deletedObjects.insert(object, object->objectName());
+ });
+ }
+
+ QQmlContextData *child = p->childContexts;
+ while (child) {
+ if (!buildObjectList(child->asQQmlContext()))
+ return false;
+ child = child->nextChild;
+ }
+
+ return true;
+}
+
+void tst_qqmlcontext::outerContextObject()
+{
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("outerContextObject.qml"));
+ QVERIFY(component.isReady());
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ int iterations = 0;
+ QTimer timer;
+ timer.setInterval(1);
+ QObject::connect(&timer, &QTimer::timeout, &engine, [&]() {
+ if (!buildObjectList(engine.rootContext())) {
+ iterations = 100;
+ timer.stop();
+ QFAIL("Deleted object found as context object");
+ } else {
+ ++iterations;
+ }
+ });
+ timer.start();
+
+ QTRY_VERIFY(iterations >= 100);
+}
+
+void tst_qqmlcontext::contextObjectHierarchy()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("contextObjectHierarchy.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(!root.isNull());
+
+ for (const QObject *child : root->children())
+ QVERIFY(QQmlData::get(child)->outerContext != nullptr);
+
+ connect(root.data(), &QObject::destroyed, [&root]() {
+ for (const QObject *child : root->children())
+ QCOMPARE(QQmlData::get(child)->outerContext, nullptr);
+ });
+}
+
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 63b5de044e..99cabb4b09 100644
--- a/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp
+++ b/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp
@@ -102,7 +102,7 @@ void tst_qqmlcpputils::fastCast()
}
{
- QObject *nullObj = 0;
+ QObject *nullObj = nullptr;
QObject *obj = qmlobject_cast<QObject *>(nullObj);
QCOMPARE(obj, nullObj); // shouldn't crash/assert.
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml
index efca6cdb80..8912d2a314 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml
@@ -11,25 +11,26 @@ MyTypeObject {
dateTimeProperty = dateTimeVar
dateTimeProperty2 = dateTimeVar2
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
- (dateTimeProperty.getMinutes() == 0) &&
- (dateTimeProperty.getSeconds() == 1) &&
+ (dateTimeProperty.getUTCDate() == 12) &&
+ (dateTimeProperty.getUTCHours() == 0) &&
+ (dateTimeProperty.getUTCMinutes() == 0) &&
+ (dateTimeProperty.getUTCSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
- (dateTimeProperty2.getMinutes() == 59) &&
- (dateTimeProperty2.getSeconds() == 59)
+ (dateTimeProperty2.getUTCDate() == 12) &&
+ (dateTimeProperty2.getUTCHours() == 23) &&
+ (dateTimeProperty2.getUTCMinutes() == 59) &&
+ (dateTimeProperty2.getUTCSeconds() == 59)
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml
index 71dd188f05..f8c1f6eb8f 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml
@@ -12,24 +12,25 @@ MyTypeObject {
var dateTimeVar = new Date("2009-05-12T00:00:01")
var dateTimeVar2 = new Date("2009-05-12T23:59:59")
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
+ (dateTimeProperty.getDate() == 12) &&
+ (dateTimeProperty.getHours() == 0) &&
(dateTimeProperty.getMinutes() == 0) &&
(dateTimeProperty.getSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
+ (dateTimeProperty2.getDate() == 12) &&
+ (dateTimeProperty2.getHours() == 23) &&
(dateTimeProperty2.getMinutes() == 59) &&
(dateTimeProperty2.getSeconds() == 59)
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml
index 2cf740645c..e960eef193 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml
@@ -2,35 +2,36 @@ import Qt.test 1.0
import QtQuick 2.0
MyTypeObject {
- dateProperty: if (1) "2009-05-12Z"
+ dateProperty: if (1) "2009-05-12"
dateTimeProperty: if (1) "2009-05-12T00:00:01Z"
dateTimeProperty2: if (1) "2009-05-12T23:59:59Z"
boolProperty: false
Component.onCompleted: {
- var dateVar = new Date("2009-05-12Z")
+ var dateVar = new Date("2009-05-12")
var dateTimeVar = new Date("2009-05-12T00:00:01Z")
var dateTimeVar2 = new Date("2009-05-12T23:59:59Z")
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
- (dateTimeProperty.getMinutes() == 0) &&
- (dateTimeProperty.getSeconds() == 1) &&
+ (dateTimeProperty.getUTCDate() == 12) &&
+ (dateTimeProperty.getUTCHours() == 0) &&
+ (dateTimeProperty.getUTCMinutes() == 0) &&
+ (dateTimeProperty.getUTCSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
- (dateTimeProperty2.getMinutes() == 59) &&
- (dateTimeProperty2.getSeconds() == 59)
+ (dateTimeProperty2.getUTCDate() == 12) &&
+ (dateTimeProperty2.getUTCHours() == 23) &&
+ (dateTimeProperty2.getUTCMinutes() == 59) &&
+ (dateTimeProperty2.getUTCSeconds() == 59)
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml
index 9b4975c833..6dd29afbc9 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml
@@ -2,35 +2,36 @@ import Qt.test 1.0
import QtQuick 2.0
MyTypeObject {
- dateProperty: if (1) new Date("2009-05-12Z")
+ dateProperty: if (1) new Date("2009-05-12")
dateTimeProperty: if (1) new Date("2009-05-12T00:00:01Z")
dateTimeProperty2: if (1) new Date("2009-05-12T23:59:59Z")
boolProperty: false
Component.onCompleted: {
- var dateVar = new Date("2009-05-12Z")
+ var dateVar = new Date("2009-05-12")
var dateTimeVar = new Date("2009-05-12T00:00:01Z")
var dateTimeVar2 = new Date("2009-05-12T23:59:59Z")
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
- (dateTimeProperty.getMinutes() == 0) &&
- (dateTimeProperty.getSeconds() == 1) &&
+ (dateTimeProperty.getUTCDate() == 12) &&
+ (dateTimeProperty.getUTCHours() == 0) &&
+ (dateTimeProperty.getUTCMinutes() == 0) &&
+ (dateTimeProperty.getUTCSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
- (dateTimeProperty2.getMinutes() == 59) &&
- (dateTimeProperty2.getSeconds() == 59)
+ (dateTimeProperty2.getUTCDate() == 12) &&
+ (dateTimeProperty2.getUTCHours() == 23) &&
+ (dateTimeProperty2.getUTCMinutes() == 59) &&
+ (dateTimeProperty2.getUTCSeconds() == 59)
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml
index 2cf740645c..cfadaafc54 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml
@@ -2,35 +2,36 @@ import Qt.test 1.0
import QtQuick 2.0
MyTypeObject {
- dateProperty: if (1) "2009-05-12Z"
- dateTimeProperty: if (1) "2009-05-12T00:00:01Z"
- dateTimeProperty2: if (1) "2009-05-12T23:59:59Z"
+ dateProperty: if (1) "2009-05-12"
+ dateTimeProperty: if (1) "2009-05-12T00:00:01+02:00"
+ dateTimeProperty2: if (1) "2009-05-12T23:59:59+02:00"
boolProperty: false
Component.onCompleted: {
- var dateVar = new Date("2009-05-12Z")
- var dateTimeVar = new Date("2009-05-12T00:00:01Z")
- var dateTimeVar2 = new Date("2009-05-12T23:59:59Z")
+ var dateVar = new Date("2009-05-12")
+ var dateTimeVar = new Date("2009-05-12T00:00:01+02:00")
+ var dateTimeVar2 = new Date("2009-05-12T23:59:59+02:00")
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
- (dateTimeProperty.getMinutes() == 0) &&
- (dateTimeProperty.getSeconds() == 1) &&
+ (dateTimeProperty.getUTCDate() == 11) &&
+ (dateTimeProperty.getUTCHours() == 22) &&
+ (dateTimeProperty.getUTCMinutes() == 0) &&
+ (dateTimeProperty.getUTCSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
- (dateTimeProperty2.getMinutes() == 59) &&
- (dateTimeProperty2.getSeconds() == 59)
+ (dateTimeProperty2.getUTCDate() == 12) &&
+ (dateTimeProperty2.getUTCHours() == 21) &&
+ (dateTimeProperty2.getUTCMinutes() == 59) &&
+ (dateTimeProperty2.getUTCSeconds() == 59)
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml
index 73e26db0c8..97cd0d1e60 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml
@@ -3,34 +3,35 @@ import QtQuick 2.0
MyTypeObject {
dateProperty: if (1) new Date("2009-05-12")
- dateTimeProperty: if (1) new Date("2009-05-12T02:00:01+02:00")
- dateTimeProperty2: if (1) new Date("2009-05-13T01:59:59+02:00")
+ dateTimeProperty: if (1) new Date("2009-05-12T00:00:01+02:00")
+ dateTimeProperty2: if (1) new Date("2009-05-12T23:59:59+02:00")
boolProperty: false
Component.onCompleted: {
var dateVar = new Date("2009-05-12")
- var dateTimeVar = new Date("2009-05-12T02:00:01+02:00")
- var dateTimeVar2 = new Date("2009-05-13T01:59:59+02:00")
+ var dateTimeVar = new Date("2009-05-12T00:00:01+02:00")
+ var dateTimeVar2 = new Date("2009-05-12T23:59:59+02:00")
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getUTCDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
- (dateTimeProperty.getMinutes() == 0) &&
- (dateTimeProperty.getSeconds() == 1) &&
+ (dateTimeProperty.getUTCDate() == 11) &&
+ (dateTimeProperty.getUTCHours() == 22) &&
+ (dateTimeProperty.getUTCMinutes() == 0) &&
+ (dateTimeProperty.getUTCSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
- (dateTimeProperty2.getMinutes() == 59) &&
- (dateTimeProperty2.getSeconds() == 59)
+ (dateTimeProperty2.getUTCDate() == 12) &&
+ (dateTimeProperty2.getUTCHours() == 21) &&
+ (dateTimeProperty2.getUTCMinutes() == 59) &&
+ (dateTimeProperty2.getUTCSeconds() == 59)
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.qml
index 14fe20787b..73677e99f1 100644
--- a/tests/auto/qml/qqmlecmascript/data/assignDate.qml
+++ b/tests/auto/qml/qqmlecmascript/data/assignDate.qml
@@ -7,28 +7,31 @@ MyTypeObject {
var dateTimeVar = new Date("2009-05-12T00:00:01")
var dateTimeVar2 = new Date("2009-05-12T23:59:59")
+ // Date, with no zone specified, is implicitly UTC
dateProperty = dateVar
+ // Date-time, with no zone, is implicitly local-time
dateTimeProperty = dateTimeVar
dateTimeProperty2 = dateTimeVar2
- // Commented properties do not currently test true:
- boolProperty = //(dateProperty.getTime() == dateVar.getTime()) &&
+ boolProperty = (dateProperty.getTime() == dateVar.getTime()) &&
(dateProperty.getFullYear() == 2009) &&
(dateProperty.getMonth() == 5-1) &&
- //(dateProperty.getDate() == 12) &&
- (dateProperty.getHours() == 0) &&
+ (dateProperty.getDate() == 12) &&
+ (dateProperty.getUTCHours() == 0) &&
+ (dateProperty.getUTCMinutes() == 0) &&
+ (dateProperty.getUTCSeconds() == 0) &&
(dateTimeProperty.getTime() == dateTimeVar.getTime()) &&
(dateTimeProperty.getFullYear() == 2009) &&
(dateTimeProperty.getMonth() == 5-1) &&
- //(dateTimeProperty.getDate() == 12) &&
- //(dateTimeProperty.getHours() == 0) &&
+ (dateTimeProperty.getDate() == 12) &&
+ (dateTimeProperty.getHours() == 0) &&
(dateTimeProperty.getMinutes() == 0) &&
(dateTimeProperty.getSeconds() == 1) &&
(dateTimeProperty2.getTime() == dateTimeVar2.getTime()) &&
(dateTimeProperty2.getFullYear() == 2009) &&
(dateTimeProperty2.getMonth() == 5-1) &&
- //(dateTimeProperty2.getDate() == 12) &&
- //(dateTimeProperty2.getHours() == 23) &&
+ (dateTimeProperty2.getDate() == 12) &&
+ (dateTimeProperty2.getHours() == 23) &&
(dateTimeProperty2.getMinutes() == 59) &&
(dateTimeProperty2.getSeconds() == 59)
}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml
new file mode 100644
index 0000000000..3f838fe8f2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml
@@ -0,0 +1,16 @@
+import QtQml 2.0
+QtObject {
+ function tryWritingReadOnlySequence() {
+ try {
+ Qt.application.arguments.push("hello")
+ } catch (e) {
+
+ try {
+ Qt.application.arguments.sort()
+ } catch (e) {
+ return true
+ }
+ }
+ return false
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml
new file mode 100644
index 0000000000..8dbd2fd3d9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml
@@ -0,0 +1,34 @@
+import QtQuick 2.6
+
+QtObject {
+ property bool success: false
+ property var num: 100
+ property var simple: 0
+ property var complex: 0
+
+
+ Component.onCompleted: {
+ function s(x) {
+ return x
+ }
+ function c(x) {
+ return x + num
+ }
+
+ var bound = s.bind(undefined, 100)
+ simple = Qt.binding(bound)
+ if (simple != 100)
+ return;
+ var bound = c.bind(undefined, 100)
+ complex = Qt.binding(bound);
+
+ if (complex != 200)
+ return;
+ num = 0;
+ if (complex != 100)
+ return;
+
+ print("success!!!");
+ success = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicString.qml b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml
index 5693794c71..c704161eb5 100644
--- a/tests/auto/qml/qqmlecmascript/data/dynamicString.qml
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml
@@ -11,6 +11,6 @@ MyTypeObject {
date.setHours(5);
date.setMinutes(30);
date.setSeconds(50);
- stringProperty = stringProperty.arg("Hello World").arg(false).arg(true).arg(100).arg(-100).arg(3.1415926).arg(Qt.formatDateTime(date, "yyyy-MM-dd hh::mm:ss"));
+ stringProperty = stringProperty.arg("Hello World").arg(false).arg(true).arg(100).arg(-100).arg(Math.PI).arg(Qt.formatDateTime(date, "yyyy-MM-dd hh::mm:ss"));
}
}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs
new file mode 100644
index 0000000000..19c012d19b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs
@@ -0,0 +1,31 @@
+export function runTest(libraryUnderTest) {
+ let state1 = state(libraryUnderTest);
+ try { modifyFromOutside(libraryUnderTest); } catch (e) {}
+ let state2 = state(libraryUnderTest);
+ try { modifyFromInside(libraryUnderTest); } catch (e) {}
+ let state3 = state(libraryUnderTest);
+ return state1 + " " + state2 + " " + state3;
+}
+
+function stringify(value) {
+ let s = "?";
+ if (value !== undefined)
+ s = value.toString();
+ return s;
+}
+
+function state(libraryUnderTest) {
+ return (stringify(libraryUnderTest.varValue) +
+ stringify(libraryUnderTest.letValue) +
+ stringify(libraryUnderTest.constValue));
+}
+
+function modifyFromOutside(libraryUnderTest) {
+ ++libraryUnderTest.varValue;
+ ++libraryUnderTest.letValue;
+ ++libraryUnderTest.constValue;
+}
+
+function modifyFromInside(libraryUnderTest) {
+ libraryUnderTest.incrementAll();
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs
new file mode 100644
index 0000000000..b6eb1a2623
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs
@@ -0,0 +1,8 @@
+export var varValue = 0;
+export let letValue = 0;
+export const constValue = 0;
+export function incrementAll() {
+ ++varValue;
+ ++letValue;
+ ++constValue;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml
new file mode 100644
index 0000000000..bb4e759cbf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import "importLexicalVariables.mjs" as TestRunner
+import "importLexicalVariables_module.mjs" as LibraryUnderTest
+
+QtObject {
+ id: root
+ function runTest() {
+ return TestRunner.runTest(LibraryUnderTest);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js
new file mode 100644
index 0000000000..f8c215a5e7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js
@@ -0,0 +1,9 @@
+.pragma library
+var varValue = 0;
+let letValue = 0;
+const constValue = 0;
+function incrementAll() {
+ ++varValue;
+ ++letValue;
+ ++constValue;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml
new file mode 100644
index 0000000000..1b3fe7fa2e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import "importLexicalVariables.mjs" as TestRunner
+import "importLexicalVariables_pragmaLibrary.js" as LibraryUnderTest
+
+QtObject {
+ id: root
+ function runTest() {
+ return TestRunner.runTest(LibraryUnderTest);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js
new file mode 100644
index 0000000000..4fb68abc87
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js
@@ -0,0 +1,8 @@
+var varValue = 0;
+let letValue = 0;
+const constValue = 0;
+function incrementAll() {
+ ++varValue;
+ ++letValue;
+ ++constValue;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml
new file mode 100644
index 0000000000..263511e802
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import "importLexicalVariables.mjs" as TestRunner
+import "importLexicalVariables_script.js" as LibraryUnderTest
+
+QtObject {
+ id: root
+ function runTest() {
+ return TestRunner.runTest(LibraryUnderTest);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_callback.js b/tests/auto/qml/qqmlecmascript/data/include_callback.js
index ea19eba300..7f3195bb1f 100644
--- a/tests/auto/qml/qqmlecmascript/data/include_callback.js
+++ b/tests/auto/qml/qqmlecmascript/data/include_callback.js
@@ -1,6 +1,6 @@
function go() {
var a = Qt.include("missing.js", function(o) { test2 = o.status == o.NETWORK_ERROR });
- test1 = a.status == a.NETWORK_ERROR
+ test1 = (a.status == a.NETWORK_ERROR) && (a.statusText.indexOf("Error opening source file") != -1);
var b = Qt.include("blank.js", function(o) { test4 = o.status == o.OK });
test3 = b.status == b.OK
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js
new file mode 100644
index 0000000000..500f04bec7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js
@@ -0,0 +1,7 @@
+.pragma library
+var Shadowed = 2;
+var global = (function(){return this})()
+
+// set Shadowed on the global object as well. This should be different from
+// the variable above, as the library has it's on context
+global.Shadowed = 1;
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml
new file mode 100644
index 0000000000..7cac09d342
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import "include_pragma_shadow.js" as Shadowed
+import "include_pragma_shadow.js" as Other
+
+Item {
+ property bool result
+
+ Component.onCompleted: {
+ result = false;
+ var global = (function(){return this})()
+ if (Shadowed.Shadowed === 2 && Other.Shadowed === 2 && global.Shadowed === 1)
+ result = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/js/include2.js b/tests/auto/qml/qqmlecmascript/data/js/include2.js
index 2a0c039dfa..7cfcdd95e2 100644
--- a/tests/auto/qml/qqmlecmascript/data/js/include2.js
+++ b/tests/auto/qml/qqmlecmascript/data/js/include2.js
@@ -2,3 +2,8 @@ test2 = true
var test2_1 = true
Qt.include("include3.js");
+
+function withTokensAllowedInJSButKeywordsInQML(char)
+{
+ var double;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
index fa6497d99b..66e18ac2a9 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
@@ -7,5 +7,5 @@ function importIncrementedValue() {
i = i + 1;
// because LibraryImport is shared, and used in previous tests,
// the value will be large (already incremented a bunch of times).
- return (i + LibraryImport.importIncrementedValue());
+ return (i + LibraryImport.importIncrementedValue()); // 11 + 5
}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
index 01f08dbdc3..8264b7229d 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
@@ -3,5 +3,5 @@ import "importPragmaLibraryWithPragmaLibraryImports.js" as LibraryImport
QtObject {
id: root
- property int testValue: LibraryImport.importIncrementedValue(); // 10 + 1 + (7 due to previous tests) = 18
+ property int testValue: LibraryImport.importIncrementedValue(); // 16
}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
index ae43e90210..0e314b20ea 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
@@ -1,7 +1,7 @@
import QtQuick 2.0
-import com.nokia.JsModule 1.0
-import com.nokia.JsModule 1.0 as RenamedModule
+import com.qt.JsModule 1.0
+import com.qt.JsModule 1.0 as RenamedModule
import "testJsModuleImport.js" as TestJsModuleImport
QtObject {
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
index 2d21953d2c..7440f610c1 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
@@ -1,4 +1,4 @@
-.import com.nokia.JsModule 1.0 as JsModule
+.import com.qt.JsModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
index e6e41bc6b2..6826f09da2 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
@@ -1,4 +1,4 @@
-.import com.nokia.JsRemoteModule 1.0 as JsModule
+.import com.qt.JsRemoteModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
index 4199bb022d..f49b38df23 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
@@ -1,7 +1,7 @@
import QtQuick 2.0
-import com.nokia.JsModule 1.0
-import com.nokia.JsModule 1.0 as RenamedModule
+import com.qt.JsModule 1.0
+import com.qt.JsModule 1.0 as RenamedModule
import "testJsModuleRemoteImport.js" as TestJsModuleImport
QtObject {
diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js
index b90033eeb4..b90033eeb4 100644
--- a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js
+++ b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js
diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir
index c33d1e7a0d..c33d1e7a0d 100644
--- a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir
+++ b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir
diff --git a/tests/auto/qml/qqmlecmascript/data/nans.qml b/tests/auto/qml/qqmlecmascript/data/nans.qml
new file mode 100644
index 0000000000..ece69f2d79
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nans.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property var prop: undefined
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml b/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml
new file mode 100644
index 0000000000..424b3e8b07
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ objectName: trueProperty ? "foo" : "bar"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qmlVarNullBinding.qml b/tests/auto/qml/qqmlecmascript/data/qmlVarNullBinding.qml
new file mode 100644
index 0000000000..6666b85ffd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qmlVarNullBinding.qml
@@ -0,0 +1,7 @@
+import QtQml 2.2
+
+QtObject {
+ property var foo: null
+ property bool signalSeen: false
+ onFooChanged: signalSeen = true
+}
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/remote/com/nokia/JsRemoteModule/ScriptAPI.js b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/ScriptAPI.js
index b90033eeb4..b90033eeb4 100644
--- a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/ScriptAPI.js
+++ b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/ScriptAPI.js
diff --git a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir
index c33d1e7a0d..c33d1e7a0d 100644
--- a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir
+++ b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir
diff --git a/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml
new file mode 100644
index 0000000000..aacf16474d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+Item {
+ property rect placement: Qt.rect(0, 0, 100, 100)
+
+ function someFunction() { return 42; }
+
+ property rect partialPlacement
+ partialPlacement.x: someFunction()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
index 5103168fd3..99c49ebf62 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
@@ -10,6 +10,11 @@ Item {
objectName: "msco"
}
+ Component {
+ id: mscoComponent
+ MySequenceConversionObject { }
+ }
+
property bool success: false
property variant intList
@@ -252,4 +257,13 @@ Item {
if (testSequence.valueOf() == prevValueOf) referenceDeletion = false;
if (testSequence.length == prevLength) referenceDeletion = false;
}
+
+ function jsonConversion() {
+ success = true
+ var msco = mscoComponent.createObject()
+ if (JSON.stringify(msco.intListProperty) != "[1,2,3,4]") success = false;
+ if (JSON.stringify(msco.qrealListProperty) != "[1.1,2.2,3.3,4.4]") success = false;
+ if (JSON.stringify(msco.boolListProperty) != "[true,false,true,false]") success = false;
+ if (JSON.stringify(msco.stringListProperty) != "[\"first\",\"second\",\"third\",\"fourth\"]") success = false;
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
index cd68fb9b82..14326bb9e6 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
@@ -102,4 +102,17 @@ QtObject {
})
return testSuccess
}
+
+ property QtObject subObject: QtObject {
+ id: subObject
+ property int value
+ property bool ok: false
+ onValueChanged: this.ok = true
+ }
+
+ function testThisInSignalHandler() {
+ subObject.ok = false
+ subObject.value = subObject.value + 1
+ return subObject.ok
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/singletonTest.qml b/tests/auto/qml/qqmlecmascript/data/singletonTest.qml
index ca3784322a..1c8984ce8c 100644
--- a/tests/auto/qml/qqmlecmascript/data/singletonTest.qml
+++ b/tests/auto/qml/qqmlecmascript/data/singletonTest.qml
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2013 Canonical Limited and/or its subsidiary(-ies).
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml b/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml
index ef08745812..85549f4e87 100644
--- a/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml
+++ b/tests/auto/qml/qqmlecmascript/data/singletonTest2.qml
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2013 Canonical Limited and/or its subsidiary(-ies).
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
index 04b39f73d5..7f5a22a459 100644
--- a/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
@@ -8,6 +8,6 @@ MyQmlObject {
return 321
}
- value: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 123 }
+ qjsvalue: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 123 }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
index 231aaf0683..39d4f74e97 100644
--- a/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
@@ -7,6 +7,6 @@ MyQmlObject {
return 321
}
- value: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 321 }
+ qjsvalue: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 321 }
}
diff --git a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro
index 101181bba0..0dd9365366 100644
--- a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro
+++ b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro
@@ -7,7 +7,6 @@ SOURCES += tst_qqmlecmascript.cpp \
../../shared/testhttpserver.cpp
HEADERS += testtypes.h \
../../shared/testhttpserver.h
-INCLUDEPATH += ../../shared
RESOURCES += qqmlecmascript.qrc
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index c4692fdf31..89887fe6c3 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -56,7 +56,7 @@ class AbstractExtensionObject : public QObject
Q_PROPERTY(int abstractProperty READ abstractProperty WRITE setAbstractProperty NOTIFY abstractPropertyChanged)
public:
- AbstractExtensionObject(QObject *parent = 0) : QObject(parent), m_abstractProperty(-1) {}
+ AbstractExtensionObject(QObject *parent = nullptr) : QObject(parent), m_abstractProperty(-1) {}
void setAbstractProperty(int abstractProperty) { m_abstractProperty = abstractProperty; emit abstractPropertyChanged(); }
int abstractProperty() const { return m_abstractProperty; }
@@ -75,7 +75,7 @@ class ImplementedExtensionObject : public AbstractExtensionObject
Q_OBJECT
Q_PROPERTY(int implementedProperty READ implementedProperty WRITE setImplementedProperty NOTIFY implementedPropertyChanged)
public:
- ImplementedExtensionObject(QObject *parent = 0) : AbstractExtensionObject(parent), m_implementedProperty(883) {}
+ ImplementedExtensionObject(QObject *parent = nullptr) : AbstractExtensionObject(parent), m_implementedProperty(883) {}
void shouldBeImplemented() {}
void setImplementedProperty(int implementedProperty) { m_implementedProperty = implementedProperty; emit implementedPropertyChanged(); }
@@ -245,9 +245,16 @@ public:
MyWorkerObject *o;
};
+MyWorkerObject::~MyWorkerObject()
+{
+ if (m_thread)
+ m_thread->wait();
+}
+
void MyWorkerObject::doIt()
{
- new MyWorkerObjectThread(this);
+ Q_ASSERT(!m_thread);
+ m_thread = new MyWorkerObjectThread(this);
}
class MyDateClass : public QObject
@@ -333,7 +340,7 @@ public:
}
};
-static MyInheritedQmlObject *theSingletonObject = 0;
+static MyInheritedQmlObject *theSingletonObject = nullptr;
static QObject *inheritedQmlObject_provider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
{
@@ -375,7 +382,7 @@ private:
static int a = 0;
static int *ptr = &a;
*ptr = 1;
- ptr = 0;
+ ptr = nullptr;
}
};
@@ -394,13 +401,13 @@ static QObject *create_singletonWithEnum(QQmlEngine *, QJSEngine *)
}
QObjectContainer::QObjectContainer()
- : widgetParent(0)
+ : widgetParent(nullptr)
, gcOnAppend(false)
{}
QQmlListProperty<QObject> QObjectContainer::data()
{
- return QQmlListProperty<QObject>(this, 0, children_append, children_count, children_at, children_clear);
+ return QQmlListProperty<QObject>(this, nullptr, children_append, children_count, children_at, children_clear);
}
void QObjectContainer::children_append(QQmlListProperty<QObject> *prop, QObject *o)
@@ -412,7 +419,7 @@ void QObjectContainer::children_append(QQmlListProperty<QObject> *prop, QObject
if (that->gcOnAppend) {
QQmlEngine *engine = qmlEngine(that);
engine->collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
}
@@ -441,7 +448,7 @@ void QObjectContainer::childDestroyed(QObject *child) {
void FloatingQObject::classBegin()
{
- setParent(0);
+ setParent(nullptr);
}
void FloatingQObject::componentComplete()
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index eedeb66647..32120ee5b7 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>
@@ -101,6 +102,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 +172,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 +278,7 @@ private:
int m_value;
int m_resetProperty;
QRegExp m_regExp;
+ QRegularExpression m_regularExpression;
QVariant m_variant;
QJSValue m_qjsvalue;
int m_intProperty;
@@ -1262,7 +1271,6 @@ public:
{
CircularReferenceObject *retn = new CircularReferenceObject(parent);
retn->m_dtorCount = m_dtorCount;
- retn->m_engine = m_engine;
return retn;
}
@@ -1283,14 +1291,8 @@ public:
thisObject->defineDefaultProperty(QStringLiteral("autoTestStrongRef"), v);
}
- void setEngine(QQmlEngine* declarativeEngine)
- {
- m_engine = QQmlEnginePrivate::get(declarativeEngine)->v8engine();
- }
-
private:
int *m_dtorCount;
- QV8Engine* m_engine;
};
Q_DECLARE_METATYPE(CircularReferenceObject*)
@@ -1509,7 +1511,7 @@ public:
}
break;
case Qt::OffsetFromUTC:
- m_offset = m_datetime.utcOffset() / 60;
+ m_offset = m_datetime.offsetFromUtc() / 60;
m_timespec = QString("%1%2:%3").arg(m_offset < 0 ? '-' : '+')
.arg(abs(m_offset) / 60)
.arg(abs(m_offset) % 60);
@@ -1532,12 +1534,17 @@ private:
class MyWorkerObject : public QObject
{
Q_OBJECT
+public:
+ ~MyWorkerObject();
public Q_SLOTS:
void doIt();
Q_SIGNALS:
void done(const QString &result);
+
+private:
+ QThread *m_thread = 0;
};
class MyUnregisteredEnumTypeObject : public QObject
@@ -1665,7 +1672,8 @@ class SingletonWithEnum : public QObject
Q_ENUMS(TestEnum)
public:
enum TestEnum {
- TestValue = 42
+ TestValue = 42,
+ TestValue_MinusOne = -1
};
};
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 45f312e934..b4349f79ca 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -43,11 +43,14 @@
#include "../../shared/util.h"
#include <private/qv4functionobject_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4alloca_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4object_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <private/qv4objectiterator_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
#ifdef Q_CC_MSVC
#define NO_INLINE __declspec(noinline)
@@ -260,6 +263,7 @@ private slots:
void doubleEvaluate();
void forInLoop();
void nonNotifyable();
+ void nonNotifyableConstant();
void deleteWhileBindingRunning();
void callQtInvokables();
void resolveClashingProperties();
@@ -287,6 +291,7 @@ private slots:
void withStatement();
void tryStatement();
void replaceBinding();
+ void bindingBoundFunctions();
void deleteRootObjectInCreation();
void onDestruction();
void onDestructionViaGC();
@@ -342,11 +347,27 @@ private slots:
void freeze_empty_object();
void singleBlockLoops();
void qtbug_60547();
+ void delayLoadingArgs();
+ void manyArguments();
+ void forInIterator();
+ void localForInIterator();
+ void shadowedFunctionName();
+ void anotherNaN();
+ void callPropertyOnUndefined();
+ void jumpStrictNotEqualUndefined();
+ void removeBindingsWithNoDependencies();
+ void temporaryDeadZone();
+ void importLexicalVariables_data();
+ void importLexicalVariables();
+ void hugeObject();
+ void templateStringTerminator();
+ void arrayAndException();
+ void numberToStringWithRadix();
+ void tailCallWithArguments();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
static void verifyContextLifetime(QQmlContextData *ctxt);
- QQmlEngine engine;
// When calling into JavaScript, the specific type of the return value can differ if that return
// value is a number. This is not only the case for non-integral numbers, or numbers that do not
@@ -364,7 +385,7 @@ private:
static void gc(QQmlEngine &engine)
{
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
@@ -373,17 +394,15 @@ void tst_qqmlecmascript::initTestCase()
{
QQmlDataTest::initTestCase();
registerTypes();
-
- QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
- engine.addImportPath(dataDir);
}
void tst_qqmlecmascript::assignBasicTypes()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
QCOMPARE(object->relatedEnumProperty(), MyEnumContainer::RelatedValue);
@@ -412,7 +431,7 @@ void tst_qqmlecmascript::assignBasicTypes()
{
QQmlComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
QCOMPARE(object->relatedEnumProperty(), MyEnumContainer::RelatedValue);
@@ -443,29 +462,38 @@ void tst_qqmlecmascript::assignBasicTypes()
void tst_qqmlecmascript::assignDate_data()
{
QTest::addColumn<QUrl>("source");
+ QTest::addColumn<int>("timeOffset"); // -1 for local-time, else minutes from UTC
- QTest::newRow("Component.onComplete JS Parse") << testFileUrl("assignDate.qml");
- QTest::newRow("Component.onComplete JS") << testFileUrl("assignDate.1.qml");
- QTest::newRow("Binding JS") << testFileUrl("assignDate.2.qml");
- QTest::newRow("Binding UTC") << testFileUrl("assignDate.3.qml");
- QTest::newRow("Binding JS UTC") << testFileUrl("assignDate.4.qml");
- QTest::newRow("Binding UTC+2") << testFileUrl("assignDate.5.qml");
- QTest::newRow("Binding JS UTC+2 ") << testFileUrl("assignDate.6.qml");
+ QTest::newRow("Component.onComplete JS Parse") << testFileUrl("assignDate.qml") << -1;
+ QTest::newRow("Component.onComplete JS") << testFileUrl("assignDate.1.qml") << 0;
+ QTest::newRow("Binding JS") << testFileUrl("assignDate.2.qml") << -1;
+ QTest::newRow("Binding UTC") << testFileUrl("assignDate.3.qml") << 0;
+ QTest::newRow("Binding JS UTC") << testFileUrl("assignDate.4.qml") << 0;
+ QTest::newRow("Binding UTC+2") << testFileUrl("assignDate.5.qml") << 120;
+ QTest::newRow("Binding JS UTC+2 ") << testFileUrl("assignDate.6.qml") << 120;
}
void tst_qqmlecmascript::assignDate()
{
QFETCH(QUrl, source);
+ QFETCH(int, timeOffset);
+ QQmlEngine engine;
QQmlComponent component(&engine, source);
QScopedPointer<QObject> obj(component.create());
MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data());
- QVERIFY(object != 0);
-
- // Dates received from JS are automatically converted to local time
- QDate expectedDate(QDateTime(QDate(2009, 5, 12), QTime(0, 0, 0), Qt::UTC).toLocalTime().date());
- QDateTime expectedDateTime(QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::UTC).toLocalTime());
- QDateTime expectedDateTime2(QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::UTC).toLocalTime());
+ QVERIFY(object != nullptr);
+
+ QDate expectedDate(2009, 5, 12);
+ QDateTime expectedDateTime;
+ QDateTime expectedDateTime2;
+ if (timeOffset == -1) {
+ expectedDateTime = QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::LocalTime);
+ expectedDateTime2 = QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::LocalTime);
+ } else {
+ expectedDateTime = QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::OffsetFromUTC, timeOffset * 60);
+ expectedDateTime2 = QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::OffsetFromUTC, timeOffset * 60);
+ }
QCOMPARE(object->dateProperty(), expectedDate);
QCOMPARE(object->dateTimeProperty(), expectedDateTime);
@@ -492,22 +520,22 @@ void tst_qqmlecmascript::exportDate_data()
QTest::newRow("UTC late") << testFileUrl("exportDate.4.qml") << QDateTime(date, late, Qt::UTC);
{
QDateTime dt(date, early, Qt::OffsetFromUTC);
- dt.setUtcOffset(offset);
+ dt.setOffsetFromUtc(offset);
QTest::newRow("+11:30 early") << testFileUrl("exportDate.5.qml") << dt;
}
{
QDateTime dt(date, late, Qt::OffsetFromUTC);
- dt.setUtcOffset(offset);
+ dt.setOffsetFromUtc(offset);
QTest::newRow("+11:30 late") << testFileUrl("exportDate.6.qml") << dt;
}
{
QDateTime dt(date, early, Qt::OffsetFromUTC);
- dt.setUtcOffset(-offset);
+ dt.setOffsetFromUtc(-offset);
QTest::newRow("-11:30 early") << testFileUrl("exportDate.7.qml") << dt;
}
{
QDateTime dt(date, late, Qt::OffsetFromUTC);
- dt.setUtcOffset(-offset);
+ dt.setOffsetFromUtc(-offset);
QTest::newRow("-11:30 late") << testFileUrl("exportDate.8.qml") << dt;
}
}
@@ -525,17 +553,18 @@ void tst_qqmlecmascript::exportDate()
QQmlComponent component(&e, source);
QScopedPointer<QObject> obj(component.create());
MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->boolProperty(), true);
}
void tst_qqmlecmascript::idShortcutInvalidates()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->objectProperty() != 0);
+ QVERIFY(object != nullptr);
+ QVERIFY(object->objectProperty() != nullptr);
delete object->objectProperty();
QVERIFY(!object->objectProperty());
delete object;
@@ -544,8 +573,8 @@ void tst_qqmlecmascript::idShortcutInvalidates()
{
QQmlComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->objectProperty() != 0);
+ QVERIFY(object != nullptr);
+ QVERIFY(object->objectProperty() != nullptr);
delete object->objectProperty();
QVERIFY(!object->objectProperty());
delete object;
@@ -554,17 +583,18 @@ void tst_qqmlecmascript::idShortcutInvalidates()
void tst_qqmlecmascript::boolPropertiesEvaluateAsBool()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
delete object;
}
{
QQmlComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
delete object;
}
@@ -572,10 +602,11 @@ void tst_qqmlecmascript::boolPropertiesEvaluateAsBool()
void tst_qqmlecmascript::signalAssignment()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->string(), QString());
emit object->basicSignal();
QCOMPARE(object->string(), QString("pass"));
@@ -585,7 +616,7 @@ void tst_qqmlecmascript::signalAssignment()
{
QQmlComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->string(), QString());
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
@@ -609,10 +640,11 @@ void tst_qqmlecmascript::signalAssignment()
void tst_qqmlecmascript::signalArguments()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("signalArguments.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->string(), QString());
emit object->basicSignal();
QCOMPARE(object->string(), QString("pass"));
@@ -623,7 +655,7 @@ void tst_qqmlecmascript::signalArguments()
{
QQmlComponent component(&engine, testFileUrl("signalArguments.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->string(), QString());
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
@@ -634,10 +666,11 @@ void tst_qqmlecmascript::signalArguments()
void tst_qqmlecmascript::methods()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("methods.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->methodCalled(), false);
QCOMPARE(object->methodIntCalled(), false);
emit object->basicSignal();
@@ -649,7 +682,7 @@ void tst_qqmlecmascript::methods()
{
QQmlComponent component(&engine, testFileUrl("methods.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->methodCalled(), false);
QCOMPARE(object->methodIntCalled(), false);
emit object->basicSignal();
@@ -661,7 +694,7 @@ void tst_qqmlecmascript::methods()
{
QQmlComponent component(&engine, testFileUrl("methods.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 19);
delete object;
}
@@ -669,7 +702,7 @@ void tst_qqmlecmascript::methods()
{
QQmlComponent component(&engine, testFileUrl("methods.4.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 19);
QCOMPARE(object->property("test2").toInt(), 17);
QCOMPARE(object->property("test3").toInt(), 16);
@@ -679,7 +712,7 @@ void tst_qqmlecmascript::methods()
{
QQmlComponent component(&engine, testFileUrl("methods.5.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 9);
delete object;
}
@@ -687,11 +720,12 @@ void tst_qqmlecmascript::methods()
void tst_qqmlecmascript::bindingLoop()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("bindingLoop.qml"));
QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -728,6 +762,8 @@ void tst_qqmlecmascript::basicExpressions()
QFETCH(QVariant, result);
QFETCH(bool, nest);
+ QQmlEngine engine;
+
MyQmlObject object1;
MyQmlObject object2;
MyQmlObject object3;
@@ -760,6 +796,7 @@ void tst_qqmlecmascript::arrayExpressions()
QObject obj2;
QObject obj3;
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
context.setContextProperty("a", &obj1);
context.setContextProperty("b", &obj2);
@@ -779,6 +816,7 @@ void tst_qqmlecmascript::arrayExpressions()
// Tests that modifying a context property will reevaluate expressions
void tst_qqmlecmascript::contextPropertiesTriggerReeval()
{
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
MyQmlObject object1;
MyQmlObject object2;
@@ -842,6 +880,7 @@ void tst_qqmlecmascript::contextPropertiesTriggerReeval()
void tst_qqmlecmascript::objectPropertiesTriggerReeval()
{
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
MyQmlObject object1;
MyQmlObject object2;
@@ -877,7 +916,7 @@ void tst_qqmlecmascript::objectPropertiesTriggerReeval()
expr.changed = false;
QCOMPARE(expr.evaluate(), QVariant("Cat"));
- object1.setObjectProperty(0);
+ object1.setObjectProperty(nullptr);
QCOMPARE(expr.changed, true);
expr.changed = false;
QCOMPARE(expr.evaluate(), QVariant());
@@ -908,19 +947,20 @@ void tst_qqmlecmascript::dependenciesWithFunctions()
void tst_qqmlecmascript::deferredProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->value(), 0);
QVERIFY(!object->objectProperty());
- QVERIFY(object->objectProperty2() != 0);
+ QVERIFY(object->objectProperty2() != nullptr);
qmlExecuteDeferred(object);
QCOMPARE(object->value(), 10);
- QVERIFY(object->objectProperty() != 0);
+ QVERIFY(object->objectProperty() != nullptr);
MyQmlObject *qmlObject =
qobject_cast<MyQmlObject *>(object->objectProperty());
- QVERIFY(qmlObject != 0);
+ QVERIFY(qmlObject != nullptr);
QCOMPARE(qmlObject->value(), 10);
object->setValue(19);
QCOMPARE(qmlObject->value(), 19);
@@ -931,15 +971,16 @@ void tst_qqmlecmascript::deferredProperties()
// Check errors on deferred properties are correctly emitted
void tst_qqmlecmascript::deferredPropertiesErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->value(), 0);
QVERIFY(!object->objectProperty());
QVERIFY(!object->objectProperty2());
- QString warning = component.url().toString() + ":6:21: Unable to assign [undefined] to QObject*";
+ QString warning = component.url().toString() + ":6:5: Unable to assign [undefined] to QObject*";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
qmlExecuteDeferred(object);
@@ -950,29 +991,30 @@ void tst_qqmlecmascript::deferredPropertiesErrors()
void tst_qqmlecmascript::deferredPropertiesInComponents()
{
// Test that it works when the property is set inside and outside component
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesInComponents.qml"));
QObject *object = component.create();
if (!object)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").value<int>(), 10);
MyDeferredObject *defObjectA =
qobject_cast<MyDeferredObject *>(object->property("deferredInside").value<QObject*>());
- QVERIFY(defObjectA != 0);
+ QVERIFY(defObjectA != nullptr);
QVERIFY(!defObjectA->objectProperty());
qmlExecuteDeferred(defObjectA);
- QVERIFY(defObjectA->objectProperty() != 0);
+ QVERIFY(defObjectA->objectProperty() != nullptr);
QCOMPARE(defObjectA->objectProperty()->property("value").value<int>(), 10);
MyDeferredObject *defObjectB =
qobject_cast<MyDeferredObject *>(object->property("deferredOutside").value<QObject*>());
- QVERIFY(defObjectB != 0);
+ QVERIFY(defObjectB != nullptr);
QVERIFY(!defObjectB->objectProperty());
qmlExecuteDeferred(defObjectB);
- QVERIFY(defObjectB->objectProperty() != 0);
+ QVERIFY(defObjectB->objectProperty() != nullptr);
QCOMPARE(defObjectB->objectProperty()->property("value").value<int>(), 10);
delete object;
@@ -983,20 +1025,22 @@ void tst_qqmlecmascript::deferredPropertiesInDestruction()
//Test that the component does not get created at all if creation is deferred until the containing context is destroyed
//Very specific operation ordering is needed for this to occur, currently accessing object from object destructor.
//
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesInDestruction.qml"));
QObject *object = component.create();
if (!object)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object; //QTBUG-33112 was that this used to cause a crash
}
void tst_qqmlecmascript::extensionObjects()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extensionObjects.qml"));
MyExtendedObject *object =
qobject_cast<MyExtendedObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->baseProperty(), 13);
QCOMPARE(object->coreProperty(), 9);
object->setProperty("extendedProperty", QVariant(11));
@@ -1018,11 +1062,12 @@ void tst_qqmlecmascript::extensionObjects()
void tst_qqmlecmascript::overrideExtensionProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
OverrideDefaultPropertyObject *object =
qobject_cast<OverrideDefaultPropertyObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->secondProperty() != 0);
+ QVERIFY(object != nullptr);
+ QVERIFY(object->secondProperty() != nullptr);
QVERIFY(!object->firstProperty());
delete object;
@@ -1030,10 +1075,12 @@ void tst_qqmlecmascript::overrideExtensionProperties()
void tst_qqmlecmascript::attachedProperties()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("attachedProperty.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 19);
QCOMPARE(object->property("b").toInt(), 19);
QCOMPARE(object->property("c").toInt(), 19);
@@ -1044,7 +1091,7 @@ void tst_qqmlecmascript::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 26);
QCOMPARE(object->property("b").toInt(), 26);
QCOMPARE(object->property("c").toInt(), 26);
@@ -1056,13 +1103,13 @@ void tst_qqmlecmascript::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "writeValue2");
MyQmlAttachedObject *attached =
qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
- QVERIFY(attached != 0);
+ QVERIFY(attached != nullptr);
QCOMPARE(attached->value2(), 9);
delete object;
@@ -1071,11 +1118,13 @@ void tst_qqmlecmascript::attachedProperties()
void tst_qqmlecmascript::enums()
{
+ QQmlEngine engine;
+
// Existent enums
{
QQmlComponent component(&engine, testFileUrl("enums.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("enumProperty").toInt(), (int)MyQmlObject::EnumValue2);
QCOMPARE(object->property("relatedEnumProperty").toInt(), (int)MyEnumContainer::RelatedValue);
@@ -1100,13 +1149,13 @@ void tst_qqmlecmascript::enums()
{
QUrl file = testFileUrl("enums.2.qml");
QString w1 = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'MyEnum' for property 'MyUnregisteredEnumTypeObject::enumProperty'");
- QString w2 = QLatin1String("QQmlExpression: Expression ") + testFileUrl("enums.2.qml").toString() + QLatin1String(":9:21 depends on non-NOTIFYable properties:");
+ QString w2 = QLatin1String("QQmlExpression: Expression ") + testFileUrl("enums.2.qml").toString() + QLatin1String(":9:5 depends on non-NOTIFYable properties:");
QString w3 = QLatin1String(" MyUnregisteredEnumTypeObject::enumProperty");
- QString w4 = file.toString() + ":7:21: Unable to assign [undefined] to int";
- QString w5 = file.toString() + ":8:21: Unable to assign [undefined] to int";
- QString w6 = file.toString() + ":9:21: Unable to assign [undefined] to int";
- QString w7 = file.toString() + ":13:23: Unable to assign [undefined] to [unknown property type]";
- QString w8 = file.toString() + ":31:23: Unable to assign int to [unknown property type]";
+ QString w4 = file.toString() + ":7:5: Unable to assign [undefined] to int";
+ QString w5 = file.toString() + ":8:5: Unable to assign [undefined] to int";
+ QString w6 = file.toString() + ":9:5: Unable to assign [undefined] to int";
+ QString w7 = file.toString() + ":13:9: Unable to assign [undefined] to [unknown property type]";
+ QString w8 = file.toString() + ":31:9: Unable to assign int to [unknown property type]";
QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
@@ -1118,7 +1167,7 @@ void tst_qqmlecmascript::enums()
QQmlComponent component(&engine, testFileUrl("enums.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 0);
QCOMPARE(object->property("b").toInt(), 0);
QCOMPARE(object->property("c").toInt(), 0);
@@ -1145,7 +1194,7 @@ void tst_qqmlecmascript::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// check the values are what we expect
QCOMPARE(object->property("a").toInt(), 4);
@@ -1177,9 +1226,10 @@ void tst_qqmlecmascript::enums()
void tst_qqmlecmascript::valueTypeFunctions()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
@@ -1192,11 +1242,13 @@ binding.
*/
void tst_qqmlecmascript::constantsOverrideBindings()
{
+ QQmlEngine engine;
+
// From ECMAScript
{
QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("c2").toInt(), 0);
object->setProperty("c1", QVariant(9));
@@ -1215,7 +1267,7 @@ void tst_qqmlecmascript::constantsOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("c1").toInt(), 0);
QCOMPARE(object->property("c2").toInt(), 10);
@@ -1251,7 +1303,7 @@ void tst_qqmlecmascript::constantsOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("c1").toInt(), 0);
QCOMPARE(object->property("c3").toInt(), 10);
@@ -1269,10 +1321,11 @@ the original binding to be disabled.
*/
void tst_qqmlecmascript::outerBindingOverridesInnerBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine,
testFileUrl("outerBindingOverridesInnerBinding.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("c1").toInt(), 0);
QCOMPARE(object->property("c2").toInt(), 0);
@@ -1298,23 +1351,26 @@ Tests for a regression where this used to crash.
*/
void tst_qqmlecmascript::nonExistentAttachedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
- QString warning = component.url().toString() + ":4:21: Unable to assign [undefined] to QString";
+ QString warning = component.url().toString() + ":4:5: Unable to assign [undefined] to QString";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::scope()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scope.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toInt(), 1);
QCOMPARE(object->property("test2").toInt(), 2);
@@ -1333,7 +1389,7 @@ void tst_qqmlecmascript::scope()
{
QQmlComponent component(&engine, testFileUrl("scope.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toInt(), 19);
QCOMPARE(object->property("test2").toInt(), 19);
@@ -1348,7 +1404,7 @@ void tst_qqmlecmascript::scope()
{
QQmlComponent component(&engine, testFileUrl("scope.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QEXPECT_FAIL("", "Properties resolvable at compile time come before the global object, which is not 100% compatible with older QML versions", Continue);
@@ -1362,7 +1418,7 @@ void tst_qqmlecmascript::scope()
{
QQmlComponent component(&engine, testFileUrl("scope.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
QCOMPARE(object->property("test2").toString(), QString());
@@ -1378,7 +1434,7 @@ void tst_qqmlecmascript::scope()
{
QQmlComponent component(&engine, testFileUrl("scope.5.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -1389,7 +1445,7 @@ void tst_qqmlecmascript::scope()
{
QQmlComponent component(&engine, testFileUrl("scope.6.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1401,9 +1457,10 @@ void tst_qqmlecmascript::scope()
// importing context
void tst_qqmlecmascript::importScope()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("importScope.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 240);
@@ -1416,9 +1473,10 @@ is essentially a test of QQmlMetaType::copy()
*/
void tst_qqmlecmascript::signalParameterTypes()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
emit object->basicSignal();
@@ -1443,9 +1501,10 @@ Test that two JS objects for the same QObject compare as equal.
*/
void tst_qqmlecmascript::objectsCompareAsEqual()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -1463,9 +1522,10 @@ Tests for a regression where the binding would not reevaluate.
*/
void tst_qqmlecmascript::aliasPropertyAndBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("c2").toInt(), 3);
QCOMPARE(object->property("c3").toInt(), 3);
@@ -1484,12 +1544,13 @@ and that the aliased property is reset correctly if possible.
*/
void tst_qqmlecmascript::aliasPropertyReset()
{
- QObject *object = 0;
+ QQmlEngine engine;
+ QObject *object = nullptr;
// test that a manual write (of undefined) to a resettable aliased property succeeds
QQmlComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
object = c1.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
QMetaObject::invokeMethod(object, "resetAliased");
@@ -1500,7 +1561,7 @@ void tst_qqmlecmascript::aliasPropertyReset()
// test that a manual write (of undefined) to a resettable alias property succeeds
QQmlComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
object = c2.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
QMetaObject::invokeMethod(object, "resetAlias");
@@ -1511,7 +1572,7 @@ void tst_qqmlecmascript::aliasPropertyReset()
// test that an alias to a bound property works correctly
QQmlComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
object = c3.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
@@ -1525,10 +1586,10 @@ void tst_qqmlecmascript::aliasPropertyReset()
// whose aliased property's object has been deleted, does not crash.
QQmlComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
object = c4.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
QObject *loader = object->findChild<QObject*>("loader");
- QVERIFY(loader != 0);
+ QVERIFY(loader != nullptr);
delete loader;
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0); // deletion should have caused value unset.
QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
@@ -1540,16 +1601,16 @@ void tst_qqmlecmascript::aliasPropertyReset()
// test that binding an alias property to an undefined value works correctly
QQmlComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
object = c5.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0); // bound to undefined value.
delete object;
// test that a manual write (of undefined) to a non-resettable property fails properly
QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
- QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
+ QString warning1 = url.toString() + QLatin1String(": Error: Cannot assign [undefined] to int");
QQmlComponent e1(&engine, url);
object = e1.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("intAlias").value<int>(), 12);
QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
@@ -1612,6 +1673,7 @@ void tst_qqmlecmascript::componentCreation()
QFETCH(QString, creationError);
QFETCH(QString, createdParent);
+ QQmlEngine engine;
QUrl testUrl(testFileUrl("componentCreation.qml"));
if (!creationError.isEmpty()) {
@@ -1621,7 +1683,7 @@ void tst_qqmlecmascript::componentCreation()
QQmlComponent component(&engine, testUrl);
MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, method.toUtf8());
QQmlComponent *created = object->componentProperty();
@@ -1633,7 +1695,7 @@ void tst_qqmlecmascript::componentCreation()
if (createdParent == QLatin1String("obj")) {
expectedParent = object;
} else if ((createdParent == QLatin1String("null")) || createdParent.isEmpty()) {
- expectedParent = 0;
+ expectedParent = nullptr;
}
QCOMPARE(created->parent(), expectedParent);
}
@@ -1658,9 +1720,10 @@ void tst_qqmlecmascript::dynamicCreation()
QFETCH(QString, method);
QFETCH(QString, createdName);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, method.toUtf8());
QObject *created = object->objectProperty();
@@ -1675,11 +1738,13 @@ void tst_qqmlecmascript::dynamicCreation()
*/
void tst_qqmlecmascript::dynamicDestruction()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
QPointer<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- QPointer<QObject> createdQmlObject = 0;
+ QVERIFY(object != nullptr);
+ QPointer<QObject> createdQmlObject = nullptr;
QMetaObject::invokeMethod(object, "create");
createdQmlObject = object->objectProperty();
@@ -1689,13 +1754,13 @@ void tst_qqmlecmascript::dynamicDestruction()
QMetaObject::invokeMethod(object, "killOther");
QVERIFY(createdQmlObject);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(createdQmlObject);
for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
if (createdQmlObject) {
QTest::qWait(100);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
}
@@ -1704,7 +1769,7 @@ void tst_qqmlecmascript::dynamicDestruction()
QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
QMetaObject::invokeMethod(object, "killMe");
QVERIFY(object);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(!object);
}
@@ -1712,7 +1777,7 @@ void tst_qqmlecmascript::dynamicDestruction()
{
QQmlComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!qvariant_cast<QObject*>(o->property("objectProperty")));
@@ -1722,7 +1787,7 @@ void tst_qqmlecmascript::dynamicDestruction()
QMetaObject::invokeMethod(o, "destroy");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(!qvariant_cast<QObject*>(o->property("objectProperty")));
@@ -1732,10 +1797,10 @@ void tst_qqmlecmascript::dynamicDestruction()
{
// QTBUG-23451
- QPointer<QObject> createdQmlObject = 0;
+ QPointer<QObject> createdQmlObject = nullptr;
QQmlComponent component(&engine, testFileUrl("dynamicDeletion.3.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!qvariant_cast<QObject*>(o->property("objectProperty")));
QMetaObject::invokeMethod(o, "create");
createdQmlObject = qvariant_cast<QObject*>(o->property("objectProperty"));
@@ -1744,7 +1809,7 @@ void tst_qqmlecmascript::dynamicDestruction()
QCOMPARE(qvariant_cast<bool>(o->property("test")), false);
for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
QTest::qWait(100);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
QVERIFY(!qvariant_cast<QObject*>(o->property("objectProperty")));
@@ -1758,9 +1823,10 @@ void tst_qqmlecmascript::dynamicDestruction()
*/
void tst_qqmlecmascript::objectToString()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qmlToString.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "testToString");
QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
@@ -1778,9 +1844,10 @@ void tst_qqmlecmascript::objectHasOwnProperty()
QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
+ QQmlEngine engine;
QQmlComponent component(&engine, url);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// test QObjects in QML
QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
@@ -1790,7 +1857,7 @@ void tst_qqmlecmascript::objectHasOwnProperty()
// now test other types in QML
QObject *child = object->findChild<QObject*>("typeObj");
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
@@ -1824,10 +1891,12 @@ This test is best run under valgrind to ensure no invalid memory access occur.
*/
void tst_qqmlecmascript::selfDeletingBinding()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->setProperty("triggerDelete", true);
delete object;
}
@@ -1835,7 +1904,7 @@ void tst_qqmlecmascript::selfDeletingBinding()
{
QQmlComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->setProperty("triggerDelete", true);
delete object;
}
@@ -1850,9 +1919,10 @@ and no synthesiszed properties).
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -1861,9 +1931,10 @@ Test that extended object properties can be accessed correctly.
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant returnValue;
QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
@@ -1877,6 +1948,7 @@ Test failure when trying to create and uncreatable extended type object.
*/
void tst_qqmlecmascript::uncreatableExtendedObjectFailureCheck()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("uncreatableExtendedObjectFailureCheck.qml"));
QObject *object = component.create();
@@ -1888,10 +1960,11 @@ Test that an subclass of an uncreatable extended object contains all the require
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup3()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant returnValue;
QVERIFY(QMetaObject::invokeMethod(object, "getAbstractProperty", Q_RETURN_ARG(QVariant, returnValue)));
@@ -1908,6 +1981,7 @@ Test file/lineNumbers for binding/Script errors.
*/
void tst_qqmlecmascript::scriptErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("scriptErrors.qml"));
QString url = component.url().toString();
@@ -1916,7 +1990,7 @@ void tst_qqmlecmascript::scriptErrors()
QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
QString warning4 = url + ":13: ReferenceError: a is not defined";
QString warning5 = url + ":11: ReferenceError: a is not defined";
- QString warning6 = url + ":10:21: Unable to assign [undefined] to int";
+ QString warning6 = url + ":10:5: Unable to assign [undefined] to int";
QString warning7 = url + ":15: TypeError: Cannot assign to read-only property \"trueProperty\"";
QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
@@ -1926,7 +2000,7 @@ void tst_qqmlecmascript::scriptErrors()
QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
emit object->basicSignal();
@@ -1945,6 +2019,7 @@ Test file/lineNumbers for inline functions.
*/
void tst_qqmlecmascript::functionErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionErrors.qml"));
QString url = component.url().toString();
@@ -1953,14 +2028,14 @@ void tst_qqmlecmascript::functionErrors()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
// test that if an exception occurs while invoking js function from cpp, it is reported as expected.
QQmlComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
url = componentTwo.url().toString();
object = componentTwo.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QObject *resource = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ScarceResourceObject(0x%1) is not a function");
@@ -1975,12 +2050,13 @@ Test various errors that can occur when assigning a property from script
*/
void tst_qqmlecmascript::propertyAssignmentErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
QString url = component.url().toString();
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -1994,9 +2070,10 @@ a signal script.
*/
void tst_qqmlecmascript::signalTriggeredBindings()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("base").toReal(), 50.);
QCOMPARE(object->property("test1").toReal(), 50.);
@@ -2022,9 +2099,10 @@ Test that list properties can be iterated from ECMAScript
*/
void tst_qqmlecmascript::listProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listProperties.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toInt(), 21);
QCOMPARE(object->property("test2").toInt(), 2);
@@ -2036,6 +2114,7 @@ void tst_qqmlecmascript::listProperties()
void tst_qqmlecmascript::exceptionClearsOnReeval()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
QString url = component.url().toString();
@@ -2043,7 +2122,7 @@ void tst_qqmlecmascript::exceptionClearsOnReeval()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
@@ -2059,6 +2138,7 @@ void tst_qqmlecmascript::exceptionClearsOnReeval()
void tst_qqmlecmascript::exceptionSlotProducesWarning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
QString url = component.url().toString();
@@ -2066,12 +2146,13 @@ void tst_qqmlecmascript::exceptionSlotProducesWarning()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::exceptionBindingProducesWarning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
QString url = component.url().toString();
@@ -2079,29 +2160,32 @@ void tst_qqmlecmascript::exceptionBindingProducesWarning()
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::compileInvalidBinding()
{
// QTBUG-23387: ensure that invalid bindings don't cause a crash.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("v8bindingException.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
// Check that transient binding errors are not displayed
void tst_qqmlecmascript::transientErrors()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("transientErrors.qml"));
QQmlTestMessageHandler messageHandler;
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
@@ -2115,7 +2199,7 @@ void tst_qqmlecmascript::transientErrors()
QQmlTestMessageHandler messageHandler;
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
@@ -2126,9 +2210,10 @@ void tst_qqmlecmascript::transientErrors()
// Check that errors during shutdown are minimized
void tst_qqmlecmascript::shutdownErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("shutdownErrors.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlTestMessageHandler messageHandler;
@@ -2139,6 +2224,7 @@ void tst_qqmlecmascript::shutdownErrors()
void tst_qqmlecmascript::compositePropertyType()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compositePropertyType.qml"));
QTest::ignoreMessage(QtDebugMsg, "hello world");
@@ -2149,9 +2235,10 @@ void tst_qqmlecmascript::compositePropertyType()
// QTBUG-5759
void tst_qqmlecmascript::jsObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("jsObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 92);
@@ -2160,10 +2247,12 @@ void tst_qqmlecmascript::jsObject()
void tst_qqmlecmascript::undefinedResetsProperty()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("resettableProperty").toInt(), 92);
@@ -2180,7 +2269,7 @@ void tst_qqmlecmascript::undefinedResetsProperty()
{
QQmlComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("resettableProperty").toInt(), 19);
@@ -2195,9 +2284,10 @@ void tst_qqmlecmascript::undefinedResetsProperty()
// Aliases to variant properties should work
void tst_qqmlecmascript::qtbug_22464()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_22464.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -2206,10 +2296,11 @@ void tst_qqmlecmascript::qtbug_22464()
void tst_qqmlecmascript::qtbug_21580()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_21580.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -2219,19 +2310,21 @@ void tst_qqmlecmascript::qtbug_21580()
// Causes a v8 binding, but not all v8 bindings to be destroyed during evaluation
void tst_qqmlecmascript::singleV8BindingDestroyedDuringEvaluation()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singleV8BindingDestroyedDuringEvaluation.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
// QTBUG-6781
void tst_qqmlecmascript::bug1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("bug.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 14);
@@ -2249,11 +2342,12 @@ void tst_qqmlecmascript::bug1()
#ifndef QT_NO_WIDGETS
void tst_qqmlecmascript::bug2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -2262,9 +2356,10 @@ void tst_qqmlecmascript::bug2()
// Don't crash in createObject when the component has errors.
void tst_qqmlecmascript::dynamicCreationCrash()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
QMetaObject::invokeMethod(object, "dontCrash");
@@ -2285,9 +2380,9 @@ void tst_qqmlecmascript::dynamicCreationOwnership()
QQmlEngine dcoEngine;
QQmlComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
- QVERIFY(mdcdo != 0);
+ QVERIFY(mdcdo != nullptr);
mdcdo->setDtorCount(&dtorCount);
for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
@@ -2298,29 +2393,38 @@ void tst_qqmlecmascript::dynamicCreationOwnership()
QMetaObject::invokeMethod(object, "performGc");
}
if (i % 10 == 0) {
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
}
delete object;
}
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QCOMPARE(dtorCount, expectedDtorCount);
}
void tst_qqmlecmascript::regExpBug()
{
+ QQmlEngine engine;
+
//QTBUG-9367
{
QQmlComponent component(&engine, testFileUrl("regExp.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
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());
@@ -2330,15 +2434,27 @@ 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(QV8Engine *engine, const QV4::Value &o, const char *source)
+static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source)
{
QString functionSource = QLatin1String("(function(object) { return ") +
QLatin1String(source) + QLatin1String(" })");
- QV4::Scope scope(QV8Engine::getV4(engine));
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource);
+ QV4::Scope scope(v4);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -2346,10 +2462,10 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const
scope.engine->catchException();
return true;
}
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- function->call(scope, d);
+ QV4::JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = o;
+ *jsCallData->thisObject = v4->global();
+ function->call(jsCallData);
if (scope.engine->hasException) {
scope.engine->catchException();
return true;
@@ -2357,14 +2473,14 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const
return false;
}
-static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o,
+static inline bool evaluate_value(QV4::ExecutionEngine *v4, const QV4::Value &o,
const char *source, const QV4::Value &result)
{
QString functionSource = QLatin1String("(function(object) { return ") +
QLatin1String(source) + QLatin1String(" })");
- QV4::Scope scope(QV8Engine::getV4(engine));
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource);
+ QV4::Scope scope(v4);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -2375,26 +2491,27 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o,
if (!function)
return false;
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- function->call(scope, d);
+ QV4::ScopedValue value(scope);
+ QV4::JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = o;
+ *jsCallData->thisObject = v4->global();
+ value = function->call(jsCallData);
if (scope.engine->hasException) {
scope.engine->catchException();
return false;
}
- return QV4::Runtime::method_strictEqual(scope.result, result);
+ return QV4::Runtime::StrictEqual::call(value, result);
}
-static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o,
- const char *source)
+static inline QV4::ReturnedValue evaluate(QV4::ExecutionEngine *v4, const QV4::Value &o,
+ const char *source)
{
QString functionSource = QLatin1String("(function(object) { return ") +
QLatin1String(source) + QLatin1String(" })");
- QV4::Scope scope(QV8Engine::getV4(engine));
+ QV4::Scope scope(v4);
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -2404,15 +2521,15 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o
}
if (!function)
return QV4::Encode::undefined();
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- function->call(scope, d);
+ QV4::JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = o;
+ *jsCallData->thisObject = v4->global();
+ QV4::ScopedValue result(scope, function->call(jsCallData));
if (scope.engine->hasException) {
scope.engine->catchException();
return QV4::Encode::undefined();
}
- return scope.result.asReturnedValue();
+ return result->asReturnedValue();
}
#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
@@ -2426,12 +2543,11 @@ void tst_qqmlecmascript::callQtInvokables()
MyInvokableObject *o = new MyInvokableObject();
QQmlEngine qmlengine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&qmlengine);
- QV8Engine *engine = ep->v8engine();
- QV4::Scope scope(QV8Engine::getV4(engine));
+ QV4::ExecutionEngine *engine = qmlengine.handle();
+ QV4::Scope scope(engine);
- QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), o));
+ QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o));
// Non-existent methods
o->reset();
@@ -2714,28 +2830,28 @@ void tst_qqmlecmascript::callQtInvokables()
QCOMPARE(o->error(), false);
QCOMPARE(o->invoked(), 13);
QCOMPARE(o->actuals().count(), 1);
- QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)0));
+ QCOMPARE(o->actuals().at(0), qVariantFromValue((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 *)0));
+ QCOMPARE(o->actuals().at(0), qVariantFromValue((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 *)0));
+ QCOMPARE(o->actuals().at(0), qVariantFromValue((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 *)0));
+ QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr));
o->reset();
QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", QV4::Primitive::undefinedValue()));
@@ -2999,9 +3115,8 @@ void tst_qqmlecmascript::resolveClashingProperties()
{
ClashingNames *o = new ClashingNames();
QQmlEngine qmlengine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&qmlengine);
- QV4::ExecutionEngine *engine = QV8Engine::getV4(ep->v8engine());
+ QV4::ExecutionEngine *engine = qmlengine.handle();
QV4::Scope scope(engine);
QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o));
@@ -3019,7 +3134,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);
@@ -3040,6 +3155,7 @@ void tst_qqmlecmascript::resolveClashingProperties()
// QTBUG-13047 (check that you can pass registered object types as args)
void tst_qqmlecmascript::invokableObjectArg()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
QObject *o = component.create();
@@ -3054,6 +3170,7 @@ void tst_qqmlecmascript::invokableObjectArg()
// QTBUG-13047 (check that you can return registered object types from methods)
void tst_qqmlecmascript::invokableObjectRet()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
QObject *o = component.create();
@@ -3064,6 +3181,7 @@ void tst_qqmlecmascript::invokableObjectRet()
void tst_qqmlecmascript::invokableEnumRet()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableEnumRet.qml"));
QObject *o = component.create();
@@ -3075,6 +3193,7 @@ void tst_qqmlecmascript::invokableEnumRet()
// QTBUG-5675
void tst_qqmlecmascript::listToVariant()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listToVariant.qml"));
MyQmlContainer container;
@@ -3083,7 +3202,7 @@ void tst_qqmlecmascript::listToVariant()
context.setContextObject(&container);
QObject *object = component.create(&context);
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant v = object->property("test");
QCOMPARE(v.userType(), qMetaTypeId<QQmlListReference>());
@@ -3095,6 +3214,7 @@ void tst_qqmlecmascript::listToVariant()
// QTBUG-16316
void tst_qqmlecmascript::listAssignment()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listAssignment.qml"));
QObject *obj = component.create();
QCOMPARE(obj->property("list1length").toInt(), 2);
@@ -3133,6 +3253,7 @@ void tst_qqmlecmascript::multiEngineObject()
// Test that references to QObjects are cleanup when the object is destroyed
void tst_qqmlecmascript::deletedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deletedObject.qml"));
QObject *object = component.create();
@@ -3147,14 +3268,15 @@ void tst_qqmlecmascript::deletedObject()
void tst_qqmlecmascript::attachedPropertyScope()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MyQmlAttachedObject *attached =
qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
- QVERIFY(attached != 0);
+ QVERIFY(attached != nullptr);
QCOMPARE(object->property("value2").toInt(), 0);
@@ -3167,11 +3289,13 @@ void tst_qqmlecmascript::attachedPropertyScope()
void tst_qqmlecmascript::scriptConnect()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3184,7 +3308,7 @@ void tst_qqmlecmascript::scriptConnect()
QQmlComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3197,7 +3321,7 @@ void tst_qqmlecmascript::scriptConnect()
QQmlComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3210,7 +3334,7 @@ void tst_qqmlecmascript::scriptConnect()
QQmlComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->methodCalled(), false);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3223,7 +3347,7 @@ void tst_qqmlecmascript::scriptConnect()
QQmlComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->methodCalled(), false);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3236,7 +3360,7 @@ void tst_qqmlecmascript::scriptConnect()
QQmlComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3248,11 +3372,13 @@ void tst_qqmlecmascript::scriptConnect()
void tst_qqmlecmascript::scriptDisconnect()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3271,7 +3397,7 @@ void tst_qqmlecmascript::scriptDisconnect()
QQmlComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3290,7 +3416,7 @@ void tst_qqmlecmascript::scriptDisconnect()
QQmlComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3308,7 +3434,7 @@ void tst_qqmlecmascript::scriptDisconnect()
QQmlComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 0);
emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
@@ -3338,6 +3464,7 @@ public slots:
void tst_qqmlecmascript::ownership()
{
+ QQmlEngine engine;
OwnershipObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3345,13 +3472,13 @@ void tst_qqmlecmascript::ownership()
{
QQmlComponent component(&engine, testFileUrl("ownership.qml"));
- QVERIFY(own.object != 0);
+ QVERIFY(own.object != nullptr);
QObject *object = component.create(context);
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(own.object.isNull());
@@ -3364,16 +3491,16 @@ void tst_qqmlecmascript::ownership()
{
QQmlComponent component(&engine, testFileUrl("ownership.qml"));
- QVERIFY(own.object != 0);
+ QVERIFY(own.object != nullptr);
QObject *object = component.create(context);
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
- QVERIFY(own.object != 0);
+ QVERIFY(own.object != nullptr);
delete object;
}
@@ -3385,7 +3512,7 @@ class CppOwnershipReturnValue : public QObject
{
Q_OBJECT
public:
- CppOwnershipReturnValue() : value(0) {}
+ CppOwnershipReturnValue() : value(nullptr) {}
~CppOwnershipReturnValue() { delete value; }
Q_INVOKABLE QObject *create() {
@@ -3420,21 +3547,22 @@ void tst_qqmlecmascript::cppOwnershipReturnValue()
QObject *object = component.create();
- QVERIFY(object != 0);
- QVERIFY(source.value != 0);
+ QVERIFY(object != nullptr);
+ QVERIFY(source.value != nullptr);
delete object;
}
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
- QVERIFY(source.value != 0);
+ QVERIFY(source.value != nullptr);
}
// QTBUG-15697
void tst_qqmlecmascript::ownershipCustomReturnValue()
{
+ QQmlEngine engine;
CppOwnershipReturnValue source;
{
@@ -3448,14 +3576,14 @@ void tst_qqmlecmascript::ownershipCustomReturnValue()
QObject *object = component.create();
- QVERIFY(object != 0);
- QVERIFY(source.value != 0);
+ QVERIFY(object != nullptr);
+ QVERIFY(source.value != nullptr);
delete object;
}
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(source.value.isNull());
@@ -3467,7 +3595,7 @@ class OwnershipChangingObject : public QObject
{
Q_OBJECT
public:
- OwnershipChangingObject(): object(0) { }
+ OwnershipChangingObject(): object(nullptr) { }
QPointer<QObject> object;
@@ -3478,6 +3606,7 @@ public slots:
void tst_qqmlecmascript::ownershipRootObject()
{
+ QQmlEngine engine;
OwnershipChangingObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3488,10 +3617,10 @@ void tst_qqmlecmascript::ownershipRootObject()
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
- QVERIFY(own.object != 0);
+ QVERIFY(own.object != nullptr);
delete context;
delete object;
@@ -3499,6 +3628,7 @@ void tst_qqmlecmascript::ownershipRootObject()
void tst_qqmlecmascript::ownershipConsistency()
{
+ QQmlEngine engine;
OwnershipChangingObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3518,10 +3648,10 @@ void tst_qqmlecmascript::ownershipConsistency()
engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
- QVERIFY(own.object != 0);
+ QVERIFY(own.object != nullptr);
delete context;
delete object;
@@ -3529,6 +3659,7 @@ void tst_qqmlecmascript::ownershipConsistency()
void tst_qqmlecmascript::ownershipQmlIncubated()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("ownershipQmlIncubated.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -3537,7 +3668,7 @@ void tst_qqmlecmascript::ownershipQmlIncubated()
QMetaObject::invokeMethod(object, "deleteIncubatedItem");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(!object->property("incubatedItem").value<QObject*>());
@@ -3568,6 +3699,7 @@ private:
// Tests that returning a QList<QObject*> from a method works
void tst_qqmlecmascript::qlistqobjectMethods()
{
+ QQmlEngine engine;
QListQObjectMethodsObject obj;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&obj);
@@ -3586,10 +3718,11 @@ void tst_qqmlecmascript::qlistqobjectMethods()
// QTBUG-9205
void tst_qqmlecmascript::strictlyEquals()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("strictlyEquals.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -3605,10 +3738,11 @@ void tst_qqmlecmascript::strictlyEquals()
void tst_qqmlecmascript::compiled()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compiled.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toReal(), qreal(15.7));
QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
@@ -3645,10 +3779,11 @@ void tst_qqmlecmascript::compiled()
// Test that numbers assigned in bindings as strings work consistently
void tst_qqmlecmascript::numberAssignment()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("numberAssignment.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
@@ -3671,10 +3806,11 @@ void tst_qqmlecmascript::numberAssignment()
void tst_qqmlecmascript::propertySplicing()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertySplicing.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -3684,10 +3820,11 @@ void tst_qqmlecmascript::propertySplicing()
// QTBUG-16683
void tst_qqmlecmascript::signalWithUnknownTypes()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MyQmlObject::MyType type;
type.value = 0x8971123;
@@ -3737,9 +3874,10 @@ void tst_qqmlecmascript::signalWithJSValueInVariant()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QJSValue value = engine.evaluate(expression);
QVERIFY(!value.isError());
@@ -3761,9 +3899,10 @@ void tst_qqmlecmascript::signalWithJSValueInVariant_twoEngines()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QJSEngine engine2;
QJSValue value = engine2.evaluate(expression);
@@ -3791,9 +3930,10 @@ void tst_qqmlecmascript::signalWithQJSValue()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QJSValue value = engine.evaluate(expression);
QVERIFY(!value.isError());
@@ -3959,7 +4099,7 @@ void tst_qqmlecmascript::singletonType()
if (!errorMessage.isEmpty()) {
QVERIFY(!object);
} else {
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
for (int i = 0; i < readProperties.size(); ++i)
QCOMPARE(object->property(readProperties.at(i).toLatin1().constData()), readExpectedValues.at(i));
for (int i = 0; i < writeProperties.size(); ++i)
@@ -3994,7 +4134,7 @@ void tst_qqmlecmascript::singletonTypeCaching()
QQmlEngine cleanEngine;
QQmlComponent component(&cleanEngine, testfile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QList<QVariant> firstValues;
QMetaObject::invokeMethod(object, "modifyValues");
for (int i = 0; i < readProperties.size(); ++i)
@@ -4003,7 +4143,7 @@ void tst_qqmlecmascript::singletonTypeCaching()
QQmlComponent component2(&cleanEngine, testfile);
QObject *object2 = component2.create();
- QVERIFY(object2 != 0);
+ QVERIFY(object2 != nullptr);
for (int i = 0; i < readProperties.size(); ++i)
QCOMPARE(object2->property(readProperties.at(i).toLatin1().constData()), firstValues.at(i)); // cached, shouldn't have changed.
delete object2;
@@ -4011,6 +4151,7 @@ void tst_qqmlecmascript::singletonTypeCaching()
void tst_qqmlecmascript::singletonTypeImportOrder()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonTypeImportOrder.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -4020,6 +4161,7 @@ void tst_qqmlecmascript::singletonTypeImportOrder()
void tst_qqmlecmascript::singletonTypeResolution()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonTypeResolution.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -4031,27 +4173,26 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
QQmlContextData *childCtxt = ctxt->childContexts;
if (!ctxt->importedScripts.isNullOrUndefined()) {
- QV8Engine *engine = QV8Engine::get(ctxt->engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::ExecutionEngine *v4 = ctxt->engine->handle();
QV4::Scope scope(v4);
QV4::ScopedArrayObject scripts(scope, ctxt->importedScripts.value());
QV4::Scoped<QV4::QQmlContextWrapper> qml(scope);
for (quint32 i = 0; i < scripts->getLength(); ++i) {
QQmlContextData *scriptContext, *newContext;
- qml = scripts->getIndexed(i);
+ qml = scripts->get(i);
- scriptContext = qml ? qml->getContext() : 0;
+ scriptContext = qml ? qml->getContext() : nullptr;
qml = QV4::Encode::undefined();
{
- QV4::Scope scope(QV8Engine::getV4((engine)));
- QV4::ScopedContext temporaryScope(scope, QV4::QmlContext::create(scope.engine->rootContext(), scriptContext, 0));
+ QV4::Scope scope(v4);
+ QV4::ScopedContext temporaryScope(scope, QV4::QmlContext::create(scope.engine->rootContext(), scriptContext, nullptr));
Q_UNUSED(temporaryScope)
}
ctxt->engine->collectGarbage();
- qml = scripts->getIndexed(i);
- newContext = qml ? qml->getContext() : 0;
+ qml = scripts->get(i);
+ newContext = qml ? qml->getContext() : nullptr;
QCOMPARE(scriptContext, newContext);
}
}
@@ -4164,7 +4305,7 @@ void tst_qqmlecmascript::importScripts_data()
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(18));
+ << (QVariantList() << QVariant(16));
QTest::newRow("import singleton type into js import")
<< testFileUrl("jsimport/testImportSingletonType.qml")
@@ -4298,6 +4439,10 @@ void tst_qqmlecmascript::importScripts()
ThreadedTestHTTPServer server(dataDirectory() + "/remote");
+ QQmlEngine engine;
+ QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
+ engine.addImportPath(dataDir);
+
QStringList importPathList = engine.importPathList();
QString remotePath(server.urlString("/"));
@@ -4326,7 +4471,7 @@ void tst_qqmlecmascript::importScripts()
if (!errorMessage.isEmpty()) {
QVERIFY(!object);
} else {
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlContextData *ctxt = QQmlContextData::get(engine.rootContext());
tst_qqmlecmascript::verifyContextLifetime(ctxt);
@@ -4341,6 +4486,7 @@ void tst_qqmlecmascript::importScripts()
void tst_qqmlecmascript::importCreationContext()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("jsimport/creationContext.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4361,11 +4507,11 @@ void tst_qqmlecmascript::scarceResources_other()
QPixmap origPixmap(100, 100);
origPixmap.fill(Qt::blue);
QString srp_name, expectedWarning;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- ScarceResourceObject *eo = 0;
- QObject *srsc = 0;
- QObject *object = 0;
+ QQmlEngine engine;
+ QV4::ExecutionEngine *v4 = engine.handle();
+ ScarceResourceObject *eo = nullptr;
+ QObject *srsc = nullptr;
+ QObject *object = nullptr;
/* property var semantics */
@@ -4394,7 +4540,7 @@ void tst_qqmlecmascript::scarceResources_other()
// test that scarce resources are handled properly from js functions in qml files
QQmlComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
object = varComponentEleven.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
@@ -4413,7 +4559,7 @@ void tst_qqmlecmascript::scarceResources_other()
// test that if an exception occurs while invoking js function from cpp, that the resources are released.
QQmlComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
object = varComponentTwelve.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
@@ -4431,7 +4577,7 @@ void tst_qqmlecmascript::scarceResources_other()
// that the scarce resource is removed from the engine's list of scarce resources to clean up.
QQmlComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
object = varComponentThirteen.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
QMetaObject::invokeMethod(object, "assignVarProperty");
QVERIFY(v4->scarceResources.isEmpty()); // the scarce resource is a VME property.
@@ -4445,7 +4591,7 @@ void tst_qqmlecmascript::scarceResources_other()
// test that scarce resources are handled properly in signal invocation
QQmlComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
object = variantComponentTen.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
srsc = object->findChild<QObject*>("srsc");
QVERIFY(srsc);
QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
@@ -4468,7 +4614,7 @@ void tst_qqmlecmascript::scarceResources_other()
// test that scarce resources are handled properly from js functions in qml files
QQmlComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
object = variantComponentEleven.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
@@ -4487,7 +4633,7 @@ void tst_qqmlecmascript::scarceResources_other()
// test that if an exception occurs while invoking js function from cpp, that the resources are released.
QQmlComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
object = variantComponentTwelve.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
@@ -4733,14 +4879,14 @@ void tst_qqmlecmascript::scarceResources()
QFETCH(QVariantList, expectedValues);
QFETCH(QStringList, expectedErrors);
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine);
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- ScarceResourceObject *eo = 0;
- QObject *object = 0;
+ QQmlEngine engine;
+ QV4::ExecutionEngine *v4 = engine.handle();
+ ScarceResourceObject *eo = nullptr;
+ QObject *object = nullptr;
QQmlComponent c(&engine, qmlFile);
object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
for (int i = 0; i < propertyNames.size(); ++i) {
QString prop = propertyNames.at(i);
bool validity = expectedValidity.at(i).toBool();
@@ -4766,9 +4912,10 @@ void tst_qqmlecmascript::scarceResources()
void tst_qqmlecmascript::propertyChangeSlots()
{
// ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
// ensure that invalid property names fail properly.
@@ -4832,9 +4979,10 @@ void tst_qqmlecmascript::propertyVar()
{
QFETCH(QUrl, qmlFile);
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -4871,9 +5019,10 @@ void tst_qqmlecmascript::propertyQJSValue()
{
QFETCH(QUrl, qmlFile);
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -4883,14 +5032,15 @@ void tst_qqmlecmascript::propertyQJSValue()
// Tests that we can write QVariant values to var properties from C++
void tst_qqmlecmascript::propertyVarCpp()
{
- QObject *object = 0;
+ QObject *object = nullptr;
// ensure that writing to and reading from a var property from cpp works as required.
// Literal values stored in var properties can be read and written as QVariants
// of a specific type, whereas object values are read as QVariantMaps.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// assign int to property var that currently has int assigned
QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
QCOMPARE(object->property("varBound"), QVariant(15));
@@ -4909,11 +5059,13 @@ void tst_qqmlecmascript::propertyVarCpp()
void tst_qqmlecmascript::propertyVarOwnership()
{
+ QQmlEngine engine;
+
// Referenced JS objects are not collected
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
QMetaObject::invokeMethod(object, "runTest");
QCOMPARE(object->property("test").toBool(), true);
@@ -4923,7 +5075,7 @@ void tst_qqmlecmascript::propertyVarOwnership()
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), false);
QMetaObject::invokeMethod(object, "runTest");
QCOMPARE(object->property("test").toBool(), true);
@@ -4933,7 +5085,7 @@ void tst_qqmlecmascript::propertyVarOwnership()
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test2").toBool(), false);
QCOMPARE(object->property("test2").toBool(), false);
@@ -4957,7 +5109,7 @@ void tst_qqmlecmascript::propertyVarOwnership()
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -4976,7 +5128,7 @@ void tst_qqmlecmascript::propertyVarOwnership()
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.5.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "createComponent");
engine.collectGarbage();
QMetaObject::invokeMethod(object, "runTest");
@@ -4990,22 +5142,23 @@ void tst_qqmlecmascript::propertyVarImplicitOwnership()
// The childObject has a reference to a different QObject. We want to ensure
// that the different item will not be cleaned up until required. IE, the childObject
// has implicit ownership of the constructed QObject.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
+ QVERIFY(rootObject != nullptr);
QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
+ QVERIFY(childObject != nullptr);
QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
QCOMPARE(childObject->property("textCanary").toInt(), 10);
QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
QPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
QVERIFY(!qobjectGuard.isNull());
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QVERIFY(!qobjectGuard.isNull());
QMetaObject::invokeMethod(object, "deassignCircular");
@@ -5017,11 +5170,12 @@ void tst_qqmlecmascript::propertyVarImplicitOwnership()
void tst_qqmlecmascript::propertyVarReparent()
{
// ensure that nothing breaks if we re-parent objects
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QObject *rect = object->property("vp").value<QObject*>();
QObject *text = rect->findChild<QObject*>("textOne");
@@ -5059,11 +5213,12 @@ void tst_qqmlecmascript::propertyVarReparentNullContext()
// sometimes reparenting can cause problems
// (eg, if the ctxt is collected, varproperties are no longer available)
// this test ensures that no crash occurs in that situation.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QObject *rect = object->property("vp").value<QObject*>();
QObject *text = rect->findChild<QObject*>("textOne");
@@ -5095,9 +5250,10 @@ void tst_qqmlecmascript::propertyVarReparentNullContext()
void tst_qqmlecmascript::propertyVarCircular()
{
// enforce behaviour regarding circular references - ensure qdvmemo deletion.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
{
QCOMPARE(object->property("canaryInt"), QVariant(5));
@@ -5105,7 +5261,7 @@ void tst_qqmlecmascript::propertyVarCircular()
QVERIFY(canaryResourceVariant.isValid());
}
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QCOMPARE(object->property("canaryInt"), QVariant(5));
QVariant canaryResourceVariant = object->property("canaryResource");
@@ -5127,16 +5283,17 @@ void tst_qqmlecmascript::propertyVarCircular2()
{
// track deletion of JS-owned parent item with Cpp-owned child
// where the child has a var property referencing its parent.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
+ QVERIFY(rootObject != nullptr);
QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
+ QVERIFY(childObject != nullptr);
QPointer<QObject> rootObjectTracker(rootObject);
QVERIFY(!rootObjectTracker.isNull());
QPointer<QObject> childObjectTracker(childObject);
@@ -5155,11 +5312,12 @@ void tst_qqmlecmascript::propertyVarInheritance()
{
// enforce behaviour regarding element inheritance - ensure handle disposal.
// The particular component under test here has a chain of references.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
// we want to be able to track when the varProperties array of the last metaobject is disposed
QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
@@ -5174,9 +5332,9 @@ void tst_qqmlecmascript::propertyVarInheritance()
// XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
// public function which can return us a handle to something in the varProperties array.
QV4::ReturnedValue tmp = icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ"));
- icoCanaryHandle.set(QQmlEnginePrivate::getV4Engine(&engine), tmp);
+ icoCanaryHandle.set(engine.handle(), tmp);
tmp = ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ"));
- ccoCanaryHandle.set(QQmlEnginePrivate::getV4Engine(&engine), tmp);
+ ccoCanaryHandle.set(engine.handle(), tmp);
tmp = QV4::Encode::null();
QVERIFY(!icoCanaryHandle.isUndefined());
QVERIFY(!ccoCanaryHandle.isUndefined());
@@ -5200,21 +5358,22 @@ void tst_qqmlecmascript::propertyVarInheritance2()
{
// The particular component under test here does NOT have a chain of references; the
// only link between rootObject and childObject is that rootObject is the parent of childObject.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
+ QVERIFY(rootObject != nullptr);
QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
+ QVERIFY(childObject != nullptr);
QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
QCOMPARE(childObject->property("textCanary").toInt(), 10);
QV4::WeakValue childObjectVarArrayValueHandle;
{
- childObjectVarArrayValueHandle.set(QQmlEnginePrivate::getV4Engine(&engine),
+ childObjectVarArrayValueHandle.set(engine.handle(),
QQmlVMEMetaObject::get(childObject)->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
QVERIFY(!childObjectVarArrayValueHandle.isUndefined());
gc(engine);
@@ -5233,10 +5392,11 @@ void tst_qqmlecmascript::propertyVarInheritance2()
// Ensure that QObject type conversion works on binding assignment
void tst_qqmlecmascript::elementAssign()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("elementAssign.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -5246,10 +5406,11 @@ void tst_qqmlecmascript::elementAssign()
// QTBUG-12457
void tst_qqmlecmascript::objectPassThroughSignals()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -5259,10 +5420,11 @@ void tst_qqmlecmascript::objectPassThroughSignals()
// QTBUG-21626
void tst_qqmlecmascript::objectConversion()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectConversion.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant retn;
QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
QCOMPARE(retn.value<QJSValue>().property("test").toInt(), int(100));
@@ -5274,10 +5436,11 @@ void tst_qqmlecmascript::objectConversion()
// QTBUG-20242
void tst_qqmlecmascript::booleanConversion()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("booleanConversion.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test_true1").toBool(), true);
QCOMPARE(object->property("test_true2").toBool(), true);
@@ -5300,16 +5463,15 @@ void tst_qqmlecmascript::handleReferenceManagement()
QQmlEngine hrmEngine;
QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
- cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "createReference");
gc(hrmEngine);
QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
@@ -5320,16 +5482,15 @@ void tst_qqmlecmascript::handleReferenceManagement()
QQmlEngine hrmEngine;
QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
- cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "circularReference");
gc(hrmEngine);
QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
@@ -5339,7 +5500,7 @@ void tst_qqmlecmascript::handleReferenceManagement()
QQmlEngine hrmEngine;
QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.dynprop.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "createReference");
gc(hrmEngine);
QMetaObject::invokeMethod(object, "ensureReference");
@@ -5356,7 +5517,7 @@ void tst_qqmlecmascript::handleReferenceManagement()
QQmlEngine hrmEngine;
QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.dynprop.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "createReference");
gc(hrmEngine);
QMetaObject::invokeMethod(object, "ensureReference");
@@ -5373,7 +5534,7 @@ void tst_qqmlecmascript::handleReferenceManagement()
QQmlEngine hrmEngine;
QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.dynprop.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "createReference");
gc(hrmEngine);
QMetaObject::invokeMethod(object, "ensureReference");
@@ -5388,9 +5549,10 @@ void tst_qqmlecmascript::handleReferenceManagement()
void tst_qqmlecmascript::stringArg()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringArg.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "success");
QVERIFY(object->property("returnValue").toBool());
@@ -5404,10 +5566,11 @@ void tst_qqmlecmascript::stringArg()
void tst_qqmlecmascript::readonlyDeclaration()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -5421,13 +5584,15 @@ Q_DECLARE_METATYPE(QList<QString>)
Q_DECLARE_METATYPE(QList<QUrl>)
void tst_qqmlecmascript::sequenceConversionRead()
{
+ QQmlEngine engine;
+
{
QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
+ QVERIFY(seq != nullptr);
QMetaObject::invokeMethod(object, "readSequences");
QList<int> intList; intList << 1 << 2 << 3 << 4;
@@ -5476,9 +5641,9 @@ void tst_qqmlecmascript::sequenceConversionRead()
QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
+ QVERIFY(seq != nullptr);
// we haven't registered QList<NonRegisteredType> as a sequence type.
QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<NonRegisteredType>' for property 'MySequenceConversionObject::typeListProperty'");
@@ -5501,13 +5666,14 @@ void tst_qqmlecmascript::sequenceConversionRead()
void tst_qqmlecmascript::sequenceConversionWrite()
{
+ QQmlEngine engine;
{
QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
+ QVERIFY(seq != nullptr);
QMetaObject::invokeMethod(object, "writeSequences");
QCOMPARE(object->property("success").toBool(), true);
@@ -5528,9 +5694,9 @@ void tst_qqmlecmascript::sequenceConversionWrite()
QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
+ QVERIFY(seq != nullptr);
// we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QJSValue to QList<QPoint>");
@@ -5549,18 +5715,20 @@ void tst_qqmlecmascript::sequenceConversionArray()
{
// ensure that in JS the returned sequences act just like normal JS Arrays.
QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "indexedAccess");
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QMetaObject::invokeMethod(object.data(), "indexedAccess");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "arrayOperations");
+ QMetaObject::invokeMethod(object.data(), "arrayOperations");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testEqualitySemantics");
+ QMetaObject::invokeMethod(object.data(), "testEqualitySemantics");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QMetaObject::invokeMethod(object.data(), "testReferenceDeletion");
QCOMPARE(object->property("referenceDeletion").toBool(), true);
- delete object;
+ QMetaObject::invokeMethod(object.data(), "jsonConversion");
+ QVERIFY(object->property("success").toBool());
}
@@ -5569,9 +5737,10 @@ void tst_qqmlecmascript::sequenceConversionIndexes()
// ensure that we gracefully fail if unsupported index values are specified.
// Qt container classes only support non-negative, signed integer index values.
QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set");
QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set");
QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get");
@@ -5590,9 +5759,10 @@ void tst_qqmlecmascript::sequenceConversionThreads()
// ensure that sequence conversion operations work correctly in a worker thread
// and that serialisation between the main and worker thread succeeds.
QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "testIntSequence");
QTRY_VERIFY(object->property("finished").toBool());
@@ -5627,11 +5797,12 @@ void tst_qqmlecmascript::sequenceConversionThreads()
void tst_qqmlecmascript::sequenceConversionBindings()
{
+ QQmlEngine engine;
{
QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
@@ -5642,11 +5813,11 @@ void tst_qqmlecmascript::sequenceConversionBindings()
{
QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
- QString warning = QString(QLatin1String("%1:17:27: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
+ QString warning = QString(QLatin1String("%1:17:9: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
}
@@ -5654,9 +5825,10 @@ void tst_qqmlecmascript::sequenceConversionBindings()
void tst_qqmlecmascript::sequenceConversionCopy()
{
QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "testCopySequences");
QCOMPARE(object->property("success").toBool(), true);
QMetaObject::invokeMethod(object, "readSequenceCopyElements");
@@ -5672,11 +5844,13 @@ void tst_qqmlecmascript::sequenceConversionCopy()
void tst_qqmlecmascript::assignSequenceTypes()
{
+ QQmlEngine engine;
+
// test binding array to sequence type property
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
@@ -5690,7 +5864,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
@@ -5704,7 +5878,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
@@ -5716,7 +5890,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2 << 3));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
@@ -5730,7 +5904,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
@@ -5744,7 +5918,7 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->intListProperty(), (QList<int>() << 1));
QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1));
QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
@@ -5756,13 +5930,13 @@ void tst_qqmlecmascript::assignSequenceTypes()
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
- QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
+ QVERIFY(msco1 != nullptr && msco2 != nullptr && msco3 != nullptr && msco4 != nullptr && msco5 != nullptr);
QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
@@ -5770,24 +5944,36 @@ void tst_qqmlecmascript::assignSequenceTypes()
QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
delete object;
}
+
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.8.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QVariant result;
+ QMetaObject::invokeMethod(object.data(), "tryWritingReadOnlySequence", Q_RETURN_ARG(QVariant, result));
+ QVERIFY(result.type() == QVariant::Bool);
+ QVERIFY(result.toBool());
+ }
}
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qqmlecmascript::nullObjectBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
- QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
+ QVERIFY(object->property("test") == QVariant::fromValue((QObject *)nullptr));
delete object;
}
void tst_qqmlecmascript::nullObjectInitializer()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -5818,7 +6004,7 @@ void tst_qqmlecmascript::nullObjectInitializer()
{
const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty");
QVERIFY(propertyIndex > 0);
- QVERIFY(ddata->hasBindingBit(propertyIndex));
+ QVERIFY(!ddata->hasBindingBit(propertyIndex));
}
QVERIFY(obj->property("success").toBool());
@@ -5827,6 +6013,13 @@ void tst_qqmlecmascript::nullObjectInitializer()
QVERIFY(value.userType() == qMetaTypeId<QObject*>());
QVERIFY(!value.value<QObject*>());
}
+
+ {
+ QQmlComponent component(&engine, testFileUrl("qmlVarNullBinding.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(!obj->property("signalSeen").toBool());
+ }
}
// Test that bindings don't evaluate once the engine has been destroyed
@@ -5836,7 +6029,7 @@ void tst_qqmlecmascript::deletedEngine()
QQmlComponent component(engine, testFileUrl("deletedEngine.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 39);
object->setProperty("b", QVariant(9));
@@ -5855,20 +6048,22 @@ void tst_qqmlecmascript::deletedEngine()
// Test the crashing part of QTBUG-9705
void tst_qqmlecmascript::libraryScriptAssert()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::variantsAssignedUndefined()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toInt(), 10);
QCOMPARE(object->property("test2").toInt(), 11);
@@ -5884,10 +6079,11 @@ void tst_qqmlecmascript::variantsAssignedUndefined()
void tst_qqmlecmascript::variants()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("variants.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("undefinedVariant").type(), QVariant::Invalid);
QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::Nullptr));
@@ -5907,12 +6103,13 @@ void tst_qqmlecmascript::variants()
void tst_qqmlecmascript::qtbug_9792()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_9792.qml"));
QQmlContext *context = new QQmlContext(engine.rootContext());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtDebugMsg, "Hello world!");
object->basicSignal();
@@ -5931,13 +6128,14 @@ void tst_qqmlecmascript::qtbug_9792()
// Verifies that QPointer<>s used in the vmemetaobject are cleaned correctly
void tst_qqmlecmascript::qtcreatorbug_1289()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QObject *nested = qvariant_cast<QObject *>(o->property("object"));
- QVERIFY(nested != 0);
+ QVERIFY(nested != nullptr);
QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
@@ -5952,6 +6150,7 @@ void tst_qqmlecmascript::qtcreatorbug_1289()
// Test that we shut down without stupid warnings
void tst_qqmlecmascript::noSpuriousWarningsAtShutdown()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
@@ -5980,13 +6179,14 @@ void tst_qqmlecmascript::noSpuriousWarningsAtShutdown()
void tst_qqmlecmascript::canAssignNullToQObject()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
- QVERIFY(o->objectProperty() != 0);
+ QVERIFY(o->objectProperty() != nullptr);
o->setProperty("runTest", true);
@@ -5999,7 +6199,7 @@ void tst_qqmlecmascript::canAssignNullToQObject()
QQmlComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!o->objectProperty());
@@ -6009,20 +6209,21 @@ void tst_qqmlecmascript::canAssignNullToQObject()
void tst_qqmlecmascript::functionAssignment_fromBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
QString url = component.url().toString();
- QString w1 = url + ":4:25: Unable to assign a function to a property of any type other than var.";
- QString w2 = url + ":5:25: Invalid use of Qt.binding() in a binding declaration.";
- QString w3 = url + ":6:21: Invalid use of Qt.binding() in a binding declaration.";
- QString w4 = url + ":7:15: Invalid use of Qt.binding() in a binding declaration.";
+ QString w1 = url + ":4:5: Unable to assign a function to a property of any type other than var.";
+ QString w2 = url + ":5:5: Invalid use of Qt.binding() in a binding declaration.";
+ QString w3 = url + ":6:5: Invalid use of Qt.binding() in a binding declaration.";
+ QString w4 = url + ":7:5: Invalid use of Qt.binding() in a binding declaration.";
QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, w2.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, w3.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, w4.toLatin1().constData());
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!o->property("a").isValid());
@@ -6033,11 +6234,12 @@ void tst_qqmlecmascript::functionAssignment_fromJS()
{
QFETCH(QString, triggerProperty);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!o->property("a").isValid());
o->setProperty("aNumber", QVariant(5));
@@ -6065,11 +6267,12 @@ void tst_qqmlecmascript::functionAssignment_fromJS_data()
void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(!o->property("a").isValid());
o->setProperty("assignFuncWithoutReturn", true);
@@ -6089,6 +6292,7 @@ void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
void tst_qqmlecmascript::functionAssignment_afterBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.3.qml"));
QString url = component.url().toString();
@@ -6096,7 +6300,7 @@ void tst_qqmlecmascript::functionAssignment_afterBinding()
QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData());
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("t1"), QVariant::fromValue<int>(4)); // should have bound
QCOMPARE(o->property("t2"), QVariant::fromValue<int>(2)); // should not have changed
@@ -6105,10 +6309,11 @@ void tst_qqmlecmascript::functionAssignment_afterBinding()
void tst_qqmlecmascript::eval()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("eval.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
@@ -6121,10 +6326,11 @@ void tst_qqmlecmascript::eval()
void tst_qqmlecmascript::function()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("function.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
@@ -6136,11 +6342,12 @@ void tst_qqmlecmascript::function()
// Test the "Qt.include" method
void tst_qqmlecmascript::include()
{
+ QQmlEngine engine;
// Non-library relative include
{
QQmlComponent component(&engine, testFileUrl("include.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test0").toInt(), 99);
QCOMPARE(o->property("test1").toBool(), true);
@@ -6156,7 +6363,7 @@ void tst_qqmlecmascript::include()
{
QQmlComponent component(&engine, testFileUrl("include_shared.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test0").toInt(), 99);
QCOMPARE(o->property("test1").toBool(), true);
@@ -6172,7 +6379,7 @@ void tst_qqmlecmascript::include()
{
QQmlComponent component(&engine, testFileUrl("include_callback.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
@@ -6188,12 +6395,20 @@ void tst_qqmlecmascript::include()
{
QQmlComponent component(&engine, testFileUrl("include_pragma.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toInt(), 100);
delete o;
}
+ // Including file with ".pragma library", shadowing a global var
+ {
+ QQmlComponent component(&engine, testFileUrl("include_pragma_shadow.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("result").toBool(), true);
+ }
+
// Remote - error
{
TestHTTPServer server;
@@ -6202,7 +6417,7 @@ void tst_qqmlecmascript::include()
QQmlComponent component(&engine, testFileUrl("include_remote_missing.qml"));
QObject *o = component.beginCreate(engine.rootContext());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
o->setProperty("serverBaseUrl", server.baseUrl().toString());
component.completeCreate();
@@ -6219,7 +6434,7 @@ void tst_qqmlecmascript::include()
{
QQmlComponent component(&engine, QUrl("qrc:///data/include.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test0").toInt(), 99);
QCOMPARE(o->property("test1").toBool(), true);
@@ -6235,18 +6450,15 @@ void tst_qqmlecmascript::include()
void tst_qqmlecmascript::includeRemoteSuccess()
{
-#if defined(Q_CC_MSVC) && _MSC_VER == 1700
- QSKIP("This test does not work reliably with MSVC2012 on Win8 64-bit in release mode.");
-#endif
-
// Remote - success
TestHTTPServer server;
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("include_remote.qml"));
QObject *o = component.beginCreate(engine.rootContext());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
o->setProperty("serverBaseUrl", server.baseUrl().toString());
component.completeCreate();
@@ -6270,42 +6482,42 @@ void tst_qqmlecmascript::includeRemoteSuccess()
void tst_qqmlecmascript::signalHandlers()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalHandlers.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("count").toInt(), 0);
- QMetaObject::invokeMethod(o, "testSignalCall");
+ QMetaObject::invokeMethod(o.data(), "testSignalCall");
QCOMPARE(o->property("count").toInt(), 1);
- QMetaObject::invokeMethod(o, "testSignalHandlerCall");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall");
QCOMPARE(o->property("count").toInt(), 1);
QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
QCOMPARE(o->property("funcCount").toInt(), 0);
- QMetaObject::invokeMethod(o, "testSignalConnection");
+ QMetaObject::invokeMethod(o.data(), "testSignalConnection");
QCOMPARE(o->property("funcCount").toInt(), 1);
- QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerConnection");
QCOMPARE(o->property("funcCount").toInt(), 2);
- QMetaObject::invokeMethod(o, "testSignalDefined");
+ QMetaObject::invokeMethod(o.data(), "testSignalDefined");
QCOMPARE(o->property("definedResult").toBool(), true);
- QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerDefined");
QCOMPARE(o->property("definedHandlerResult").toBool(), true);
QVariant result;
- QMetaObject::invokeMethod(o, "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(o, "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(o, "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result.toBool(), true);
+ QMetaObject::invokeMethod(o.data(), "testThisInSignalHandler", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
-
- delete o;
}
void tst_qqmlecmascript::qtbug_37351()
@@ -6331,46 +6543,51 @@ void tst_qqmlecmascript::qtbug_37351()
void tst_qqmlecmascript::qtbug_10696()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_10696.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
delete o;
}
void tst_qqmlecmascript::qtbug_11606()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_11606.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
void tst_qqmlecmascript::qtbug_11600()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_11600.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
void tst_qqmlecmascript::qtbug_21864()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_21864.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
void tst_qqmlecmascript::rewriteMultiLineStrings()
{
+ QQmlEngine engine;
{
// QTBUG-23387
QQmlComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QTRY_COMPARE(o->property("test").toBool(), true);
delete o;
}
@@ -6378,7 +6595,7 @@ void tst_qqmlecmascript::rewriteMultiLineStrings()
{
QQmlComponent component(&engine, testFileUrl("rewriteMultiLineStrings_crlf.1.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
delete o;
}
}
@@ -6386,13 +6603,14 @@ void tst_qqmlecmascript::rewriteMultiLineStrings()
void tst_qqmlecmascript::qobjectConnectionListExceptionHandling()
{
// QTBUG-23375
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
@@ -6400,9 +6618,10 @@ void tst_qqmlecmascript::qobjectConnectionListExceptionHandling()
// Reading and writing non-scriptable properties should fail
void tst_qqmlecmascript::nonscriptable()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonscriptable.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("readOk").toBool(), true);
QCOMPARE(o->property("writeOk").toBool(), true);
delete o;
@@ -6411,9 +6630,10 @@ void tst_qqmlecmascript::nonscriptable()
// deleteLater() should not be callable from QML
void tst_qqmlecmascript::deleteLater()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteLater.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
@@ -6421,9 +6641,10 @@ void tst_qqmlecmascript::deleteLater()
// objectNameChanged() should be usable from QML
void tst_qqmlecmascript::objectNameChangedSignal()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectNameChangedSignal.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), false);
o->setObjectName("obj");
QCOMPARE(o->property("test").toBool(), true);
@@ -6433,6 +6654,7 @@ void tst_qqmlecmascript::objectNameChangedSignal()
// destroyed() should not be usable from QML
void tst_qqmlecmascript::destroyedSignal()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("destroyedSignal.qml"));
QVERIFY(component.isError());
@@ -6442,9 +6664,10 @@ void tst_qqmlecmascript::destroyedSignal()
void tst_qqmlecmascript::in()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("in.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
delete o;
@@ -6452,10 +6675,11 @@ void tst_qqmlecmascript::in()
void tst_qqmlecmascript::typeOf()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("typeOf.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
@@ -6472,17 +6696,19 @@ void tst_qqmlecmascript::typeOf()
void tst_qqmlecmascript::qtbug_24448()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_24448.qml"));
QScopedPointer<QObject> o(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(o->property("test").toBool());
}
void tst_qqmlecmascript::sharedAttachedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
delete o;
@@ -6491,9 +6717,10 @@ void tst_qqmlecmascript::sharedAttachedObject()
// QTBUG-13999
void tst_qqmlecmascript::objectName()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectName.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toString(), QString("hello"));
QCOMPARE(o->property("test2").toString(), QString("ell"));
@@ -6508,9 +6735,10 @@ void tst_qqmlecmascript::objectName()
void tst_qqmlecmascript::writeRemovesBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6520,9 +6748,10 @@ void tst_qqmlecmascript::writeRemovesBinding()
// Test bindings assigned to alias properties actually assign to the alias' target
void tst_qqmlecmascript::aliasBindingsAssignCorrectly()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6532,10 +6761,11 @@ void tst_qqmlecmascript::aliasBindingsAssignCorrectly()
// Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
void tst_qqmlecmascript::aliasBindingsOverrideTarget()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6545,7 +6775,7 @@ void tst_qqmlecmascript::aliasBindingsOverrideTarget()
{
QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6555,7 +6785,7 @@ void tst_qqmlecmascript::aliasBindingsOverrideTarget()
{
QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6566,10 +6796,11 @@ void tst_qqmlecmascript::aliasBindingsOverrideTarget()
// Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
void tst_qqmlecmascript::aliasWritesOverrideBindings()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6579,7 +6810,7 @@ void tst_qqmlecmascript::aliasWritesOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6589,7 +6820,7 @@ void tst_qqmlecmascript::aliasWritesOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
@@ -6601,29 +6832,32 @@ void tst_qqmlecmascript::aliasWritesOverrideBindings()
// QTBUG-20200
void tst_qqmlecmascript::aliasToCompositeElement()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::qtbug_20344()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_20344.qml"));
QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::revisionErrors()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
QString url = component.url().toString();
@@ -6636,7 +6870,7 @@ void tst_qqmlecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
{
@@ -6658,7 +6892,7 @@ void tst_qqmlecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
{
@@ -6674,19 +6908,20 @@ void tst_qqmlecmascript::revisionErrors()
QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
}
void tst_qqmlecmascript::revision()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
{
@@ -6694,7 +6929,7 @@ void tst_qqmlecmascript::revision()
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
{
@@ -6702,7 +6937,7 @@ void tst_qqmlecmascript::revision()
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
// Test that non-root classes can resolve revisioned methods
@@ -6710,7 +6945,7 @@ void tst_qqmlecmascript::revision()
QQmlComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toReal(), 11.);
delete object;
}
@@ -6719,7 +6954,7 @@ void tst_qqmlecmascript::revision()
QQmlComponent component(&engine, testFileUrl("metaobjectRevision5.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toReal(), 11.);
delete object;
}
@@ -6727,9 +6962,10 @@ void tst_qqmlecmascript::revision()
void tst_qqmlecmascript::realToInt()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("realToInt.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "test1");
QCOMPARE(object->value(), int(4));
@@ -6739,10 +6975,11 @@ void tst_qqmlecmascript::realToInt()
void tst_qqmlecmascript::urlProperty()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->setStringProperty("http://qt-project.org");
QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
QCOMPARE(object->intProperty(), 123);
@@ -6753,10 +6990,11 @@ void tst_qqmlecmascript::urlProperty()
void tst_qqmlecmascript::urlPropertyWithEncoding()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->setStringProperty("http://qt-project.org");
const QUrl encoded = QUrl::fromEncoded("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
QCOMPARE(object->urlProperty(), encoded);
@@ -6767,15 +7005,16 @@ void tst_qqmlecmascript::urlPropertyWithEncoding()
void tst_qqmlecmascript::urlListPropertyWithEncoding()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlListProperty.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
- QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
+ QVERIFY(msco1 != nullptr && msco2 != nullptr && msco3 != nullptr && msco4 != nullptr);
const QUrl encoded = QUrl::fromEncoded("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
@@ -6787,50 +7026,57 @@ void tst_qqmlecmascript::urlListPropertyWithEncoding()
void tst_qqmlecmascript::dynamicString()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicString.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ 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!"));
}
void tst_qqmlecmascript::deleteLaterObjectMethodCall()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteLaterObjectMethodCall.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::automaticSemicolon()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::compatibilitySemicolon()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compatibilitySemicolon.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::incrDecrSemicolon1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::incrDecrSemicolon2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::incrDecrSemicolon_error1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon_error1.qml"));
QObject *object = component.create();
QVERIFY(!object);
@@ -6838,19 +7084,21 @@ void tst_qqmlecmascript::incrDecrSemicolon_error1()
void tst_qqmlecmascript::unaryExpression()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("unaryExpression.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
// Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
void tst_qqmlecmascript::doubleEvaluate()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
WriteCounter *wc = qobject_cast<WriteCounter *>(object);
- QVERIFY(wc != 0);
+ QVERIFY(wc != nullptr);
QCOMPARE(wc->count(), 1);
wc->setProperty("x", 9);
@@ -6862,17 +7110,18 @@ void tst_qqmlecmascript::doubleEvaluate()
void tst_qqmlecmascript::nonNotifyable()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonNotifyable.qml"));
QQmlTestMessageHandler messageHandler;
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString expected1 = QLatin1String("QQmlExpression: Expression ") +
component.url().toString() +
- QLatin1String(":5:24 depends on non-NOTIFYable properties:");
+ QLatin1String(":5:5 depends on non-NOTIFYable properties:");
QString expected2 = QLatin1String(" ") +
QLatin1String(object->metaObject()->className()) +
QLatin1String("::value");
@@ -6884,11 +7133,25 @@ void tst_qqmlecmascript::nonNotifyable()
delete object;
}
+void tst_qqmlecmascript::nonNotifyableConstant()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("nonNotifyableConstant.qml"));
+ QQmlTestMessageHandler messageHandler;
+
+ // Shouldn't produce an error message about non-NOTIFYable properties,
+ // as the property has the CONSTANT attribute.
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ QCOMPARE(messageHandler.messages().size(), 0);
+}
+
void tst_qqmlecmascript::forInLoop()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("forInLoop.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QMetaObject::invokeMethod(object, "listProperty");
@@ -6906,9 +7169,10 @@ void tst_qqmlecmascript::forInLoop()
// An object the binding depends on is deleted while the binding is still running
void tst_qqmlecmascript::deleteWhileBindingRunning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -6916,6 +7180,7 @@ void tst_qqmlecmascript::qtbug_22679()
{
MyQmlObject object;
object.setStringProperty(QLatin1String("Please work correctly"));
+ QQmlEngine engine;
engine.rootContext()->setContextProperty("contextProp", &object);
QQmlComponent component(&engine, testFileUrl("qtbug_22679.qml"));
@@ -6923,7 +7188,7 @@ void tst_qqmlecmascript::qtbug_22679()
QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>)));
QObject *o = component.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(warningsSpy.count(), 0);
delete o;
}
@@ -6945,6 +7210,7 @@ void tst_qqmlecmascript::qtbug_22843()
fileName += QLatin1String(".library");
fileName += QLatin1String(".qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(fileName));
QString url = component.url().toString();
@@ -6957,10 +7223,11 @@ void tst_qqmlecmascript::qtbug_22843()
void tst_qqmlecmascript::switchStatement()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("switchStatement.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -6983,7 +7250,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7006,7 +7273,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7029,11 +7296,11 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.4.qml"));
- QString warning = component.url().toString() + ":4:12: Unable to assign [undefined] to int";
+ 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());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7057,7 +7324,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.5.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7080,7 +7347,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.6.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// `object->value()' is the number of executed statements
@@ -7103,11 +7370,12 @@ void tst_qqmlecmascript::switchStatement()
void tst_qqmlecmascript::withStatement()
{
+ QQmlEngine engine;
{
QUrl url = testFileUrl("withStatement.1.qml");
QQmlComponent component(&engine, url);
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->value(), 123);
}
@@ -7115,10 +7383,11 @@ void tst_qqmlecmascript::withStatement()
void tst_qqmlecmascript::tryStatement()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("tryStatement.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->value(), 123);
}
@@ -7126,7 +7395,7 @@ void tst_qqmlecmascript::tryStatement()
{
QQmlComponent component(&engine, testFileUrl("tryStatement.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->value(), 321);
}
@@ -7134,17 +7403,17 @@ void tst_qqmlecmascript::tryStatement()
{
QQmlComponent component(&engine, testFileUrl("tryStatement.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
- QCOMPARE(object->value(), 1);
+ QVERIFY(object->qjsvalue().isUndefined());
}
{
QQmlComponent component(&engine, testFileUrl("tryStatement.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
- QCOMPARE(object->value(), 1);
+ QVERIFY(object->qjsvalue().isUndefined());
}
}
@@ -7180,7 +7449,7 @@ void tst_qqmlecmascript::invokableWithQObjectDerived()
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("result").value<bool>());
delete object;
@@ -7190,9 +7459,10 @@ void tst_qqmlecmascript::invokableWithQObjectDerived()
void tst_qqmlecmascript::realTypePrecision()
{
// Properties and signal parameters of type real should have double precision.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("realTypePrecision.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toDouble(), 1234567890.);
QCOMPARE(object->property("test2").toDouble(), 1234567890.);
QCOMPARE(object->property("test3").toDouble(), 1234567890.);
@@ -7206,7 +7476,7 @@ void tst_qqmlecmascript::registeredFlagMethod()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("registeredFlagMethod.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->buttons(), 0);
emit object->basicSignal();
@@ -7221,7 +7491,18 @@ void tst_qqmlecmascript::replaceBinding()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("replaceBinding.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
+
+ QVERIFY(obj->property("success").toBool());
+ delete obj;
+}
+
+void tst_qqmlecmascript::bindingBoundFunctions()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("bindingBoundFunctions.qml"));
+ QObject *obj = c.create();
+ QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
delete obj;
@@ -7229,11 +7510,11 @@ void tst_qqmlecmascript::replaceBinding()
void tst_qqmlecmascript::deleteRootObjectInCreation()
{
- {
QQmlEngine engine;
+ {
QQmlComponent c(&engine, testFileUrl("deleteRootObjectInCreation.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVERIFY(obj->property("rootIndestructible").toBool());
QVERIFY(!obj->property("childDestructible").toBool());
QTest::qWait(1);
@@ -7244,7 +7525,7 @@ void tst_qqmlecmascript::deleteRootObjectInCreation()
{
QQmlComponent c(&engine, testFileUrl("deleteRootObjectInCreation.2.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("testConditionsMet").toBool());
delete object;
}
@@ -7258,9 +7539,9 @@ void tst_qqmlecmascript::onDestruction()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("onDestruction.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
delete obj;
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
{
@@ -7271,8 +7552,8 @@ void tst_qqmlecmascript::onDestruction()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("onDestruction.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QVERIFY(obj != nullptr);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
}
@@ -7281,8 +7562,8 @@ class WeakReferenceMutator : public QObject
Q_OBJECT
public:
WeakReferenceMutator()
- : resultPtr(Q_NULLPTR)
- , weakRef(Q_NULLPTR)
+ : resultPtr(nullptr)
+ , weakRef(nullptr)
{}
void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr)
@@ -7298,10 +7579,11 @@ public:
private slots:
void reviveFirstWeakReference() {
- *resultPtr = weakRef->valueRef() && weakRef->isNullOrUndefined();
+ // weakRef is not required to be undefined here. The gc can clear it later.
+ *resultPtr = weakRef->valueRef();
if (!*resultPtr)
return;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(this));
+ QV4::ExecutionEngine *v4 = qmlEngine(this)->handle();
weakRef->set(v4, v4->newObject());
*resultPtr = weakRef->valueRef() && !weakRef->isNullOrUndefined();
}
@@ -7351,7 +7633,7 @@ void tst_qqmlecmascript::onDestructionViaGC()
qmlRegisterType<WeakReferenceMutator>("Test", 1, 0, "WeakReferenceMutator");
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
+ QV4::ExecutionEngine *v4 =engine.handle();
QQmlComponent component(&engine, testFileUrl("DestructionHelper.qml"));
@@ -7369,7 +7651,7 @@ void tst_qqmlecmascript::onDestructionViaGC()
QVERIFY2(!weakReferenceMutator.isNull(), qPrintable(component.errorString()));
weakReferenceMutator->init(v4, weakRef.data(), &mutatorResult);
- v4->memoryManager->allocObject<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult);
+ v4->memoryManager->allocate<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult);
}
gc(engine);
@@ -7383,7 +7665,7 @@ struct EventProcessor : public QObject
public:
Q_INVOKABLE void process()
{
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
};
@@ -7398,7 +7680,7 @@ void tst_qqmlecmascript::bindingSuppression()
QQmlComponent c(&engine, testFileUrl("bindingSuppression.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
delete obj;
QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
@@ -7411,7 +7693,7 @@ void tst_qqmlecmascript::signalEmitted()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("signalEmitted.2.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QTRY_VERIFY(obj->property("success").toBool());
delete obj;
}
@@ -7421,7 +7703,7 @@ void tst_qqmlecmascript::signalEmitted()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("signalEmitted.3.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
gc(engine); // should collect c1.
QTRY_VERIFY(obj->property("success").toBool());
delete obj;
@@ -7432,7 +7714,7 @@ void tst_qqmlecmascript::signalEmitted()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("signalEmitted.4.qml"));
QObject *obj = c.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
gc(engine); // should collect c1.
QMetaObject::invokeMethod(obj, "destroyC2");
QTRY_VERIFY(obj->property("success").toBool()); // handles events (incl. delete later).
@@ -7443,38 +7725,36 @@ void tst_qqmlecmascript::signalEmitted()
// QTBUG-25647
void tst_qqmlecmascript::threadSignal()
{
+ QQmlEngine engine;
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QTRY_VERIFY(object->property("passed").toBool());
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QTRY_VERIFY(object->property("passed").toBool());
}
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QSignalSpy doneSpy(object, SIGNAL(done(QString)));
- QMetaObject::invokeMethod(object, "doIt");
- QTRY_VERIFY(object->property("passed").toBool());
- QCOMPARE(doneSpy.count(), 1);
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QMetaObject::invokeMethod(object.data(), "doIt");
+ QTRY_VERIFY(object->property("passed").toBool());
}
}
// ensure that the qqmldata::destroyed() handler doesn't cause problems
void tst_qqmlecmascript::qqmldataDestroyed()
{
+ QQmlEngine engine;
// gc cleans up a qobject, later the qqmldata destroyed handler will run.
{
QQmlComponent c(&engine, testFileUrl("qqmldataDestroyed.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// now gc causing the collection of the dynamically constructed object.
engine.collectGarbage();
engine.collectGarbage();
// now process events to allow deletion (calling qqmldata::destroyed())
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
// shouldn't crash.
delete object;
@@ -7485,7 +7765,7 @@ void tst_qqmlecmascript::qqmldataDestroyed()
{
QQmlComponent c(&engine, testFileUrl("qqmldataDestroyed.2.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("testConditionsMet").toBool());
// the gc() within the handler will have triggered the weak
// qobject reference callback. If that incorrectly disposes
@@ -7498,9 +7778,10 @@ void tst_qqmlecmascript::qqmldataDestroyed()
void tst_qqmlecmascript::secondAlias()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("secondAlias.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 200);
delete object;
}
@@ -7508,9 +7789,10 @@ void tst_qqmlecmascript::secondAlias()
// An alias to a var property works
void tst_qqmlecmascript::varAlias()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("varAlias.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 192);
delete object;
}
@@ -7518,9 +7800,10 @@ void tst_qqmlecmascript::varAlias()
// Used to trigger an assert in the lazy meta object creation stage
void tst_qqmlecmascript::overrideDataAssert()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("overrideDataAssert.qml"));
QObject *object = c.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->metaObject();
delete object;
}
@@ -7543,18 +7826,20 @@ void tst_qqmlecmascript::fallbackBindings()
{
QFETCH(QString, source);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(source));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
}
void tst_qqmlecmascript::propertyOverride()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyOverride.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
}
@@ -7587,12 +7872,13 @@ void tst_qqmlecmascript::sequenceSort()
QFETCH(QString, function);
QFETCH(bool, useComparer);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("sequenceSort.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant q;
QMetaObject::invokeMethod(object, function.toLatin1().constData(), Q_RETURN_ARG(QVariant, q), Q_ARG(QVariant, useComparer));
@@ -7603,12 +7889,13 @@ void tst_qqmlecmascript::sequenceSort()
void tst_qqmlecmascript::dateParse()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("date.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant q;
QMetaObject::invokeMethod(object, "test_is_invalid_jsDateTime", Q_RETURN_ARG(QVariant, q));
@@ -7623,12 +7910,13 @@ void tst_qqmlecmascript::dateParse()
void tst_qqmlecmascript::utcDate()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("utcdate.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant q;
QVariant val = QString::fromLatin1("2014-07-16T23:30:31");
@@ -7638,12 +7926,13 @@ void tst_qqmlecmascript::utcDate()
void tst_qqmlecmascript::negativeYear()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("negativeyear.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant q;
QMetaObject::invokeMethod(object, "check_negative_tostring", Q_RETURN_ARG(QVariant, q));
@@ -7659,6 +7948,7 @@ void tst_qqmlecmascript::negativeYear()
void tst_qqmlecmascript::concatenatedStringPropertyAccess()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("concatenatedStringPropertyAccess.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -7704,19 +7994,21 @@ void tst_qqmlecmascript::updateCall()
// documented it can be called from within QML. Make sure
// we don't crash when calling it.
QString file("updateCall.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(file));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlecmascript::numberParsing()
{
+ QQmlEngine engine;
for (int i = 1; i < 8; ++i) {
QString file("numberParsing.%1.qml");
file = file.arg(i);
QQmlComponent component(&engine, testFileUrl(file));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
for (int i = 1; i < 3; ++i) {
QString file("numberParsing_error.%1.qml");
@@ -7728,6 +8020,7 @@ void tst_qqmlecmascript::numberParsing()
void tst_qqmlecmascript::stringParsing()
{
+ QQmlEngine engine;
for (int i = 1; i < 7; ++i) {
QString file("stringParsing_error.%1.qml");
file = file.arg(i);
@@ -7751,10 +8044,11 @@ void tst_qqmlecmascript::push_and_shift()
void tst_qqmlecmascript::qtbug_32801()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_32801.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
// do not crash when a QML signal is connected to a non-void slot
connect(obj.data(), SIGNAL(testSignal(QString)), obj.data(), SLOT(slotWithReturnValue(QString)));
@@ -7763,6 +8057,7 @@ void tst_qqmlecmascript::qtbug_32801()
void tst_qqmlecmascript::thisObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("thisObject.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -7772,21 +8067,23 @@ void tst_qqmlecmascript::thisObject()
void tst_qqmlecmascript::qtbug_33754()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_33754.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
}
void tst_qqmlecmascript::qtbug_34493()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_34493.qml"));
QScopedPointer<QObject> obj(component.create());
if (component.errors().size())
qDebug() << component.errors();
QVERIFY(component.errors().isEmpty());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVERIFY(QMetaObject::invokeMethod(obj.data(), "doIt"));
QTRY_VERIFY(obj->property("prop").toString() == QLatin1String("Hello World!"));
}
@@ -7795,12 +8092,13 @@ void tst_qqmlecmascript::qtbug_34493()
// as its type*, it's parent type* and as QObject*
void tst_qqmlecmascript::singletonFromQMLToCpp()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFile("singletonTest.qml"));
QScopedPointer<QObject> obj(component.create());
if (component.errors().size())
qDebug() << component.errors();
QVERIFY(component.errors().isEmpty());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("qobjectTest"), QVariant(true));
QCOMPARE(obj->property("myQmlObjectTest"), QVariant(true));
@@ -7812,12 +8110,13 @@ void tst_qqmlecmascript::singletonFromQMLToCpp()
// and correctly compares to itself
void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFile("singletonTest2.qml"));
QScopedPointer<QObject> o(component.create());
if (component.errors().size())
qDebug() << component.errors();
QVERIFY(component.errors().isEmpty());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("myInheritedQmlObjectTest1"), QVariant(true));
QCOMPARE(o->property("myInheritedQmlObjectTest2"), QVariant(true));
@@ -7836,9 +8135,10 @@ void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
void tst_qqmlecmascript::setPropertyOnInvalid()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("setPropertyOnNull.qml"));
- QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QString warning = component.url().toString() + ":4: TypeError: Value is null and could not be converted to an object";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
QVERIFY(object);
@@ -7847,7 +8147,7 @@ void tst_qqmlecmascript::setPropertyOnInvalid()
{
QQmlComponent component(&engine, testFileUrl("setPropertyOnUndefined.qml"));
- QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QString warning = component.url().toString() + ":4: TypeError: Value is undefined and could not be converted to an object";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
QVERIFY(object);
@@ -7857,12 +8157,13 @@ void tst_qqmlecmascript::setPropertyOnInvalid()
void tst_qqmlecmascript::miscTypeTest()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("misctypetest.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant q;
QMetaObject::invokeMethod(object, "test_invalid_url_equal", Q_RETURN_ARG(QVariant, q));
@@ -7885,6 +8186,7 @@ void tst_qqmlecmascript::stackLimits()
void tst_qqmlecmascript::idsAsLValues()
{
+ QQmlEngine engine;
QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString());
QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
@@ -7895,17 +8197,19 @@ void tst_qqmlecmascript::idsAsLValues()
void tst_qqmlecmascript::qtbug_34792()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug34792.qml"));
QObject *object = component.create();
- if (object == 0)
+ if (object == nullptr)
qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
void tst_qqmlecmascript::noCaptureWhenWritingProperty()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("noCaptureWhenWritingProperty.qml"));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
@@ -7914,6 +8218,7 @@ void tst_qqmlecmascript::noCaptureWhenWritingProperty()
void tst_qqmlecmascript::singletonWithEnum()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonWithEnum.qml"));
QScopedPointer<QObject> obj(component.create());
if (obj.isNull())
@@ -7922,52 +8227,66 @@ void tst_qqmlecmascript::singletonWithEnum()
QVariant prop = obj->property("testValue");
QCOMPARE(prop.type(), QVariant::Int);
QCOMPARE(prop.toInt(), int(SingletonWithEnum::TestValue));
+
+ {
+ QQmlExpression expr(qmlContext(obj.data()), obj.data(), "SingletonWithEnum.TestValue_MinusOne");
+ bool valueUndefined = false;
+ QVariant result = expr.evaluate(&valueUndefined);
+ QVERIFY2(!expr.hasError(), qPrintable(expr.error().toString()));
+ QVERIFY(!valueUndefined);
+ QCOMPARE(result.toInt(), -1);
+ }
}
void tst_qqmlecmascript::lazyBindingEvaluation()
{
- QQmlComponent component(&engine, testFileUrl("lazyBindingEvaluation.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("lazyBindingEvaluation.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QVariant prop = obj->property("arrayLength");
- QCOMPARE(prop.type(), QVariant::Int);
- QCOMPARE(prop.toInt(), 2);
+ QVERIFY(!obj.isNull());
+ QVariant prop = obj->property("arrayLength");
+ QCOMPARE(prop.type(), QVariant::Int);
+ QCOMPARE(prop.toInt(), 2);
}
void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext()
{
- QQmlComponent component(&engine, testFileUrl("varPropertyAccessOnObjectWithInvalidContext.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("varPropertyAccessOnObjectWithInvalidContext.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QVERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::importedScriptsAccessOnObjectWithInvalidContext()
{
- QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QTRY_VERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::importedScriptsWithoutQmlMode()
{
- QQmlComponent component(&engine, testFileUrl("importScriptsWithoutQmlMode.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("importScriptsWithoutQmlMode.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QTRY_VERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::contextObjectOnLazyBindings()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("contextObjectOnLazyBindings.qml"));
QScopedPointer<QObject> obj(component.create());
if (obj.isNull())
@@ -7980,6 +8299,7 @@ void tst_qqmlecmascript::contextObjectOnLazyBindings()
void tst_qqmlecmascript::garbageCollectionDuringCreation()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import Qt.test 1.0\n"
"QObjectContainerWithGCOnAppend {\n"
@@ -8007,6 +8327,7 @@ void tst_qqmlecmascript::garbageCollectionDuringCreation()
void tst_qqmlecmascript::qtbug_39520()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\n"
"Item {\n"
@@ -8045,7 +8366,7 @@ class ObjectContainer : public QObject
Q_PROPERTY(ContainedObject1 *object1 READ object1 WRITE setObject1)
Q_PROPERTY(ContainedObject2 *object2 READ object2 WRITE setObject2)
public:
- explicit ObjectContainer(QObject *parent = 0) :
+ explicit ObjectContainer(QObject *parent = nullptr) :
QObject(parent),
mGetterCalled(false),
mSetterCalled(false)
@@ -8055,7 +8376,7 @@ public:
ContainedObject1 *object1()
{
mGetterCalled = true;
- return 0;
+ return nullptr;
}
void setObject1(ContainedObject1 *)
@@ -8066,7 +8387,7 @@ public:
ContainedObject2 *object2()
{
mGetterCalled = true;
- return 0;
+ return nullptr;
}
void setObject2(ContainedObject2 *)
@@ -8128,16 +8449,18 @@ void tst_qqmlecmascript::switchExpression()
void tst_qqmlecmascript::qtbug_46022()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_46022.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("test1").toBool(), true);
QCOMPARE(obj->property("test2").toBool(), true);
}
void tst_qqmlecmascript::qtbug_52340()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_52340.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -8149,10 +8472,11 @@ void tst_qqmlecmascript::qtbug_52340()
void tst_qqmlecmascript::qtbug_54589()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("result").toBool(), true);
}
@@ -8160,16 +8484,18 @@ void tst_qqmlecmascript::qtbug_54687()
{
QJSEngine e;
// it's simple: this shouldn't crash.
- engine.evaluate("12\n----12");
+ e.evaluate("12\n----12");
}
void tst_qqmlecmascript::stringify_qtbug_50592()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringify_qtbug_50592.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
- QCOMPARE(obj->property("source").toString(), QString::fromLatin1("http://example.org/some_nonexistant_image.png"));
+ QVERIFY(obj != nullptr);
+ QCOMPARE(obj->property("source").toString(),
+ QString::fromLatin1("\"http://example.org/some_nonexistant_image.png\""));
}
// Tests for the JS-only instanceof. Tests for the QML extensions for
@@ -8226,7 +8552,7 @@ void tst_qqmlecmascript::instanceof()
QJSEngine engine;
QJSValue ret = engine.evaluate(setupCode + ";\n" + QTest::currentDataTag());
- if (expectedValue.type() == QMetaType::Bool) {
+ if (expectedValue.type() == QVariant::Bool) {
bool returnValue = ret.toBool();
QVERIFY2(!ret.isError(), qPrintable(ret.toString()));
QCOMPARE(returnValue, expectedValue.toBool());
@@ -8352,10 +8678,11 @@ void tst_qqmlecmascript::freeze_empty_object()
void tst_qqmlecmascript::singleBlockLoops()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_59012.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVERIFY(!component.isError());
}
@@ -8363,12 +8690,249 @@ void tst_qqmlecmascript::singleBlockLoops()
// This fix ensures it looks up the right thing.
void tst_qqmlecmascript::qtbug_60547()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug60547/main.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
QCOMPARE(object->property("counter"), QVariant(int(1)));
}
+void tst_qqmlecmascript::anotherNaN()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("nans.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+ object->setProperty("prop", std::numeric_limits<double>::quiet_NaN()); // don't crash
+
+ std::uint64_t anotherNaN = 0xFFFFFF01000000F7ul;
+ double d;
+ std::memcpy(&d, &anotherNaN, sizeof(d));
+ QVERIFY(std::isnan(d));
+ object->setProperty("prop", d); // don't crash
+}
+
+void tst_qqmlecmascript::delayLoadingArgs()
+{
+ QJSEngine engine;
+ QJSValue ret = engine.evaluate("(function(x){return x + (x+=2)})(20)");
+ QCOMPARE(ret.toInt(), 42); // esp. not 44.
+}
+
+void tst_qqmlecmascript::manyArguments()
+{
+ const char *testCase =
+ "function x() { var sum; for (var i = 0; i < arguments.length; ++i) sum += arguments[i][0]; }"
+ "x([0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9])";
+
+ QJSEngine engine;
+ engine.evaluate(testCase);
+}
+
+void tst_qqmlecmascript::forInIterator()
+{
+ auto testCase =
+ "(function(){\n"
+ "var x = 'yoyo'\n"
+ "var i\n"
+ "for (i in x) {\n"
+ "}\n"
+ "return i\n"
+ "})()";
+ QJSEngine engine;
+ QJSValue ret = engine.evaluate(testCase);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QStringLiteral("3"));
+}
+
+void tst_qqmlecmascript::localForInIterator()
+{
+ auto testCase =
+ "(function(){\n"
+ "var x = 'yoyo'\n"
+ "for (var i in x) {\n"
+ "}\n"
+ "return i\n"
+ "})()";
+ QJSEngine engine;
+ QJSValue ret = engine.evaluate(testCase);
+ QVERIFY(ret.isString());
+ QCOMPARE(ret.toString(), QStringLiteral("3"));
+}
+
+void tst_qqmlecmascript::shadowedFunctionName()
+{
+ // verify that arguments shadow the function name
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1(
+ "function f(f) { return f; }\n"
+ "f(true)\n"
+ ));
+ QVERIFY(!v.isError());
+ QVERIFY(v.isBool());
+ QCOMPARE(v.toBool(), true);
+}
+
+void tst_qqmlecmascript::callPropertyOnUndefined()
+{
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1(
+ "function f() {\n"
+ " var base;\n"
+ " base.push(1);"
+ "}\n"
+ ));
+ QVERIFY(!v.isError()); // well, more importantly: this shouldn't fail on an assert.
+}
+
+void tst_qqmlecmascript::jumpStrictNotEqualUndefined()
+{
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1(
+ "var ok = 0\n"
+ "var foo = 0\n"
+ "if (foo !== void 1)\n"
+ " ++ok;\n"
+ "else\n"
+ " --ok;\n"
+ "if (foo === void 1)\n"
+ " --ok;\n"
+ "else\n"
+ " ++ok;\n"
+ "ok\n"
+ ));
+ QVERIFY(!v.isError());
+ QCOMPARE(v.toInt(), 2);
+}
+
+void tst_qqmlecmascript::removeBindingsWithNoDependencies()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("removeBindingsWithNoDependencies.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QVariant rect = object->property("placement");
+ QCOMPARE(rect.toRectF(), QRectF(0, 0, 100, 100));
+ const QMetaObject *metaObject = object->metaObject();
+
+ {
+ const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("placement"));
+ QVERIFY(prop.isValid());
+ QVERIFY(!QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex())));
+ }
+
+ {
+ const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("partialPlacement"));
+ QVERIFY(prop.isValid());
+ QQmlAbstractBinding *vtProxyBinding = QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex()));
+ QVERIFY(vtProxyBinding);
+ QVERIFY(vtProxyBinding->isValueTypeProxy());
+
+ QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding*>(vtProxyBinding);
+ QVERIFY(!proxy->subBindings());
+ }
+
+}
+
+void tst_qqmlecmascript::temporaryDeadZone()
+{
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1("a; let a;"));
+ QVERIFY(v.isError());
+ v = engine.evaluate(QString::fromLatin1("a.name; let a;"));
+ QVERIFY(v.isError());
+ v = engine.evaluate(QString::fromLatin1("var a = {}; a[b]; let b;"));
+ QVERIFY(v.isError());
+ v = engine.evaluate(QString::fromLatin1("class C { constructor() { super[x]; let x; } }; new C()"));
+ QVERIFY(v.isError());
+}
+
+void tst_qqmlecmascript::importLexicalVariables_data()
+{
+ QTest::addColumn<QUrl>("testFile");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("script")
+ << testFileUrl("importLexicalVariables_script.qml")
+ << QStringLiteral("000 100 210");
+ QTest::newRow("pragmaLibrary")
+ << testFileUrl("importLexicalVariables_pragmaLibrary.qml")
+ << QStringLiteral("000 100 210");
+ QTest::newRow("module")
+ << testFileUrl("importLexicalVariables_module.qml")
+ << QStringLiteral("000 000 110");
+}
+
+void tst_qqmlecmascript::importLexicalVariables()
+{
+ QFETCH(QUrl, testFile);
+ QFETCH(QString, expected);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFile);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QVERIFY(!component.isError());
+
+ QVariant result;
+ QMetaObject::invokeMethod(object.data(), "runTest", Qt::DirectConnection, Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result, QVariant(expected));
+}
+
+void tst_qqmlecmascript::hugeObject()
+{
+ // mainly check that this doesn't crash
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1(
+ "var known = {}, prefix = 'x'\n"
+ "for (var i = 0; i < 150000; i++) known[prefix + i] = true;"
+ ));
+ QVERIFY(!v.isError());
+}
+
+void tst_qqmlecmascript::templateStringTerminator()
+{
+ QJSEngine engine;
+ const QJSValue value = engine.evaluate("let a = 123; let b = `x${a}\ny^`; b;");
+ QVERIFY(!value.isError());
+ QCOMPARE(value.toString(), QLatin1String("x123\ny^"));
+}
+
+void tst_qqmlecmascript::arrayAndException()
+{
+ QJSEngine engine;
+ const QJSValue value = engine.evaluate("[...[],[,,$]]");
+ // Should not crash
+ QVERIFY(value.isError());
+}
+
+void tst_qqmlecmascript::numberToStringWithRadix()
+{
+ QJSEngine engine;
+ {
+ const QJSValue value = engine.evaluate(".5.toString(5)");
+ QVERIFY(!value.isError());
+ QVERIFY(value.toString().startsWith("0.2222222222"));
+ }
+ {
+ const QJSValue value = engine.evaluate(".05.toString(5)");
+ QVERIFY(!value.isError());
+ QVERIFY(value.toString().startsWith("0.01111111111"));
+ }
+}
+
+void tst_qqmlecmascript::tailCallWithArguments()
+{
+ QJSEngine engine;
+ const QJSValue value = engine.evaluate(
+ "'use strict';\n"
+ "[[1, 2]].map(function (a) {\n"
+ " return (function() { return Math.min.apply(this, arguments); })(a[0], a[1]);\n"
+ "})[0];");
+ QVERIFY(!value.isError());
+ QCOMPARE(value.toInt(), 1);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml
new file mode 100644
index 0000000000..1047926750
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.8
+
+Item {
+ property alias textEdit: textEdit
+
+ TextEdit {
+ id: textEdit
+
+ }
+}
diff --git a/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml
new file mode 100644
index 0000000000..552c6c3791
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Item {
+ property alias textEdit: textEdit
+
+ TextEdit {
+ id: textEdit
+
+ }
+}
diff --git a/tests/auto/qml/qqmlengine/data/qrcurls.js b/tests/auto/qml/qqmlengine/data/qrcurls.js
new file mode 100644
index 0000000000..15a4d5a70c
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/qrcurls.js
@@ -0,0 +1 @@
+function someFunction() {}
diff --git a/tests/auto/qml/qqmlengine/data/qrcurls.qml b/tests/auto/qml/qqmlengine/data/qrcurls.qml
new file mode 100644
index 0000000000..e879577e10
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/qrcurls.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+
+QtObject {
+}
diff --git a/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml
new file mode 100644
index 0000000000..39bd01fe40
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.8
+
+Item {
+ GroupedPropertiesRevisionComponent1 {
+ textEdit.onEditingFinished: console.log("test")
+ }
+}
diff --git a/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml
new file mode 100644
index 0000000000..bb9ba79b01
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.8
+
+Item {
+ GroupedPropertiesRevisionComponent2 {
+ textEdit.onEditingFinished: console.log("test")
+ }
+}
diff --git a/tests/auto/qml/qqmlengine/qqmlengine.pro b/tests/auto/qml/qqmlengine/qqmlengine.pro
index e7952d8e3a..d2eb92bfd5 100644
--- a/tests/auto/qml/qqmlengine/qqmlengine.pro
+++ b/tests/auto/qml/qqmlengine/qqmlengine.pro
@@ -7,3 +7,12 @@ include (../../shared/util.pri)
SOURCES += tst_qqmlengine.cpp
QT += core-private gui-private qml-private network testlib
+
+boot2qt: {
+ # GC corruption test is too heavy for qemu-arm
+ DEFINES += SKIP_GCCORRUPTION_TEST
+}
+
+RESOURCES += \
+ data/qrcurls.qml \
+ data/qrcurls.js
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 07569efc72..f58ae38264 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -41,6 +41,7 @@
#include <QQmlNetworkAccessManagerFactory>
#include <QQmlExpression>
#include <QQmlIncubationController>
+#include <QTemporaryDir>
#include <private/qqmlengine_p.h>
#include <QQmlAbstractUrlInterceptor>
@@ -51,6 +52,7 @@ public:
tst_qqmlengine() {}
private slots:
+ void initTestCase() override;
void rootContext();
void networkAccessManager();
void synchronousNetworkAccessManager();
@@ -73,6 +75,11 @@ private slots:
void urlInterceptor();
void qmlContextProperties();
void testGCCorruption();
+ void testGroupedPropertyRevisions();
+ void componentFromEval();
+ void qrcUrls();
+ void cppSignalAndEval();
+ void singletonInstance();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -80,8 +87,17 @@ public slots:
static QObject *ptr = new QObject();
return ptr;
}
+
+private:
+ QTemporaryDir m_tempDir;
};
+void tst_qqmlengine::initTestCase()
+{
+ QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
+ QQmlDataTest::initTestCase();
+}
+
void tst_qqmlengine::rootContext()
{
QQmlEngine engine;
@@ -95,7 +111,7 @@ void tst_qqmlengine::rootContext()
class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
{
public:
- NetworkAccessManagerFactory() : manager(0) {}
+ NetworkAccessManagerFactory() : manager(nullptr) {}
QNetworkAccessManager *create(QObject *parent) {
manager = new QNetworkAccessManager(parent);
@@ -111,7 +127,7 @@ void tst_qqmlengine::networkAccessManager()
// Test QQmlEngine created manager
QPointer<QNetworkAccessManager> manager = engine->networkAccessManager();
- QVERIFY(manager != 0);
+ QVERIFY(manager != nullptr);
delete engine;
// Test factory created manager
@@ -143,10 +159,10 @@ class ImmediateManager : public QNetworkAccessManager {
Q_OBJECT
public:
- ImmediateManager(QObject *parent = 0) : QNetworkAccessManager(parent) {
+ ImmediateManager(QObject *parent = nullptr) : QNetworkAccessManager(parent) {
}
- QNetworkReply *createRequest(Operation, const QNetworkRequest & , QIODevice * outgoingData = 0) {
+ QNetworkReply *createRequest(Operation, const QNetworkRequest & , QIODevice * outgoingData = nullptr) {
Q_UNUSED(outgoingData);
return new ImmediateReply;
}
@@ -200,17 +216,17 @@ void tst_qqmlengine::contextForObject()
QQmlEngine *engine = new QQmlEngine;
// Test null-object
- QVERIFY(!QQmlEngine::contextForObject(0));
+ QVERIFY(!QQmlEngine::contextForObject(nullptr));
// Test an object with no context
QObject object;
QVERIFY(!QQmlEngine::contextForObject(&object));
// Test setting null-object
- QQmlEngine::setContextForObject(0, engine->rootContext());
+ QQmlEngine::setContextForObject(nullptr, engine->rootContext());
// Test setting null-context
- QQmlEngine::setContextForObject(&object, 0);
+ QQmlEngine::setContextForObject(&object, nullptr);
// Test setting context
QQmlEngine::setContextForObject(&object, engine->rootContext());
@@ -224,7 +240,7 @@ void tst_qqmlengine::contextForObject()
QCOMPARE(QQmlEngine::contextForObject(&object), engine->rootContext());
// Delete context
- delete engine; engine = 0;
+ delete engine; engine = nullptr;
QVERIFY(!QQmlEngine::contextForObject(&object));
}
@@ -286,9 +302,12 @@ void tst_qqmlengine::clearComponentCache()
{
QQmlEngine engine;
+ const QString fileName = m_tempDir.filePath(QStringLiteral("temp.qml"));
+ const QUrl fileUrl = QUrl::fromLocalFile(fileName);
+
// Create original qml file
{
- QFile file("temp.qml");
+ QFile file(fileName);
QVERIFY(file.open(QIODevice::WriteOnly));
file.write("import QtQuick 2.0\nQtObject {\nproperty int test: 10\n}\n");
file.close();
@@ -296,9 +315,9 @@ void tst_qqmlengine::clearComponentCache()
// Test "test" property
{
- QQmlComponent component(&engine, "temp.qml");
+ QQmlComponent component(&engine, fileUrl);
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("test").toInt(), 10);
delete obj;
}
@@ -311,7 +330,7 @@ void tst_qqmlengine::clearComponentCache()
// Similar effects of lacking precision have been observed on some Linux systems.
QThread::sleep(1);
- QFile file("temp.qml");
+ QFile file(fileName);
QVERIFY(file.open(QIODevice::WriteOnly));
file.write("import QtQuick 2.0\nQtObject {\nproperty int test: 11\n}\n");
file.close();
@@ -319,9 +338,9 @@ void tst_qqmlengine::clearComponentCache()
// Test cache hit
{
- QQmlComponent component(&engine, "temp.qml");
+ QQmlComponent component(&engine, fileUrl);
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("test").toInt(), 10);
delete obj;
}
@@ -331,12 +350,18 @@ void tst_qqmlengine::clearComponentCache()
// Test cache refresh
{
- QQmlComponent component(&engine, "temp.qml");
+ QQmlComponent component(&engine, fileUrl);
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("test").toInt(), 11);
delete obj;
}
+
+ // Regular Synchronous loading will leave us with an event posted
+ // to the gui thread and an extra refcount that will only be dropped after the
+ // event delivery. Call sendPostedEvents() to get rid of it so that
+ // the temporary directory can be removed.
+ QCoreApplication::sendPostedEvents();
}
struct ComponentCacheFunctions : public QObject, public QQmlIncubationController
@@ -350,7 +375,7 @@ public:
Q_INVOKABLE void trim()
{
// Wait for any pending deletions to occur
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
// There might be JS function objects around that hold a last ref to the compilation unit that's
@@ -402,7 +427,7 @@ void tst_qqmlengine::trimComponentCache()
QQmlComponent component(&engine, testFileUrl(file));
QVERIFY(component.isReady());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
}
@@ -471,7 +496,7 @@ void tst_qqmlengine::repeatedCompilation()
QQmlComponent component(&engine, testFileUrl("repeatedCompilation.qml"));
QVERIFY(component.isReady());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
}
}
@@ -515,11 +540,11 @@ void tst_qqmlengine::outputWarningsToStandardError()
QObject *o = c.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
delete o;
QCOMPARE(messageHandler.messages().count(), 1);
- QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:48: Unable to assign [undefined] to int"));
+ QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:32: Unable to assign [undefined] to int"));
messageHandler.clear();
engine.setOutputWarningsToStandardError(false);
@@ -527,7 +552,7 @@ void tst_qqmlengine::outputWarningsToStandardError()
o = c.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
delete o;
QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
@@ -536,9 +561,9 @@ void tst_qqmlengine::outputWarningsToStandardError()
void tst_qqmlengine::objectOwnership()
{
{
- QCOMPARE(QQmlEngine::objectOwnership(0), QQmlEngine::CppOwnership);
- QQmlEngine::setObjectOwnership(0, QQmlEngine::JavaScriptOwnership);
- QCOMPARE(QQmlEngine::objectOwnership(0), QQmlEngine::CppOwnership);
+ QCOMPARE(QQmlEngine::objectOwnership(nullptr), QQmlEngine::CppOwnership);
+ QQmlEngine::setObjectOwnership(nullptr, QQmlEngine::JavaScriptOwnership);
+ QCOMPARE(QQmlEngine::objectOwnership(nullptr), QQmlEngine::CppOwnership);
}
{
@@ -558,7 +583,7 @@ void tst_qqmlengine::objectOwnership()
c.setData("import QtQuick 2.0; QtObject { property QtObject object: QtObject {} }", QUrl());
QObject *o = c.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QCOMPARE(QQmlEngine::objectOwnership(o), QQmlEngine::CppOwnership);
@@ -578,7 +603,7 @@ void tst_qqmlengine::objectOwnership()
c.setData("import QtQuick 2.0; Item { property int data: test.createAQObjectForOwnershipTest() ? 0 : 1 }", QUrl());
QVERIFY(c.isReady());
QObject *o = c.create();
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
}
QTRY_VERIFY(spy.count());
}
@@ -593,8 +618,8 @@ void tst_qqmlengine::objectOwnership()
c.setData("import QtQuick 2.0; QtObject { property var object: { var i = test; test ? 0 : 1 } }", QUrl());
QVERIFY(c.isReady());
QObject *o = c.create();
- QVERIFY(o != 0);
- engine.rootContext()->setContextProperty("test", 0);
+ QVERIFY(o != nullptr);
+ engine.rootContext()->setContextProperty("test", nullptr);
}
QTRY_VERIFY(spy.count());
}
@@ -613,8 +638,8 @@ void tst_qqmlengine::multipleEngines()
engine1.rootContext()->setContextProperty("object", &o);
engine2.rootContext()->setContextProperty("object", &o);
- QQmlExpression expr1(engine1.rootContext(), 0, QString("object.objectName"));
- QQmlExpression expr2(engine2.rootContext(), 0, QString("object.objectName"));
+ QQmlExpression expr1(engine1.rootContext(), nullptr, QString("object.objectName"));
+ QQmlExpression expr2(engine2.rootContext(), nullptr, QString("object.objectName"));
QCOMPARE(expr1.evaluate().toString(), QString("TestName"));
QCOMPARE(expr2.evaluate().toString(), QString("TestName"));
@@ -624,13 +649,13 @@ void tst_qqmlengine::multipleEngines()
{
QQmlEngine engine1;
engine1.rootContext()->setContextProperty("object", &o);
- QQmlExpression expr1(engine1.rootContext(), 0, QString("object.objectName"));
+ QQmlExpression expr1(engine1.rootContext(), nullptr, QString("object.objectName"));
QCOMPARE(expr1.evaluate().toString(), QString("TestName"));
}
{
QQmlEngine engine1;
engine1.rootContext()->setContextProperty("object", &o);
- QQmlExpression expr1(engine1.rootContext(), 0, QString("object.objectName"));
+ QQmlExpression expr1(engine1.rootContext(), nullptr, QString("object.objectName"));
QCOMPARE(expr1.evaluate().toString(), QString("TestName"));
}
}
@@ -721,6 +746,9 @@ public:
if (url.path().endsWith("Test.2/qmldir"))//Special case
return QUrl::fromLocalFile(m_base.path() + "interception/module/intercepted/qmldir");
+ // 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;
QString alteredPath = url.path();
int a = alteredPath.lastIndexOf('/');
@@ -839,6 +867,10 @@ void tst_qqmlengine::qmlContextProperties()
void tst_qqmlengine::testGCCorruption()
{
+#ifdef SKIP_GCCORRUPTION_TEST
+ QSKIP("Test too heavy for qemu");
+#endif
+
QQmlEngine e;
QQmlComponent c(&e, testFileUrl("testGCCorruption.qml"));
@@ -846,6 +878,171 @@ void tst_qqmlengine::testGCCorruption()
QVERIFY2(o, qPrintable(c.errorString()));
}
+void tst_qqmlengine::testGroupedPropertyRevisions()
+{
+ QQmlEngine e;
+
+ QQmlComponent c(&e, testFileUrl("testGroupedPropertiesRevision.1.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY2(object.data(), qPrintable(c.errorString()));
+ QQmlComponent c2(&e, testFileUrl("testGroupedPropertiesRevision.2.qml"));
+ QVERIFY(!c2.errorString().isEmpty());
+}
+
+void tst_qqmlengine::componentFromEval()
+{
+ QQmlEngine engine;
+ const QUrl testUrl = testFileUrl("EmptyComponent.qml");
+ QJSValue result = engine.evaluate("Qt.createComponent(\"" + testUrl.toString() + "\");");
+ QPointer<QQmlComponent> component(qobject_cast<QQmlComponent*>(result.toQObject()));
+ QVERIFY(!component.isNull());
+ QScopedPointer<QObject> item(component->create());
+ QVERIFY(!item.isNull());
+}
+
+void tst_qqmlengine::qrcUrls()
+{
+ QQmlEngine engine;
+ QQmlEnginePrivate *pEngine = QQmlEnginePrivate::get(&engine);
+
+ {
+ QQmlRefPointer<QQmlTypeData> oneQml(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.qml")));
+ QVERIFY(oneQml.data() != nullptr);
+ QQmlRefPointer<QQmlTypeData> twoQml(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.qml")));
+ QVERIFY(twoQml.data() != nullptr);
+ QCOMPARE(oneQml.data(), twoQml.data());
+ }
+
+ {
+ QQmlRefPointer<QQmlTypeData> oneJS(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.js")));
+ QVERIFY(oneJS.data() != nullptr);
+ QQmlRefPointer<QQmlTypeData> twoJS(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.js")));
+ QVERIFY(twoJS.data() != nullptr);
+ QCOMPARE(oneJS.data(), twoJS.data());
+ }
+}
+
+class ObjectCaller : public QObject
+{
+ Q_OBJECT
+signals:
+ void doubleReply(const double a);
+};
+
+void tst_qqmlengine::cppSignalAndEval()
+{
+ ObjectCaller objectCaller;
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty(QLatin1Literal("CallerCpp"), &objectCaller);
+ QQmlComponent c(&engine);
+ c.setData("import QtQuick 2.9\n"
+ "Item {\n"
+ " property var r: 0\n"
+ " Connections {\n"
+ " target: CallerCpp;\n"
+ " onDoubleReply: {\n"
+ " eval('var z = 1');\n"
+ " r = a;\n"
+ " }\n"
+ " }\n"
+ "}",
+ QUrl(QStringLiteral("qrc:/main.qml")));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ emit objectCaller.doubleReply(1.1234);
+ QCOMPARE(object->property("r"), 1.1234);
+}
+
+class CppSingleton : public QObject {
+ Q_OBJECT
+public:
+ CppSingleton() {}
+
+ static QObject *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
+ {
+ Q_UNUSED(qmlEngine);
+ Q_UNUSED(jsEngine);
+ return new CppSingleton();
+ }
+};
+
+class JsSingleton : public QObject {
+ Q_OBJECT
+public:
+ JsSingleton() {}
+
+ static QJSValue create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
+ {
+ Q_UNUSED(qmlEngine);
+ QJSValue value = jsEngine->newQObject(new JsSingleton());
+ return value;
+ }
+};
+
+class SomeQObjectClass : public QObject {
+ Q_OBJECT
+public:
+ SomeQObjectClass() : QObject(nullptr){}
+};
+
+void tst_qqmlengine::singletonInstance()
+{
+ QQmlEngine engine;
+
+ int cppSingletonTypeId = qmlRegisterSingletonType<CppSingleton>("Test", 1, 0, "CppSingleton", &CppSingleton::create);
+ int jsValueSingletonTypeId = qmlRegisterSingletonType("Test", 1, 0, "JsSingleton", &JsSingleton::create);
+
+ {
+ // Cpp QObject singleton type
+ QJSValue value = engine.singletonInstance<QJSValue>(cppSingletonTypeId);
+ QVERIFY(!value.isUndefined());
+ QVERIFY(value.isQObject());
+ QObject *instance = value.toQObject();
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+ }
+
+ {
+ // QJSValue QObject singleton type
+ QJSValue value = engine.singletonInstance<QJSValue>(jsValueSingletonTypeId);
+ QVERIFY(!value.isUndefined());
+ QVERIFY(value.isQObject());
+ QObject *instance = value.toQObject();
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "JsSingleton");
+ }
+
+ {
+ // Invalid types
+ QJSValue value;
+ value = engine.singletonInstance<QJSValue>(-4711);
+ QVERIFY(value.isUndefined());
+ value = engine.singletonInstance<QJSValue>(1701);
+ QVERIFY(value.isUndefined());
+ }
+
+ {
+ // Valid, but non-singleton type
+ int typeId = qmlRegisterType<CppSingleton>("Test", 1, 0, "NotASingleton");
+ QJSValue value = engine.singletonInstance<QJSValue>(typeId);
+ QVERIFY(value.isUndefined());
+ }
+
+ {
+ // Cpp QObject singleton type
+ CppSingleton *instance = engine.singletonInstance<CppSingleton*>(cppSingletonTypeId);
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+ QCOMPARE(instance, engine.singletonInstance<QJSValue>(cppSingletonTypeId).toQObject());
+ }
+
+ {
+ // Wrong destination type
+ SomeQObjectClass * instance = engine.singletonInstance<SomeQObjectClass*>(cppSingletonTypeId);
+ QVERIFY(!instance);
+ }
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
index 5bcec9f5b4..90508609a8 100644
--- a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
+++ b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
@@ -6,4 +6,4 @@ include (../../shared/util.pri)
SOURCES += tst_qqmlenginecleanup.cpp
-QT += testlib qml
+QT += testlib qml qml-private
diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
index d0a8b6401f..b9cede6d13 100644
--- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
+++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
@@ -31,6 +31,8 @@
#include <QtQml/qqml.h>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
+#include <private/qhashedstring_p.h>
+#include <private/qqmlmetatype_p.h>
//Separate test, because if engine cleanup attempts fail they can easily break unrelated tests
class tst_qqmlenginecleanup : public QQmlDataTest
@@ -44,41 +46,82 @@ private slots:
void test_valueTypeProviderModule(); // QTBUG-43004
};
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
void tst_qqmlenginecleanup::test_qmlClearTypeRegistrations()
{
//Test for preventing memory leaks is in tests/manual/qmltypememory
QQmlEngine* engine;
- QQmlComponent* component;
+ CleanlyLoadingComponent* component;
QUrl testFile = testFileUrl("types.qml");
+ const auto qmlTypeForTestType = []() {
+ return QQmlMetaType::qmlType(QStringLiteral("TestTypeCpp"), QStringLiteral("Test"), 2, 0);
+ };
+
+ QVERIFY(!qmlTypeForTestType().isValid());
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
+
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
- qmlClearTypeRegistrations();
+ delete engine;
+
+ {
+ auto cppType = qmlTypeForTestType();
+
+ qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
+
+ // cppType should hold the last ref, qmlClearTypeRegistration should have wiped
+ // all internal references.
+ QCOMPARE(QQmlType::refCount(cppType.priv()), 1);
+ }
//2nd run verifies that types can reload after a qmlClearTypeRegistrations
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
+ delete engine;
qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
//3nd run verifies that TestTypeCpp is no longer registered
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isError());
QCOMPARE(component->errorString(),
testFile.toString() +":33 module \"Test\" is not installed\n");
- delete engine;
delete component;
+ delete engine;
}
static void cleanState(QQmlEngine **e)
@@ -86,7 +129,7 @@ static void cleanState(QQmlEngine **e)
delete *e;
qmlClearTypeRegistrations();
*e = new QQmlEngine;
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
}
@@ -96,7 +139,7 @@ void tst_qqmlenginecleanup::test_valueTypeProviderModule()
// provider can be reinitialized after multiple calls to
// qmlClearTypeRegistrations() without causing cycles in the
// value type provider list.
- QQmlEngine *e = 0;
+ QQmlEngine *e = nullptr;
QUrl testFile1 = testFileUrl("testFile1.qml");
QUrl testFile2 = testFileUrl("testFile2.qml");
bool noCycles = false;
@@ -106,7 +149,7 @@ void tst_qqmlenginecleanup::test_valueTypeProviderModule()
c.loadUrl(i % 2 == 0 ? testFile1 : testFile2); // this will hang if cycles exist.
}
delete e;
- e = 0;
+ e = nullptr;
noCycles = true;
QVERIFY(noCycles);
diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
index aa201f2644..1decc04ad2 100644
--- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
+++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
@@ -52,7 +52,7 @@ class TestObject : public QObject
Q_PROPERTY(QQmlScriptString scriptString READ scriptString WRITE setScriptString)
Q_PROPERTY(QQmlScriptString scriptStringError READ scriptStringError WRITE setScriptStringError)
public:
- TestObject(QObject *parent = 0) : QObject(parent) {}
+ TestObject(QObject *parent = nullptr) : QObject(parent) {}
QQmlScriptString scriptString() const { return m_scriptString; }
void setScriptString(QQmlScriptString scriptString) { m_scriptString = scriptString; }
@@ -74,7 +74,7 @@ void tst_qqmlexpression::scriptString()
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("scriptString.qml"));
TestObject *testObj = qobject_cast<TestObject*>(c.create());
- QVERIFY(testObj != 0);
+ QVERIFY(testObj != nullptr);
QQmlScriptString script = testObj->scriptString();
QVERIFY(!script.isEmpty());
@@ -100,15 +100,19 @@ void tst_qqmlexpression::scriptString()
void tst_qqmlexpression::syntaxError()
{
QQmlEngine engine;
- QQmlExpression expression(engine.rootContext(), 0, "asd asd");
- QVariant v = expression.evaluate();
+ QQmlExpression expression(engine.rootContext(), nullptr, "asd asd");
+ bool isUndefined = false;
+ QVariant v = expression.evaluate(&isUndefined);
QCOMPARE(v, QVariant());
+ QVERIFY(expression.hasError());
+ QCOMPARE(expression.error().description(), "SyntaxError: Expected token `;'");
+ QVERIFY(isUndefined);
}
void tst_qqmlexpression::exception()
{
QQmlEngine engine;
- QQmlExpression expression(engine.rootContext(), 0, "abc=123");
+ QQmlExpression expression(engine.rootContext(), nullptr, "abc=123");
QVariant v = expression.evaluate();
QCOMPARE(v, QVariant());
QVERIFY(expression.hasError());
diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
index 268010ead8..341a49bf09 100644
--- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
+++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp
@@ -105,11 +105,14 @@ void tst_qqmlextensionplugin::iidCheck()
QPluginLoader loader(filePath);
QVERIFY2(loader.load(), qPrintable(loader.errorString()));
- QVERIFY(loader.instance() != Q_NULLPTR);
+ QVERIFY(loader.instance() != nullptr);
if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) {
QString iid = loader.metaData().value(QStringLiteral("IID")).toString();
- QCOMPARE(iid, QLatin1String(QQmlExtensionInterface_iid));
+ if (iid == QLatin1String(QQmlExtensionInterface_iid_old))
+ qWarning() << "Old extension plugin found. Update the IID" << loader.metaData();
+ else
+ QCOMPARE(iid, QLatin1String(QQmlExtensionInterface_iid));
}
}
diff --git a/tests/auto/qml/qqmlfile/qqmlfile.pro b/tests/auto/qml/qqmlfile/qqmlfile.pro
new file mode 100644
index 0000000000..ab66792445
--- /dev/null
+++ b/tests/auto/qml/qqmlfile/qqmlfile.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qqmlfile
+SOURCES += tst_qqmlfile.cpp
+macos:CONFIG -= app_bundle
+QT += qml testlib
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp b/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp
index fe01507412..a1c8daddcf 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -25,32 +25,34 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <QStringList>
-#include <QtQml/qqmlextensionplugin.h>
-#include <QtQml/qqml.h>
-#include <QDebug>
-class MyPluginType : public QObject
+#include <QtCore>
+#include <QtTest>
+#include <QQmlFile>
+
+class tst_qqmlfile : public QObject
{
Q_OBJECT
+
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ tst_qqmlfile() {}
+
+private Q_SLOTS:
+ void urlToLocalFileOrQrcOverloads();
};
-class MyPlugin : public QQmlExtensionPlugin
+void tst_qqmlfile::urlToLocalFileOrQrcOverloads()
{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+ const QString urlString = QStringLiteral("qrc:///example.qml");
+ const QUrl url(urlString);
+ const QString pathForUrlString = QQmlFile::urlToLocalFileOrQrc(urlString);
+ const QString pathForUrl = QQmlFile::urlToLocalFileOrQrc(url);
-public:
- MyPlugin() {}
+ QCOMPARE(pathForUrlString, pathForUrl);
+ QCOMPARE(pathForUrlString, QStringLiteral(":/example.qml"));
+}
- void registerTypes(const char *uri)
- {
- Q_ASSERT(QLatin1String(uri) == "org.qtproject.InvalidStrictModule");
- qmlRegisterType<MyPluginType>("org.qtproject.SomeOtherModule", 1, 0, "MyPluginType");
- }
-};
+QTEST_GUILESS_MAIN(tst_qqmlfile)
-#include "plugin.moc"
+#include "tst_qqmlfile.moc"
diff --git a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
index 648e4490ee..2d618170d4 100644
--- a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
+++ b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp
@@ -33,6 +33,7 @@
#include <QQmlApplicationEngine>
#include <QFileSelector>
#include <QQmlContext>
+#include <QLoggingCategory>
#include <qqmlinfo.h>
#include "../../shared/util.h"
@@ -44,6 +45,7 @@ public:
private slots:
void basicTest();
+ void basicTestCached();
void applicationEngineTest();
};
@@ -56,22 +58,41 @@ void tst_qqmlfileselector::basicTest()
QQmlComponent component(&engine, testFileUrl("basicTest.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toString(), QString("selected"));
delete object;
}
+void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+{
+ if (type == QtDebugMsg
+ && QByteArray(context.category) == QByteArray("qt.qml.diskcache")
+ && message.contains("QML source file has moved to a different location.")) {
+ QFAIL(message.toUtf8());
+ }
+}
+
+void tst_qqmlfileselector::basicTestCached()
+{
+ basicTest(); // Seed the cache, in case basicTestCached() is run on its own
+ QtMessageHandler defaultHandler = qInstallMessageHandler(&messageHandler);
+ QLoggingCategory::setFilterRules("qt.qml.diskcache.debug=true");
+ basicTest(); // Run again and check that the file is in the cache now
+ QLoggingCategory::setFilterRules(QString());
+ qInstallMessageHandler(defaultHandler);
+}
+
void tst_qqmlfileselector::applicationEngineTest()
{
QQmlApplicationEngine engine;
QQmlFileSelector* selector = QQmlFileSelector::get(&engine);
- QVERIFY(selector != 0);
+ QVERIFY(selector != nullptr);
selector->setExtraSelectors(QStringList() << "basic");
QQmlComponent component(&engine, testFileUrl("basicTest.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toString(), QString("selected"));
delete object;
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index 68739886c4..70aaa9678e 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -54,7 +54,7 @@ void tst_QQmlImport::cleanup()
void tst_QQmlImport::testDesignerSupported()
{
QQuickView *window = new QQuickView();
- window->engine()->addImportPath(QT_TESTCASE_BUILDDIR);
+ window->engine()->addImportPath(directory());
window->setSource(testFileUrl("testfile_supported.qml"));
QVERIFY(window->errors().isEmpty());
@@ -68,7 +68,7 @@ void tst_QQmlImport::testDesignerSupported()
delete window;
window = new QQuickView();
- window->engine()->addImportPath(QT_TESTCASE_BUILDDIR);
+ window->engine()->addImportPath(directory());
window->engine()->clearComponentCache();
window->setSource(testFileUrl("testfile_supported.qml"));
@@ -91,7 +91,7 @@ void tst_QQmlImport::uiFormatLoading()
int size = 0;
QQmlApplicationEngine *test = new QQmlApplicationEngine(testFileUrl("TestForm.ui.qml"));
- test->addImportPath(QT_TESTCASE_BUILDDIR);
+ test->addImportPath(directory());
QCOMPARE(test->rootObjects().size(), ++size);
QVERIFY(test->rootObjects()[size -1]);
QVERIFY(test->rootObjects()[size -1]->property("success").toBool());
diff --git a/tests/auto/qml/qqmlincubator/data/garbageCollection.qml b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml
new file mode 100644
index 0000000000..6866a02a00
--- /dev/null
+++ b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property var incubator
+
+ function getAndClearIncubator() {
+ var result = incubator
+ incubator = null
+ return result
+ }
+
+ Component.onCompleted: {
+ var c = Qt.createComponent("statusChanged.qml"); // use existing simple type for convenience
+ var incubator = c.incubateObject(root);
+ incubator.onStatusChanged = function(status) { if (status === 1) root.incubator = incubator }
+ }
+}
diff --git a/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt b/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt
index eeda289d35..9f972e3e06 100644
--- a/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt
+++ b/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt
@@ -1 +1 @@
--1:-1:Object destroyed during incubation
+-1:-1:Object or context destroyed during incubation
diff --git a/tests/auto/qml/qqmlincubator/testtypes.cpp b/tests/auto/qml/qqmlincubator/testtypes.cpp
index 3fcd3ba299..06d5904bbd 100644
--- a/tests/auto/qml/qqmlincubator/testtypes.cpp
+++ b/tests/auto/qml/qqmlincubator/testtypes.cpp
@@ -28,7 +28,7 @@
#include "testtypes.h"
#include <QtQml/qqml.h>
-SelfRegisteringType *SelfRegisteringType::m_me = 0;
+SelfRegisteringType *SelfRegisteringType::m_me = nullptr;
SelfRegisteringType::SelfRegisteringType()
: m_v(0)
{
@@ -42,13 +42,13 @@ SelfRegisteringType *SelfRegisteringType::me()
void SelfRegisteringType::clearMe()
{
- m_me = 0;
+ m_me = nullptr;
}
-SelfRegisteringOuterType *SelfRegisteringOuterType::m_me = 0;
+SelfRegisteringOuterType *SelfRegisteringOuterType::m_me = nullptr;
bool SelfRegisteringOuterType::beenDeleted = false;
SelfRegisteringOuterType::SelfRegisteringOuterType()
-: m_v(0)
+: m_v(nullptr)
{
m_me = this;
beenDeleted = false;
@@ -64,7 +64,7 @@ SelfRegisteringOuterType *SelfRegisteringOuterType::me()
return m_me;
}
-CompletionRegisteringType *CompletionRegisteringType::m_me = 0;
+CompletionRegisteringType *CompletionRegisteringType::m_me = nullptr;
CompletionRegisteringType::CompletionRegisteringType()
{
}
@@ -85,11 +85,11 @@ CompletionRegisteringType *CompletionRegisteringType::me()
void CompletionRegisteringType::clearMe()
{
- m_me = 0;
+ m_me = nullptr;
}
-CallbackRegisteringType::callback CallbackRegisteringType::m_callback = 0;
-void *CallbackRegisteringType::m_data = 0;
+CallbackRegisteringType::callback CallbackRegisteringType::m_callback = nullptr;
+void *CallbackRegisteringType::m_data = nullptr;
CallbackRegisteringType::CallbackRegisteringType()
: m_v(0)
{
@@ -97,8 +97,8 @@ CallbackRegisteringType::CallbackRegisteringType()
void CallbackRegisteringType::clearCallback()
{
- m_callback = 0;
- m_data = 0;
+ m_callback = nullptr;
+ m_data = nullptr;
}
void CallbackRegisteringType::registerCallback(callback c, void *d)
@@ -107,8 +107,8 @@ void CallbackRegisteringType::registerCallback(callback c, void *d)
m_data = d;
}
-CompletionCallbackType::callback CompletionCallbackType::m_callback = 0;
-void *CompletionCallbackType::m_data = 0;
+CompletionCallbackType::callback CompletionCallbackType::m_callback = nullptr;
+void *CompletionCallbackType::m_data = nullptr;
CompletionCallbackType::CompletionCallbackType()
{
}
@@ -124,8 +124,8 @@ void CompletionCallbackType::componentComplete()
void CompletionCallbackType::clearCallback()
{
- m_callback = 0;
- m_data = 0;
+ m_callback = nullptr;
+ m_data = nullptr;
}
void CompletionCallbackType::registerCallback(callback c, void *d)
diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
index 863b6aaa29..8e25079703 100644
--- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
+++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
@@ -39,6 +39,7 @@
#include <QQmlComponent>
#include <QQmlIncubator>
#include "../../shared/util.h"
+#include <private/qjsvalue_p.h>
#include <private/qqmlincubator_p.h>
#include <private/qqmlobjectcreator_p.h>
@@ -68,6 +69,7 @@ private slots:
void chainedAsynchronousClear();
void selfDelete();
void contextDelete();
+ void garbageCollection();
private:
QQmlIncubationController controller;
@@ -145,15 +147,15 @@ void tst_qqmlincubator::objectDeleted()
QCOMPARE(incubator.status(), QQmlIncubator::Loading);
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringOuterType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringOuterType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringOuterType::me() != 0);
+ QVERIFY(SelfRegisteringOuterType::me() != nullptr);
QVERIFY(incubator.isLoading());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
@@ -201,13 +203,13 @@ void tst_qqmlincubator::clear()
QQmlIncubator incubator;
component.create(incubator);
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
QVERIFY(incubator.isLoading());
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QPointer<SelfRegisteringType> srt = SelfRegisteringType::me();
incubator.clear();
@@ -226,7 +228,7 @@ void tst_qqmlincubator::clear()
}
QVERIFY(incubator.isReady());
- QVERIFY(incubator.object() != 0);
+ QVERIFY(incubator.object() != nullptr);
QPointer<QObject> obj = incubator.object();
incubator.clear();
@@ -299,7 +301,7 @@ void tst_qqmlincubator::forceCompletion()
incubator.forceCompletion();
QVERIFY(incubator.isReady());
- QVERIFY(incubator.object() != 0);
+ QVERIFY(incubator.object() != nullptr);
QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
delete incubator.object();
@@ -314,18 +316,18 @@ void tst_qqmlincubator::forceCompletion()
component.create(incubator);
QVERIFY(incubator.isLoading());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
incubator.forceCompletion();
QVERIFY(incubator.isReady());
- QVERIFY(incubator.object() != 0);
+ QVERIFY(incubator.object() != nullptr);
QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
delete incubator.object();
@@ -341,13 +343,13 @@ void tst_qqmlincubator::forceCompletion()
incubator.forceCompletion();
QVERIFY(incubator.isReady());
- QVERIFY(incubator.object() != 0);
+ QVERIFY(incubator.object() != nullptr);
QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
incubator.forceCompletion();
QVERIFY(incubator.isReady());
- QVERIFY(incubator.object() != 0);
+ QVERIFY(incubator.object() != nullptr);
QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
delete incubator.object();
@@ -410,19 +412,19 @@ void tst_qqmlincubator::clearDuringCompletion()
QCOMPARE(incubator.status(), QQmlIncubator::Loading);
QVERIFY(!CompletionRegisteringType::me());
- while (CompletionRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (CompletionRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(CompletionRegisteringType::me() != 0);
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(CompletionRegisteringType::me() != nullptr);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
QPointer<QObject> srt = SelfRegisteringType::me();
incubator.clear();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(incubator.isNull());
QVERIFY(srt.isNull());
@@ -436,7 +438,7 @@ void tst_qqmlincubator::objectDeletionAfterInit()
struct MyIncubator : public QQmlIncubator
{
MyIncubator(QQmlIncubator::IncubationMode mode)
- : QQmlIncubator(mode), obj(0) {}
+ : QQmlIncubator(mode), obj(nullptr) {}
virtual void setInitialState(QObject *o) {
obj = o;
@@ -455,12 +457,12 @@ void tst_qqmlincubator::objectDeletionAfterInit()
}
QVERIFY(incubator.isLoading());
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
delete incubator.obj;
incubator.clear();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QVERIFY(incubator.isNull());
}
@@ -592,11 +594,11 @@ void tst_qqmlincubator::asynchronousIfNested()
QVERIFY(component.isReady());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 10);
QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested);
- component.create(incubator, 0, qmlContext(object));
+ component.create(incubator, nullptr, qmlContext(object));
QVERIFY(incubator.isReady());
QVERIFY(incubator.object());
@@ -618,16 +620,16 @@ void tst_qqmlincubator::asynchronousIfNested()
QVERIFY(incubator.isLoading());
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
QQmlIncubator nested(QQmlIncubator::AsynchronousIfNested);
- component.create(nested, 0, qmlContext(SelfRegisteringType::me()));
+ component.create(nested, nullptr, qmlContext(SelfRegisteringType::me()));
QVERIFY(nested.isLoading());
while (nested.isLoading()) {
@@ -669,7 +671,7 @@ void tst_qqmlincubator::asynchronousIfNested()
if (!c.isReady()) return;
QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested);
- c.create(incubator, 0, qmlContext(o));
+ c.create(incubator, nullptr, qmlContext(o));
if (!incubator.isReady()) return;
@@ -738,12 +740,12 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
QVERIFY(incubator.isLoading());
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
struct MyIncubator : public QQmlIncubator {
@@ -753,7 +755,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
protected:
virtual void statusChanged(Status s) {
if (s == Ready && next)
- component->create(*next, 0, ctxt);
+ component->create(*next, nullptr, ctxt);
}
private:
@@ -762,10 +764,10 @@ void tst_qqmlincubator::chainedAsynchronousIfNested()
QQmlContext *ctxt;
};
- MyIncubator incubator2(0, &component, 0);
+ MyIncubator incubator2(nullptr, &component, nullptr);
MyIncubator incubator1(&incubator2, &component, qmlContext(SelfRegisteringType::me()));
- component.create(incubator1, 0, qmlContext(SelfRegisteringType::me()));
+ component.create(incubator1, nullptr, qmlContext(SelfRegisteringType::me()));
QVERIFY(incubator.isLoading());
QVERIFY(incubator1.isLoading());
@@ -824,7 +826,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
protected:
virtual void statusChanged(Status s) {
if (s == Ready && next) {
- component->create(*next, 0, ctxt);
+ component->create(*next, nullptr, ctxt);
}
}
@@ -842,7 +844,7 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QQmlContext *ctxt;
static void callback(CompletionCallbackType *, void *data) {
CallbackData *d = (CallbackData *)data;
- d->component->create(*d->incubator, 0, d->ctxt);
+ d->component->create(*d->incubator, nullptr, d->ctxt);
}
};
@@ -852,15 +854,15 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
QVERIFY(incubator.isLoading());
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
- MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me()));
+ MyIncubator incubator3(nullptr, &c1, qmlContext(SelfRegisteringType::me()));
MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me()));
MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me()));
@@ -952,7 +954,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
protected:
virtual void statusChanged(Status s) {
if (s == Ready && next) {
- component->create(*next, 0, ctxt);
+ component->create(*next, nullptr, ctxt);
}
}
@@ -970,7 +972,7 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QQmlContext *ctxt;
static void callback(CompletionCallbackType *, void *data) {
CallbackData *d = (CallbackData *)data;
- d->component->create(*d->incubator, 0, d->ctxt);
+ d->component->create(*d->incubator, nullptr, d->ctxt);
}
};
@@ -980,15 +982,15 @@ void tst_qqmlincubator::chainedAsynchronousClear()
QVERIFY(incubator.isLoading());
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator.isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator.isLoading());
- MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me()));
+ MyIncubator incubator3(nullptr, &c1, qmlContext(SelfRegisteringType::me()));
MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me()));
MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me()));
@@ -1103,12 +1105,12 @@ void tst_qqmlincubator::selfDelete()
QCOMPARE(incubator->QQmlIncubator::status(), QQmlIncubator::Loading);
QVERIFY(!SelfRegisteringType::me());
- while (SelfRegisteringType::me() == 0 && incubator->isLoading()) {
+ while (SelfRegisteringType::me() == nullptr && incubator->isLoading()) {
bool b = false;
controller.incubateWhile(&b);
}
- QVERIFY(SelfRegisteringType::me() != 0);
+ QVERIFY(SelfRegisteringType::me() != nullptr);
QVERIFY(incubator->isLoading());
// We have to cheat and manually remove it from the creator->allCreatedObjects
@@ -1144,6 +1146,34 @@ void tst_qqmlincubator::contextDelete()
}
}
+// QTBUG-53111
+void tst_qqmlincubator::garbageCollection()
+{
+ QQmlComponent component(&engine, testFileUrl("garbageCollection.qml"));
+ QScopedPointer<QObject> obj(component.create());
+
+ engine.collectGarbage();
+
+ bool b = true;
+ controller.incubateWhile(&b);
+
+ // verify incubation completed (the incubator was not prematurely collected)
+ QVariant incubatorVariant;
+ QMetaObject::invokeMethod(obj.data(), "getAndClearIncubator", Q_RETURN_ARG(QVariant, incubatorVariant));
+ QJSValue strongRef = incubatorVariant.value<QJSValue>();
+ QVERIFY(!strongRef.isNull() && !strongRef.isUndefined());
+
+ // turn the last strong reference to the incubator into a weak one and collect
+ QV4::WeakValue weakIncubatorRef;
+ weakIncubatorRef.set(QQmlEnginePrivate::getV4Engine(&engine), *QJSValuePrivate::getValue(&strongRef));
+ strongRef = QJSValue();
+ incubatorVariant.clear();
+
+ // verify incubator is correctly collected now that incubation is complete and all references are gone
+ engine.collectGarbage();
+ QVERIFY(weakIncubatorRef.isNullOrUndefined());
+}
+
QTEST_MAIN(tst_qqmlincubator)
#include "tst_qqmlincubator.moc"
diff --git a/tests/auto/qml/qqmlinfo/data/Component.qml b/tests/auto/qml/qqmlinfo/data/Component.qml
new file mode 100644
index 0000000000..fefbbfae76
--- /dev/null
+++ b/tests/auto/qml/qqmlinfo/data/Component.qml
@@ -0,0 +1,8 @@
+import QtQml 2.0
+
+QtObject {
+ property Component delegate: Component {
+ QtObject {
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp b/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp
index 3f6c200027..5ff72de0a0 100644
--- a/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp
+++ b/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp
@@ -50,6 +50,7 @@ private slots:
void types();
void chaining();
void messageTypes();
+ void component();
private:
QQmlEngine engine;
@@ -60,14 +61,14 @@ void tst_qqmlinfo::qmlObject()
QQmlComponent component(&engine, testFileUrl("qmlObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString message = component.url().toString() + ":3:1: QML QtObject: Test Message";
QTest::ignoreMessage(QtInfoMsg, qPrintable(message));
qmlInfo(object) << "Test Message";
QObject *nested = qvariant_cast<QObject *>(object->property("nested"));
- QVERIFY(nested != 0);
+ QVERIFY(nested != nullptr);
message = component.url().toString() + ":6:13: QML QtObject: Second Test Message";
QTest::ignoreMessage(QtInfoMsg, qPrintable(message));
@@ -79,12 +80,12 @@ void tst_qqmlinfo::nestedQmlObject()
QQmlComponent component(&engine, testFileUrl("nestedQmlObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QObject *nested = qvariant_cast<QObject *>(object->property("nested"));
- QVERIFY(nested != 0);
+ QVERIFY(nested != nullptr);
QObject *nested2 = qvariant_cast<QObject *>(object->property("nested2"));
- QVERIFY(nested2 != 0);
+ QVERIFY(nested2 != nullptr);
QString message = component.url().toString() + ":5:13: QML NestedObject: Outer Object";
QTest::ignoreMessage(QtInfoMsg, qPrintable(message));
@@ -100,12 +101,12 @@ void tst_qqmlinfo::nestedComponent()
QQmlComponent component(&engine, testFileUrl("NestedComponent.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QObject *nested = qvariant_cast<QObject *>(object->property("nested"));
- QVERIFY(nested != 0);
+ QVERIFY(nested != nullptr);
QObject *nested2 = qvariant_cast<QObject *>(object->property("nested2"));
- QVERIFY(nested2 != 0);
+ QVERIFY(nested2 != nullptr);
QString message = component.url().toString() + ":10:9: QML NestedObject: Complex Object";
QTest::ignoreMessage(QtInfoMsg, qPrintable(message));
@@ -130,7 +131,7 @@ void tst_qqmlinfo::nonQmlObject()
void tst_qqmlinfo::nullObject()
{
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: Null Object Test Message");
- qmlInfo(0) << "Null Object Test Message";
+ qmlInfo(nullptr) << "Null Object Test Message";
}
void tst_qqmlinfo::nonQmlContextedObject()
@@ -145,44 +146,44 @@ void tst_qqmlinfo::nonQmlContextedObject()
void tst_qqmlinfo::types()
{
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: false");
- qmlInfo(0) << false;
+ qmlInfo(nullptr) << false;
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: 1.1");
- qmlInfo(0) << 1.1;
+ qmlInfo(nullptr) << 1.1;
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: 1.2");
- qmlInfo(0) << 1.2f;
+ qmlInfo(nullptr) << 1.2f;
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: 15");
- qmlInfo(0) << 15;
+ qmlInfo(nullptr) << 15;
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: 'b'");
- qmlInfo(0) << QChar('b');
+ qmlInfo(nullptr) << QChar('b');
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: \"Qt\"");
- qmlInfo(0) << QByteArray("Qt");
+ qmlInfo(nullptr) << QByteArray("Qt");
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: true");
- qmlInfo(0) << bool(true);
+ qmlInfo(nullptr) << bool(true);
//### do we actually want QUrl to show up in the output?
//### why the extra space at the end?
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: QUrl(\"http://www.qt-project.org\") ");
- qmlInfo(0) << QUrl("http://www.qt-project.org");
+ qmlInfo(nullptr) << QUrl("http://www.qt-project.org");
//### should this be quoted?
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: hello");
- qmlInfo(0) << QLatin1String("hello");
+ qmlInfo(nullptr) << QLatin1String("hello");
//### should this be quoted?
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: World");
QString str("Hello World");
QStringRef ref(&str, 6, 5);
- qmlInfo(0) << ref;
+ qmlInfo(nullptr) << ref;
//### should this be quoted?
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: Quick");
- qmlInfo(0) << QString ("Quick");
+ qmlInfo(nullptr) << QString ("Quick");
}
void tst_qqmlinfo::chaining()
@@ -190,7 +191,7 @@ void tst_qqmlinfo::chaining()
QString str("Hello World");
QStringRef ref(&str, 6, 5);
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: false 1.1 1.2 15 hello 'b' World \"Qt\" true Quick QUrl(\"http://www.qt-project.org\") ");
- qmlInfo(0) << false << ' '
+ qmlInfo(nullptr) << false << ' '
<< 1.1 << ' '
<< 1.2f << ' '
<< 15 << ' '
@@ -207,13 +208,26 @@ void tst_qqmlinfo::chaining()
void tst_qqmlinfo::messageTypes()
{
QTest::ignoreMessage(QtDebugMsg, "<Unknown File>: debug");
- qmlDebug(0) << QLatin1String("debug");
+ qmlDebug(nullptr) << QLatin1String("debug");
QTest::ignoreMessage(QtInfoMsg, "<Unknown File>: info");
- qmlInfo(0) << QLatin1String("info");
+ qmlInfo(nullptr) << QLatin1String("info");
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: warning");
- qmlWarning(0) << QLatin1String("warning");
+ qmlWarning(nullptr) << QLatin1String("warning");
+}
+
+void tst_qqmlinfo::component()
+{
+ QQmlComponent component(&engine, testFileUrl("Component.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QQmlComponent *delegate = qobject_cast<QQmlComponent*>(object->property("delegate").value<QObject*>());
+ QVERIFY(delegate);
+
+ QString message = component.url().toString() + ":4:34: QML Component: Delegate error";
+ QTest::ignoreMessage(QtInfoMsg, qPrintable(message));
+ qmlInfo(delegate) << "Delegate error";
}
QTEST_MAIN(tst_qqmlinfo)
diff --git a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
index 719fd6c350..542ec44736 100644
--- a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
+++ b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro
@@ -2,7 +2,6 @@ CONFIG += testcase
TARGET = tst_qqmlinstantiator
macx:CONFIG -= app_bundle
-INCLUDEPATH += ../../shared/
SOURCES += tst_qqmlinstantiator.cpp
HEADERS += stringmodel.h
diff --git a/tests/auto/qml/qqmlinstantiator/stringmodel.h b/tests/auto/qml/qqmlinstantiator/stringmodel.h
index 0bd4ada55e..6ae3cbb6ee 100644
--- a/tests/auto/qml/qqmlinstantiator/stringmodel.h
+++ b/tests/auto/qml/qqmlinstantiator/stringmodel.h
@@ -60,27 +60,27 @@ public:
endInsertRows();
}
- int rowCount(const QModelIndex &) const
+ int rowCount(const QModelIndex &) const override
{
return items.count();
}
- virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
+ QHash<int, QByteArray> roleNames() const override
{
return roles;
}
- virtual int columnCount(const QModelIndex &) const
+ int columnCount(const QModelIndex &) const override
{
return 1;
}
- virtual bool hasChildren(const QModelIndex &) const Q_DECL_OVERRIDE
+ bool hasChildren(const QModelIndex &) const override
{
return rowCount(QModelIndex()) > 0;
}
- virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
+ QModelIndex index(int row, int column, const QModelIndex &parent) const override
{
Q_UNUSED(column);
if (row>=0 && row<rowCount(parent))
@@ -89,12 +89,12 @@ public:
return QModelIndex();
}
- virtual QModelIndex parent(const QModelIndex &) const
+ QModelIndex parent(const QModelIndex &) const override
{
return QModelIndex();
}
- QVariant data (const QModelIndex & index, int role) const
+ QVariant data (const QModelIndex & index, int role) const override
{
int row = index.row();
if ((row<0) || (row>=items.count()))
diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
index 90b719d000..a66f13e6bb 100644
--- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
+++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp
@@ -59,7 +59,7 @@ void tst_qqmlinstantiator::createNone()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createNone.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 0);
QCOMPARE(instantiator->property("success").toBool(), true);
@@ -71,7 +71,7 @@ void tst_qqmlinstantiator::createSingle()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createSingle.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 1);
QVERIFY(instantiator->delegate()->isReady());
@@ -88,7 +88,7 @@ void tst_qqmlinstantiator::createMultiple()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createMultiple.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 10);
@@ -106,7 +106,7 @@ void tst_qqmlinstantiator::stringModel()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringModel.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 4);
@@ -123,7 +123,7 @@ void tst_qqmlinstantiator::activeProperty()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("inactive.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
QSignalSpy objectSpy(instantiator, SIGNAL(objectChanged()));
@@ -158,7 +158,7 @@ void tst_qqmlinstantiator::intModelChange()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createMultiple.qml"));
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create());
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
QSignalSpy objectSpy(instantiator, SIGNAL(objectChanged()));
@@ -194,11 +194,11 @@ void tst_qqmlinstantiator::createAndRemove()
StringModel *model = new StringModel("model1");
engine.rootContext()->setContextProperty("model1", model);
QObject *rootObject = component.create();
- QVERIFY(rootObject != 0);
+ QVERIFY(rootObject != nullptr);
QQmlInstantiator *instantiator =
qobject_cast<QQmlInstantiator*>(rootObject->findChild<QObject*>("instantiator1"));
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
model->drop(1);
QVector<QString> names;
names << "Beta" << "Gamma" << "Delta";
@@ -234,7 +234,7 @@ void tst_qqmlinstantiator::asynchronous()
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator *>(incubator.object());
while (incubationController.incubatingObjectCount() > 0)
incubationController.incubateFor(10);
- QVERIFY(instantiator != 0);
+ QVERIFY(instantiator != nullptr);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 10);
diff --git a/tests/auto/qml/qqmlitemmodels/qtestmodel.h b/tests/auto/qml/qqmlitemmodels/qtestmodel.h
index 8724ef927f..6a022b3135 100644
--- a/tests/auto/qml/qqmlitemmodels/qtestmodel.h
+++ b/tests/auto/qml/qqmlitemmodels/qtestmodel.h
@@ -91,8 +91,6 @@ public:
}
int rowCount(const QModelIndex& parent = QModelIndex()) const {
- if (!fetched)
- qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO);
if ((parent.column() > 0) || (level(parent) > levels)
|| (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1)))
return 0;
diff --git a/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp
index fca72ab021..cbb7ebb0ff 100644
--- a/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp
+++ b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp
@@ -182,7 +182,7 @@ void tst_qqmlitemmodels::itemSelection()
QCOMPARE(object->property("count").toInt(), 5);
QCOMPARE(object->property("contains").toBool(), true);
- const char *propNames[] = { "itemSelectionRead", "itemSelectionBinding", 0 };
+ const char *propNames[] = { "itemSelectionRead", "itemSelectionBinding", nullptr };
for (const char **name = propNames; *name; name++) {
QVariant isVariant = object->property(*name);
QCOMPARE(isVariant.userType(), qMetaTypeId<QItemSelection>());
@@ -217,7 +217,7 @@ void tst_qqmlitemmodels::modelIndexList()
QModelIndexList someMIL = object->someModelIndexList();
QCOMPARE(cppMILVariant.value<QModelIndexList>(), someMIL);
- const char *propNames[] = { "modelIndexListRead", "modelIndexListBinding", 0 };
+ const char *propNames[] = { "modelIndexListRead", "modelIndexListBinding", nullptr };
for (const char **name = propNames; *name; name++) {
QVariant milVariant = object->property(*name);
QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
diff --git a/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml b/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml
new file mode 100644
index 0000000000..67e92e5a05
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml
@@ -0,0 +1,19 @@
+import QtQml 2.0
+import Test 1.0
+DeferredProperties {
+ groupProperty: QtObject {
+ objectName: "innerobj"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+ QtObject {
+ objectName: "innerlist1"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+ QtObject {
+ objectName: "innerlist2"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
new file mode 100644
index 0000000000..f311f6b602
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import Test 1.0
+LazyDeferredSubObject {
+ subObject: QtObject { objectName: 'default' }
+ objectName: subObject.objectName
+}
diff --git a/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml
new file mode 100644
index 0000000000..c6788f787a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ EnumValue2,
+ EnumValue3
+ }
+
+ enum MyOtherEnum {
+ OtherEnumValue1 = 24,
+ OtherEnumValue2,
+ OtherEnumValue3 = 24,
+ OtherEnumValue4,
+ OtherEnumValue5 = 1
+ }
+
+ property int enumValue: TypeWithEnum.EnumValue2
+ property int enumValue2
+ property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue2
+ Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue3
+
+ property int otherEnumValue1: TypeWithEnum.OtherEnumValue1
+ property int otherEnumValue2: TypeWithEnum.OtherEnumValue2
+ property int otherEnumValue3: TypeWithEnum.OtherEnumValue3
+ property int otherEnumValue4: TypeWithEnum.OtherEnumValue4
+ property int otherEnumValue5: TypeWithEnum.OtherEnumValue5
+}
diff --git a/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml b/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml
new file mode 100644
index 0000000000..e5151096e5
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/accessDeletedObject.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ Component.onCompleted: {
+ var createdObject = objectCreator.create()
+ createdObject.del()
+ // Shouldn't crash.
+ var test = "index" in createdObject
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.15.qml b/tests/auto/qml/qqmllanguage/data/alias.15.qml
new file mode 100644
index 0000000000..5f3de9c83e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.15.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.6
+
+Item {
+ id: root
+
+ property alias symbol: symbol
+ symbol.y: 1
+
+ Item {
+ id: symbol
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/alias.16.qml b/tests/auto/qml/qqmllanguage/data/alias.16.qml
new file mode 100644
index 0000000000..4637aec58f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.16.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import QtQuick.Window 2.0
+
+Window {
+ visible: true
+
+ property alias list: repeater.model
+
+ list: ["A", "B", "C"]
+
+ Repeater {
+ id: repeater
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.errors.txt b/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.errors.txt
new file mode 100644
index 0000000000..af103cf8bf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.errors.txt
@@ -0,0 +1 @@
+4:27:Cannot assign object of type "Component" to property of type "QQmlTimer*" as the former is neither the same as the latter nor a sub-class of it.
diff --git a/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.qml b/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.qml
new file mode 100644
index 0000000000..2159bf8116
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/assignComponentToWrongType.qml
@@ -0,0 +1,9 @@
+import QtQml 2.9
+
+QtObject {
+ property Timer stuff: Component {
+ QtObject {
+ objectName: "wrong"
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
index fce248a381..69b0096a5e 100644
--- a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
+++ b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
@@ -30,6 +30,7 @@ QtObject {
MyQmlObject { id: testObj22; objectName: "test22"; qjsvalue: null },
MyQmlObject { id: testObj1Bound; objectName: "test1Bound"; qjsvalue: testObj1.qjsvalue + 4 }, // 1 + 4 + 4 = 9
MyQmlObject { id: testObj20Bound; objectName: "test20Bound"; qjsvalue: testObj20.qjsvalue(testObj1Bound.qjsvalue) }, // 9 * 3 = 27
+ MyQmlObject { id: testObj23; objectName: "test23"; qjsvalue: QtObject { objectName: "blah" } },
QtObject {
id: varProperties
objectName: "varProperties"
diff --git a/tests/auto/qml/qqmllanguage/data/circularSingleton.qml b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml
new file mode 100644
index 0000000000..e569111956
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.10
+import "singleton/circular"
+
+QtObject {
+ property int value: MySingleton.value
+}
diff --git a/tests/auto/qml/qqmllanguage/data/deferredProperties.qml b/tests/auto/qml/qqmllanguage/data/deferredProperties.qml
new file mode 100644
index 0000000000..07b146967c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/deferredProperties.qml
@@ -0,0 +1,19 @@
+import QtQml 2.0
+import Test 1.0
+MyDeferredProperties {
+ groupProperty: QtObject {
+ objectName: "outerobj"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+ QtObject {
+ objectName: "outerlist1"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+ QtObject {
+ objectName: "outerlist2"
+ property bool wasCompleted: false
+ Component.onCompleted: wasCompleted = true
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt b/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
index 015d55b03b..30b5193cd5 100644
--- a/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
@@ -1 +1 @@
-3:1:UnknownType is not a type
+4:5:UnknownType is not a type
diff --git a/tests/auto/qml/qqmllanguage/data/empty.errors.txt b/tests/auto/qml/qqmllanguage/data/empty.errors.txt
index 620db2bbba..ba685d78ae 100644
--- a/tests/auto/qml/qqmllanguage/data/empty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/empty.errors.txt
@@ -1,2 +1 @@
-1:1:Expected token `numeric literal'
-1:1:Expected a qualified name id
+-1:-1:File is empty
diff --git a/tests/auto/qml/qqmllanguage/data/groupPropertyInPropertyValueSource.qml b/tests/auto/qml/qqmllanguage/data/groupPropertyInPropertyValueSource.qml
new file mode 100644
index 0000000000..579086fa1c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/groupPropertyInPropertyValueSource.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Rectangle {
+ ColorAnimation on color {
+ id: animation
+ from: "red"
+ to: "darkgray"
+ duration: 250
+ easing.type: Easing.InOutQuad
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs
new file mode 100644
index 0000000000..c17a351216
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.1.mjs
@@ -0,0 +1,4 @@
+
+export function ok() {
+ return true;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml
new file mode 100644
index 0000000000..cc988a6114
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.1.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "importJsModule.1.mjs" as JSModule
+
+Item {
+ property bool test: JSModule.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml
new file mode 100644
index 0000000000..0799585622
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.2.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import org.qtproject.PureESJsModule 1.0
+
+Item {
+ property bool test: ModuleAPI.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs
new file mode 100644
index 0000000000..41d2f391bf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.indirect.mjs
@@ -0,0 +1,4 @@
+
+import { indirectOk } from "./importJsModule.3.mjs";
+
+export function ok() { return indirectOk(); }
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs b/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs
new file mode 100644
index 0000000000..3623dc6f4f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.mjs
@@ -0,0 +1,4 @@
+export function indirectOk() { return true; }
+
+export * from "./importJsModule.3.indirect.mjs";
+
diff --git a/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml b/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml
new file mode 100644
index 0000000000..3b187205c7
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/importJsModule.3.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "importJsModule.3.mjs" as JSModule
+
+Item {
+ property bool test: JSModule.ok()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt b/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
index 3813680562..4f3f758b7e 100644
--- a/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
+++ b/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
@@ -1,2 +1,2 @@
-3:1:Type IncorrectCaseType unavailable
+3:1:IncorrectCaseType is not a type
-1:-1:File name case mismatch
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt
new file mode 100644
index 0000000000..8b94763860
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.errors.txt
@@ -0,0 +1 @@
+4:28:Invalid alias target location: source
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml
new file mode 100644
index 0000000000..71063ae320
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.12.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+QtObject {
+ property alias source: previewImage.source
+ previewImage { id: previewImage }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt
new file mode 100644
index 0000000000..234753ad59
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt
@@ -0,0 +1 @@
+6:5:Invalid alias target
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml
new file mode 100644
index 0000000000..4050c0a7ad
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ property alias dataValue: dataVal
+
+ invalidAliasComponent {
+ id: dataVal
+ strValue: "value2"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml b/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml
new file mode 100644
index 0000000000..a45b1806a3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string strValue: "value1"
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.1.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.1.errors.txt
index 810fd31b41..d76f18ba89 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.1.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.1.errors.txt
@@ -1 +1 @@
-5:5:Invalid grouped property access
+5:5:Invalid grouped property access: Property "o" with type "QVariant", which is not a value type
diff --git a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.3.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.3.errors.txt
index f6d6f29fbf..9a0422753f 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.3.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.3.errors.txt
@@ -1 +1 @@
-4:5:Invalid grouped property access
+4:5:Invalid grouped property access: Property "customType" with type "MyCustomVariantType", which is not a value type
diff --git a/tests/auto/qml/qqmllanguage/data/invalidID.10.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidID.10.errors.txt
new file mode 100644
index 0000000000..d9dcb32f8e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidID.10.errors.txt
@@ -0,0 +1 @@
+4:9:Invalid use of id property with a value type
diff --git a/tests/auto/qml/qqmllanguage/data/invalidID.10.qml b/tests/auto/qml/qqmllanguage/data/invalidID.10.qml
new file mode 100644
index 0000000000..4f1817dba4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidID.10.qml
@@ -0,0 +1,7 @@
+import Test 1.0
+MyQmlObject {
+ rect {
+ id: notPossible
+ width: 100
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt
new file mode 100644
index 0000000000..a96fe376aa
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt
@@ -0,0 +1 @@
+6:22:Expected token `numeric literal'
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml
new file mode 100644
index 0000000000..fef23ecbef
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ EnumValue2 = "hello",
+ EnumValue3
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt
new file mode 100644
index 0000000000..a96fe376aa
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt
@@ -0,0 +1 @@
+6:22:Expected token `numeric literal'
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml
new file mode 100644
index 0000000000..9892fcd19c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ EnumValue2 = hello,
+ EnumValue3
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt
new file mode 100644
index 0000000000..43465c60ec
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt
@@ -0,0 +1 @@
+7:22:Enum value out of range
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml
new file mode 100644
index 0000000000..654bc0e626
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ EnumValue2,
+ EnumValue3 = 2147483648
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt
new file mode 100644
index 0000000000..12756dc593
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt
@@ -0,0 +1 @@
+7:22:Enum value must be an integer
diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml
new file mode 100644
index 0000000000..4a0aafba5e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ EnumValue2,
+ EnumValue3 = 17.5
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
new file mode 100644
index 0000000000..2465a18320
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import Test 1.0
+MyLazyDeferredSubObject {
+ subObject.objectName: 'custom'
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml
new file mode 100644
index 0000000000..ec7c76c055
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+import org.qtproject.MixedModule 1.0
+
+Item {
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml
new file mode 100644
index 0000000000..bf5a77576b
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+pragma Singleton
+
+Item {
+ enum EnumInSingleton {
+ EnumValue = 42,
+ AnotherEnumValue
+ }
+
+ enum AnotherEnumInSingleton {
+ AnotherEnumValue = 2
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir
new file mode 100644
index 0000000000..cd03a5f941
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir
@@ -0,0 +1,4 @@
+module org.qtproject.MixedModule
+singleton SingletonType 1.0 SingletonType.qml
+NonSingletonType 1.0 NonSingletonType.qml
+Test 1.0 test.js
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js
new file mode 100644
index 0000000000..6a53b53b02
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js
@@ -0,0 +1 @@
+var foo = 1
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs
new file mode 100644
index 0000000000..c17a351216
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/API.mjs
@@ -0,0 +1,4 @@
+
+export function ok() {
+ return true;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir
new file mode 100644
index 0000000000..59b4740f75
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/PureESJsModule/qmldir
@@ -0,0 +1 @@
+ModuleAPI 1.0 API.mjs
diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt
new file mode 100644
index 0000000000..d1bd2bcff4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt
@@ -0,0 +1 @@
+6:9:Enum names must begin with an upper case letter
diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml
new file mode 100644
index 0000000000..0b50820128
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum MyEnum {
+ EnumValue1,
+ enumValue2,
+ EnumValue3
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt
new file mode 100644
index 0000000000..3e051c416e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt
@@ -0,0 +1 @@
+4:5:Scoped enum names must begin with an upper case letter
diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml
new file mode 100644
index 0000000000..bb7aea6aa4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ enum myEnum {
+ EnumValue1,
+ EnumValue2,
+ EnumValue3
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml b/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml
new file mode 100644
index 0000000000..7768a6aedf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml
@@ -0,0 +1,3 @@
+import org.qtproject.MixedModule 1.0
+
+NonSingletonType {}
diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml
new file mode 100644
index 0000000000..c6b38d51a9
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property InternalType myInternalType: InternalType {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml
new file mode 100644
index 0000000000..9b488f92da
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import modulewithinternaltypes 1.0
+QtObject {
+ property InternalType myInternalType: InternalType {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir
new file mode 100644
index 0000000000..3593845329
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir
@@ -0,0 +1,3 @@
+PublicType 1.0 MyPublicType.qml
+PublicTypeWithExplicitImport 1.0 MyPublicTypeWithExplicitImport.qml
+internal InternalType MyInternalType.qml
diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml
new file mode 100644
index 0000000000..ff2f0f5a2c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property int secondVar: {
+ stats.increaseEvaluationCounter()
+ return 1
+ }
+ property int firstVar: secondVar + 1
+}
diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml
new file mode 100644
index 0000000000..0eb5e03642
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property int firstVar: secondVar + 1
+ property int secondVar: {
+ stats.increaseEvaluationCounter()
+ return 1
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
index db7d9c0f60..cefd62f9d4 100644
--- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
@@ -1 +1 @@
-4:18:Unexpected object assignment
+4:18:Unexpected object assignment for property "x"
diff --git a/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml b/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml
new file mode 100644
index 0000000000..4a3cc52793
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+QtObject {
+ id: root
+ property bool testFunc;
+ property bool ok: false
+ property QtObject subObject: QtObject {
+ function testFunc()
+ {
+ root.ok = true
+ }
+
+ Component.onCompleted: testFunc()
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/property.4.errors.txt b/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
index b447186849..2807384ec4 100644
--- a/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
@@ -1 +1 @@
-5:1:Syntax error
+5:1:Expected token `:'
diff --git a/tests/auto/qml/qqmllanguage/data/scopedEnumsWithNameClash.qml b/tests/auto/qml/qqmllanguage/data/scopedEnumsWithNameClash.qml
new file mode 100644
index 0000000000..4f8174a52d
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/scopedEnumsWithNameClash.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+import ScopedEnumsWithNameClashTest 1.0
+
+QtObject {
+ property bool success: false
+
+ Component.onCompleted: {
+ success = (ScopedEnum.ScopedEnum.OtherScopedEnum === 3)
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/scopedEnumsWithResolvedNameClash.qml b/tests/auto/qml/qqmllanguage/data/scopedEnumsWithResolvedNameClash.qml
new file mode 100644
index 0000000000..84efa6859b
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/scopedEnumsWithResolvedNameClash.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import ScopedEnumsWithResolvedNameClashTest 1.0
+
+QtObject {
+ property bool success: false
+
+ Component.onCompleted: {
+ success = (ScopedEnum.ScopedEnum.OtherScopedEnum === 3)
+ && (ScopedEnum.OtherScopedEnum.ScopedVal2 === 1)
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml b/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml
index d5a4e2ccf6..65d351a975 100644
--- a/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml
+++ b/tests/auto/qml/qqmllanguage/data/singleton/RegisteredCompositeSingletonType.qml
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml
new file mode 100644
index 0000000000..1253018789
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml
@@ -0,0 +1,12 @@
+pragma Singleton
+import QtQuick 2.10
+
+QtObject {
+ enum MyEnum {
+ Value0,
+ Value1,
+ Value2
+ }
+
+ property int value: MySingleton.Value2
+}
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir
new file mode 100644
index 0000000000..3bc50738dd
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir
@@ -0,0 +1 @@
+singleton MySingleton MySingleton.qml
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/js/jspragma.js b/tests/auto/qml/qqmllanguage/data/singleton/js/jspragma.js
index a3dcfd398f..5932178ee3 100644
--- a/tests/auto/qml/qqmllanguage/data/singleton/js/jspragma.js
+++ b/tests/auto/qml/qqmllanguage/data/singleton/js/jspragma.js
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest17.qml b/tests/auto/qml/qqmllanguage/data/singletonTest17.qml
index 192099845b..f8bebd9752 100644
--- a/tests/auto/qml/qqmllanguage/data/singletonTest17.qml
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest17.qml
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest18.qml b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml
new file mode 100644
index 0000000000..7616c23531
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import "singleton"
+import Test 1.0
+
+Item {
+ property var qmlSingleton: SingletonType
+ property var jsSingleton: MyQJSValueQObjectSingleton
+ property var cppSingleton: MyTypeObjectSingleton
+}
diff --git a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml
new file mode 100644
index 0000000000..e3c99e70e1
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml
@@ -0,0 +1,10 @@
+import QtQml 2.2
+QtObject {
+ property int x: 42
+ property int y: 0
+ function g(){
+ y = this.x;
+ }
+ property var f: g
+ Component.onCompleted: f()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml
new file mode 100644
index 0000000000..79e8347330
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import org.qtproject.MixedModule 1.0
+
+QtObject {
+ property int enumValue: TypeWithEnum.EnumValue2
+ property int enumValue2: -1
+ property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue3
+ property int enumValueFromSingleton: { var x = SingletonType.EnumValue; return x; }
+ Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue1
+
+ property int duplicatedEnumValueFromSingleton: SingletonType.AnotherEnumValue
+ property int scopedEnumValueFromSingleton1: SingletonType.EnumInSingleton.AnotherEnumValue
+ property int scopedEnumValueFromSingleton2: SingletonType.AnotherEnumInSingleton.AnotherEnumValue
+ property int scopedEnumValueFromSingleton3: { var x = SingletonType.AnotherEnumInSingleton.AnotherEnumValue; return x; }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/wrongType.16.errors.txt b/tests/auto/qml/qqmllanguage/data/wrongType.16.errors.txt
index 77cf210918..cedae349d2 100644
--- a/tests/auto/qml/qqmllanguage/data/wrongType.16.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/wrongType.16.errors.txt
@@ -1 +1 @@
-4:24:Cannot assign object to property
+4:24:Cannot assign object of type "QtObject" to property of type "MyQmlObject*" as the former is neither the same as the latter nor a sub-class of it.
diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.pro b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
index 99c0c3e823..3e88f3f0db 100644
--- a/tests/auto/qml/qqmllanguage/qqmllanguage.pro
+++ b/tests/auto/qml/qqmllanguage/qqmllanguage.pro
@@ -6,7 +6,6 @@ SOURCES += tst_qqmllanguage.cpp \
testtypes.cpp
HEADERS += testtypes.h
-INCLUDEPATH += ../../shared/
HEADERS += ../../shared/testhttpserver.h
SOURCES += ../../shared/testhttpserver.cpp
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index bdcdaa8137..f9a6ee8e5a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -35,6 +35,14 @@ static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngin
return new MyTypeObject();
}
+static QJSValue myQJSValueQObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+
+ QJSValue value = scriptEngine->newQObject(new MyTypeObject());
+ return value;
+}
+
void registerTypes()
{
qmlRegisterInterface<MyInterface>("MyInterface");
@@ -101,8 +109,12 @@ void registerTypes()
qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType");
qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton);
+ qmlRegisterSingletonType("Test", 1, 0, "MyQJSValueQObjectSingleton", myQJSValueQObjectSingleton);
qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass");
+
+ qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject");
+ qmlRegisterType<DeferredProperties>("Test", 1, 0, "DeferredProperties");
}
QVariant myCustomVariantTypeConverter(const QString &data)
@@ -113,7 +125,7 @@ QVariant myCustomVariantTypeConverter(const QString &data)
}
-void CustomBindingParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void CustomBindingParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
Q_ASSERT(customBinding);
@@ -126,14 +138,14 @@ void CustomBinding::componentComplete()
Q_ASSERT(m_target);
foreach (const QV4::CompiledData::Binding *binding, bindings) {
- QString name = compilationUnit->data->stringAt(binding->propertyNameIndex);
+ QString name = compilationUnit->stringAt(binding->propertyNameIndex);
int bindingId = binding->value.compiledScriptIndex;
QQmlContextData *context = QQmlContextData::get(qmlContext(this));
QQmlProperty property(m_target, name, qmlContext(this));
- QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
+ QV4::Scope scope(qmlEngine(this)->handle());
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(scope.engine->rootContext(), context, m_target));
QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core,
compilationUnit->runtimeFunctions[bindingId], m_target, context, qmlContext);
@@ -142,7 +154,7 @@ void CustomBinding::componentComplete()
}
}
-void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
if (bindings.count() != 1) {
error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test"));
@@ -150,7 +162,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q
}
const QV4::CompiledData::Binding *binding = bindings.first();
- if (qmlUnit->stringAt(binding->propertyNameIndex) != QStringLiteral("foo")) {
+ if (compilationUnit->stringAt(binding->propertyNameIndex) != QStringLiteral("foo")) {
error(binding, QStringLiteral("Custom parser invoked with the wrong property name"));
return;
}
@@ -159,7 +171,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q
error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum"));
return;
}
- QByteArray script = qmlUnit->stringAt(binding->stringIndex).toUtf8();
+ QByteArray script = compilationUnit->stringAt(binding->stringIndex).toUtf8();
bool ok;
int v = evaluateEnum(script, &ok);
if (!ok) {
@@ -172,7 +184,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q
}
}
-void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &bindings)
+void SimpleObjectCustomParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &bindings)
{
SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
Q_ASSERT(o);
@@ -182,8 +194,8 @@ void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData:
MyQmlObject::MyQmlObject()
: m_value(-1)
- , m_interface(0)
- , m_qmlobject(0)
+ , m_interface(nullptr)
+ , m_qmlobject(nullptr)
, m_childAddedEventCount(0)
{
qRegisterMetaType<MyCustomVariantType>("MyCustomVariantType");
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index e4a76b4324..bb6e9582c2 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -781,15 +781,15 @@ class MyCustomParserType : public QObject
class MyCustomParserTypeParser : public QQmlCustomParser
{
public:
- virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
+ 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 *> &) {}
};
class EnumSupportingCustomParser : public QQmlCustomParser
{
public:
- virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &);
- virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
+ 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 *> &) {}
};
class MyParserStatus : public QObject, public QQmlParserStatus
@@ -1282,8 +1282,8 @@ public:
class CustomBindingParser : public QQmlCustomParser
{
- virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
+ 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 *> &);
};
class SimpleObjectWithCustomParser : public QObject
@@ -1328,8 +1328,8 @@ private:
class SimpleObjectCustomParser : public QQmlCustomParser
{
- virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
- virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
+ 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 *> &);
};
class RootObjectInCreationTester : public QObject
@@ -1349,6 +1349,65 @@ private:
QObject *obj;
};
+class LazyDeferredSubObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *subObject READ subObject WRITE setSubObject NOTIFY subObjectChanged FINAL)
+ Q_CLASSINFO("DeferredPropertyNames", "subObject");
+public:
+ LazyDeferredSubObject()
+ : obj(0)
+ {}
+
+ QObject *subObject() const { if (!obj) qmlExecuteDeferred(const_cast<LazyDeferredSubObject *>(this)); return obj; }
+ void setSubObject(QObject *o) { if (obj == o) return; obj = o; emit subObjectChanged(); }
+
+signals:
+ void subObjectChanged();
+
+private:
+ QObject *obj;
+};
+
+class DeferredProperties : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *groupProperty MEMBER m_group)
+ Q_PROPERTY(QQmlListProperty<QObject> listProperty READ listProperty)
+ Q_CLASSINFO("DeferredPropertyNames", "groupProperty,listProperty")
+ Q_CLASSINFO("DefaultProperty", "listProperty")
+public:
+ QQmlListProperty<QObject> listProperty() { return QQmlListProperty<QObject>(this, m_list); }
+
+private:
+ QObject *m_group = 0;
+ QObjectList m_list;
+};
+
+class ScopedEnumsWithNameClash
+{
+ Q_GADGET
+ Q_ENUMS(ScopedEnum)
+ Q_ENUMS(OtherScopedEnum)
+
+public:
+ enum class ScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3, OtherScopedEnum };
+ enum class OtherScopedEnum : int { ScopedVal1 = 10, ScopedVal2 = 11, ScopedVal3 = 12 };
+};
+
+class ScopedEnumsWithResolvedNameClash
+{
+ Q_GADGET
+ Q_ENUMS(ScopedEnum)
+ Q_ENUMS(OtherScopedEnum)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+
+public:
+ enum class ScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3, OtherScopedEnum };
+ enum class OtherScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3 };
+};
+
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 15f19d550b..32bab2954d 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -34,16 +34,20 @@
#include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
+#include <QtCore/qscopeguard.h>
#include <QSignalSpy>
#include <QFont>
#include <QQmlFileSelector>
#include <QFileSelector>
+#include <QEasingCurve>
+#include <QScopeGuard>
#include <private/qqmlproperty_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlscriptstring_p.h>
#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlcomponent_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
@@ -123,6 +127,8 @@ private slots:
void dynamicObjectProperties();
void dynamicSignalsAndSlots();
void simpleBindings();
+ void noDoubleEvaluationForFlushedBindings_data();
+ void noDoubleEvaluationForFlushedBindings();
void autoComponentCreation();
void autoComponentCreationInGroupProperty();
void propertyValueSource();
@@ -178,6 +184,10 @@ private slots:
void importIncorrectCase();
void importJs_data();
void importJs();
+ void importJsModule_data();
+ void importJsModule();
+ void explicitSelfImport();
+ void importInternalType();
void qmlAttachedPropertiesObjectMethod();
void customOnProperty();
@@ -209,6 +219,9 @@ private slots:
void lowercaseEnumCompileTime_data();
void lowercaseEnumCompileTime();
void scopedEnum();
+ void scopedEnumsWithNameClash();
+ void scopedEnumsWithResolvedNameClash();
+ void qmlEnums();
void literals_data();
void literals();
@@ -237,6 +250,9 @@ private slots:
void compositeSingletonJavaScriptPragma();
void compositeSingletonSelectors();
void compositeSingletonRegistered();
+ void compositeSingletonCircular();
+
+ void singletonsHaveContextAndEngine();
void customParserBindingScopes();
void customParserEvaluateEnum();
@@ -248,6 +264,9 @@ private slots:
void propertyCacheInSync();
void rootObjectInCreationNotForSubObjects();
+ void lazyDeferredSubObject();
+ void deferredProperties();
+ void executeDeferredPropertiesOnce();
void noChildEvents();
@@ -269,6 +288,18 @@ private slots:
void concurrentLoadQmlDir();
+ void accessDeletedObject();
+
+ void lowercaseTypeNames();
+
+ void thisInQmlScope();
+
+ void valueTypeGroupPropertiesInBehavior();
+
+ void retrieveQmlTypeId();
+
+ void polymorphicFunctionLookup();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -355,9 +386,11 @@ void tst_qqmllanguage::insertedSemicolon()
QQmlComponent component(&engine, testFileUrl(file));
+ QScopedPointer<QObject> object;
+
if(create) {
- QObject *object = component.create();
- QVERIFY(!object);
+ object.reset(component.create());
+ QVERIFY(object.isNull());
}
VERIFY_ERRORS(errorFile.toLatin1().constData());
@@ -416,6 +449,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("invalidID.7") << "invalidID.7.qml" << "invalidID.7.errors.txt" << false;
QTest::newRow("invalidID.8") << "invalidID.8.qml" << "invalidID.8.errors.txt" << false;
QTest::newRow("invalidID.9") << "invalidID.9.qml" << "invalidID.9.errors.txt" << false;
+ QTest::newRow("invalidID.10") << "invalidID.10.qml" << "invalidID.10.errors.txt" << false;
QTest::newRow("scriptString.1") << "scriptString.1.qml" << "scriptString.1.errors.txt" << false;
QTest::newRow("scriptString.2") << "scriptString.2.qml" << "scriptString.2.errors.txt" << false;
@@ -510,6 +544,8 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false;
QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false;
QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false;
+ QTest::newRow("invalidAlias.12") << "invalidAlias.12.qml" << "invalidAlias.12.errors.txt" << false;
+ QTest::newRow("invalidAlias.13") << "invalidAlias.13.qml" << "invalidAlias.13.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false;
@@ -545,6 +581,12 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("singularProperty.2") << "singularProperty.2.qml" << "singularProperty.2.errors.txt" << false;
QTest::newRow("scopedEnumList") << "scopedEnumList.qml" << "scopedEnumList.errors.txt" << false;
+ QTest::newRow("lowercase enum value") << "lowercaseQmlEnum.1.qml" << "lowercaseQmlEnum.1.errors.txt" << false;
+ QTest::newRow("lowercase enum type") << "lowercaseQmlEnum.2.qml" << "lowercaseQmlEnum.2.errors.txt" << false;
+ QTest::newRow("string enum value") << "invalidQmlEnumValue.1.qml" << "invalidQmlEnumValue.1.errors.txt" << false;
+ QTest::newRow("identifier enum type") << "invalidQmlEnumValue.2.qml" << "invalidQmlEnumValue.2.errors.txt" << false;
+ QTest::newRow("enum value too large") << "invalidQmlEnumValue.3.qml" << "invalidQmlEnumValue.3.errors.txt" << false;
+ QTest::newRow("non-integer enum value") << "invalidQmlEnumValue.4.qml" << "invalidQmlEnumValue.4.errors.txt" << false;
const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ?
QStringLiteral("incorrectCase.errors.sensitive.txt") :
@@ -569,6 +611,8 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("badCompositeRegistration.1") << "badCompositeRegistration.1.qml" << "badCompositeRegistration.1.errors.txt" << false;
QTest::newRow("badCompositeRegistration.2") << "badCompositeRegistration.2.qml" << "badCompositeRegistration.2.errors.txt" << false;
+
+ QTest::newRow("assignComponentToWrongType") << "assignComponentToWrongType.qml" << "assignComponentToWrongType.errors.txt" << false;
}
@@ -580,9 +624,11 @@ void tst_qqmllanguage::errors()
QQmlComponent component(&engine, testFileUrl(file));
+ QScopedPointer<QObject> object;
+
if (create) {
- QObject *object = component.create();
- QVERIFY(!object);
+ object.reset(component.create());
+ QVERIFY(object.isNull());
}
VERIFY_ERRORS(errorFile.toLatin1().constData());
@@ -592,16 +638,16 @@ void tst_qqmllanguage::simpleObject()
{
QQmlComponent component(&engine, testFileUrl("simpleObject.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
void tst_qqmllanguage::simpleContainer()
{
QQmlComponent component(&engine, testFileUrl("simpleContainer.qml"));
VERIFY_ERRORS(0);
- MyContainer *container= qobject_cast<MyContainer*>(component.create());
- QVERIFY(container != 0);
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create()));
+ QVERIFY(container != nullptr);
QCOMPARE(container->getChildren()->count(),2);
}
@@ -609,8 +655,8 @@ void tst_qqmllanguage::interfaceProperty()
{
QQmlComponent component(&engine, testFileUrl("interfaceProperty.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
+ QVERIFY(object != nullptr);
QVERIFY(object->interface());
QCOMPARE(object->interface()->id, 913);
}
@@ -619,8 +665,8 @@ void tst_qqmllanguage::interfaceQList()
{
QQmlComponent component(&engine, testFileUrl("interfaceQList.qml"));
VERIFY_ERRORS(0);
- MyContainer *container= qobject_cast<MyContainer*>(component.create());
- QVERIFY(container != 0);
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create()));
+ QVERIFY(container != nullptr);
QCOMPARE(container->getQListInterfaces()->count(), 2);
for(int ii = 0; ii < 2; ++ii)
QCOMPARE(container->getQListInterfaces()->at(ii)->id, 913);
@@ -630,8 +676,8 @@ void tst_qqmllanguage::assignObjectToSignal()
{
QQmlComponent component(&engine, testFileUrl("assignObjectToSignal.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
}
@@ -640,8 +686,8 @@ void tst_qqmllanguage::assignObjectToVariant()
{
QQmlComponent component(&engine, testFileUrl("assignObjectToVariant.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVariant v = object->property("a");
QVERIFY(v.userType() == qMetaTypeId<QObject *>());
}
@@ -650,8 +696,8 @@ void tst_qqmllanguage::assignLiteralSignalProperty()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralSignalProperty.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->onLiteralSignal(), 10);
}
@@ -660,8 +706,8 @@ void tst_qqmllanguage::assignQmlComponent()
{
QQmlComponent component(&engine, testFileUrl("assignQmlComponent.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 1);
QObject *child = object->getChildren()->at(0);
QCOMPARE(child->property("x"), QVariant(10));
@@ -673,8 +719,8 @@ void tst_qqmllanguage::assignBasicTypes()
{
QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
QCOMPARE(object->qtEnumProperty(), Qt::RichText);
@@ -703,9 +749,9 @@ void tst_qqmllanguage::assignBasicTypes()
QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2f, 2.3f));
const QUrl encoded = QUrl::fromEncoded("main.qml?with%3cencoded%3edata", QUrl::TolerantMode);
QCOMPARE(object->urlProperty(), component.url().resolved(encoded));
- QVERIFY(object->objectProperty() != 0);
+ QVERIFY(object->objectProperty() != nullptr);
MyTypeObject *child = qobject_cast<MyTypeObject *>(object->objectProperty());
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
QCOMPARE(child->intProperty(), 8);
//these used to go via script. Ensure they no longer do
@@ -718,8 +764,8 @@ void tst_qqmllanguage::assignTypeExtremes()
{
QQmlComponent component(&engine, testFileUrl("assignTypeExtremes.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->uintProperty(), 0xEE6B2800);
QCOMPARE(object->intProperty(), -0x77359400);
}
@@ -729,8 +775,8 @@ void tst_qqmllanguage::assignCompositeToType()
{
QQmlComponent component(&engine, testFileUrl("assignCompositeToType.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
// Test that literals are stored correctly in variant properties
@@ -738,8 +784,8 @@ void tst_qqmllanguage::assignLiteralToVariant()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToVariant.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVERIFY(isJSNumberType(object->property("test1").userType()));
QVERIFY(isJSNumberType(object->property("test2").userType()));
@@ -766,8 +812,6 @@ void tst_qqmllanguage::assignLiteralToVariant()
QCOMPARE(object->property("test10"), QVariant(bool(true)));
QCOMPARE(object->property("test11"), QVariant(bool(false)));
QVERIFY(object->property("test12") == QVariant(QVector4D(100, 100, 100, 100)));
-
- delete object;
}
// Test that literals are stored correctly in "var" properties
@@ -777,8 +821,8 @@ void tst_qqmllanguage::assignLiteralToVar()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToVar.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVERIFY(isJSNumberType(object->property("test1").userType()));
QCOMPARE(object->property("test2").userType(), (int)QMetaType::Double);
@@ -817,16 +861,14 @@ void tst_qqmllanguage::assignLiteralToVar()
QCOMPARE(object->property("test16"), QVariant(QVector3D(100, 100, 100)));
QCOMPARE(object->property("variantTest1Bound"), QVariant(9));
QCOMPARE(object->property("test1Bound"), QVariant(11));
-
- delete object;
}
void tst_qqmllanguage::assignLiteralToJSValue()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
- QVERIFY(root != 0);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root != nullptr);
{
MyQmlObject *object = root->findChild<MyQmlObject *>("test1");
@@ -906,6 +948,11 @@ void tst_qqmllanguage::assignLiteralToJSValue()
QJSValue value = object->qjsvalue();
QVERIFY(value.isNumber());
QCOMPARE(value.toNumber(), qreal(27));
+ } {
+ MyQmlObject *object = root->findChild<MyQmlObject *>("test23");
+ QJSValue value = object->qjsvalue();
+ QVERIFY(value.isQObject());
+ QCOMPARE(value.toQObject()->objectName(), "blah");
}
}
@@ -913,11 +960,11 @@ void tst_qqmllanguage::assignNullStrings()
{
QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QVERIFY(object->stringProperty().isNull());
QVERIFY(object->byteArrayProperty().isNull());
- QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection);
+ QMetaObject::invokeMethod(object.data(), "assignNullStringsFromJs", Qt::DirectConnection);
QVERIFY(object->stringProperty().isNull());
QVERIFY(object->byteArrayProperty().isNull());
}
@@ -927,8 +974,8 @@ void tst_qqmllanguage::bindJSValueToVar()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
- QVERIFY(root != 0);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root != nullptr);
QObject *object = root->findChild<QObject *>("varProperties");
@@ -976,8 +1023,8 @@ void tst_qqmllanguage::bindJSValueToVariant()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
- QVERIFY(root != 0);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root != nullptr);
QObject *object = root->findChild<QObject *>("variantProperties");
@@ -1025,8 +1072,8 @@ void tst_qqmllanguage::bindJSValueToType()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
- QVERIFY(root != 0);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root != nullptr);
{
MyTypeObject *object = root->findChild<MyTypeObject *>("typedProperties");
@@ -1060,8 +1107,8 @@ void tst_qqmllanguage::bindTypeToJSValue()
QQmlComponent component(&engine, testFileUrl("bindTypeToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
- QVERIFY(root != 0);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root != nullptr);
{
MyQmlObject *object = root->findChild<MyQmlObject *>("flagProperty");
@@ -1199,8 +1246,8 @@ void tst_qqmllanguage::customParserTypes()
{
QQmlComponent component(&engine, testFileUrl("customParserTypes.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("count"), QVariant(2));
}
@@ -1209,8 +1256,8 @@ void tst_qqmllanguage::rootAsQmlComponent()
{
QQmlComponent component(&engine, testFileUrl("rootAsQmlComponent.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("x"), QVariant(11));
QCOMPARE(object->getChildren()->count(), 2);
}
@@ -1233,13 +1280,13 @@ void tst_qqmllanguage::inlineQmlComponents()
{
QQmlComponent component(&engine, testFileUrl("inlineQmlComponents.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 1);
QQmlComponent *comp = qobject_cast<QQmlComponent *>(object->getChildren()->at(0));
- QVERIFY(comp != 0);
- MyQmlObject *compObject = qobject_cast<MyQmlObject *>(comp->create());
- QVERIFY(compObject != 0);
+ QVERIFY(comp != nullptr);
+ QScopedPointer<MyQmlObject> compObject(qobject_cast<MyQmlObject *>(comp->create()));
+ QVERIFY(compObject != nullptr);
QCOMPARE(compObject->value(), 11);
}
@@ -1249,18 +1296,18 @@ void tst_qqmllanguage::idProperty()
{
QQmlComponent component(&engine, testFileUrl("idProperty.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 2);
MyTypeObject *child =
qobject_cast<MyTypeObject *>(object->getChildren()->at(0));
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
QCOMPARE(child->id(), QString("myObjectId"));
QCOMPARE(object->property("object"), QVariant::fromValue((QObject *)child));
child =
qobject_cast<MyTypeObject *>(object->getChildren()->at(1));
- QVERIFY(child != 0);
+ QVERIFY(child != nullptr);
QCOMPARE(child->id(), QString("name.with.dots"));
}
{
@@ -1280,14 +1327,14 @@ void tst_qqmllanguage::autoNotifyConnection()
{
QQmlComponent component(&engine, testFileUrl("autoNotifyConnection.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QMetaProperty prop = object->metaObject()->property(object->metaObject()->indexOfProperty("receivedNotify"));
QVERIFY(prop.isValid());
- QCOMPARE(prop.read(object), QVariant::fromValue(false));
+ QCOMPARE(prop.read(object.data()), QVariant::fromValue(false));
object->setPropertyWithNotify(1);
- QCOMPARE(prop.read(object), QVariant::fromValue(true));
+ QCOMPARE(prop.read(object.data()), QVariant::fromValue(true));
}
// Tests that signals can be assigned to
@@ -1295,8 +1342,8 @@ void tst_qqmllanguage::assignSignal()
{
QQmlComponent component(&engine, testFileUrl("assignSignal.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlotWithArgs(9)");
@@ -1307,8 +1354,8 @@ void tst_qqmllanguage::assignSignalFunctionExpression()
{
QQmlComponent component(&engine, testFileUrl("assignSignalFunctionExpression.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlotWithArgs(9)");
@@ -1336,10 +1383,9 @@ void tst_qqmllanguage::overrideSignal()
QQmlComponent component(&engine, testFileUrl(file));
if (errorFile.isEmpty()) {
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
- delete object;
} else {
VERIFY_ERRORS(errorFile.toLatin1().constData());
}
@@ -1350,8 +1396,7 @@ void tst_qqmllanguage::dynamicProperties()
{
QQmlComponent component(&engine, testFileUrl("dynamicProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
QCOMPARE(object->property("intProperty"), QVariant(10));
QCOMPARE(object->property("boolProperty"), QVariant(false));
QCOMPARE(object->property("doubleProperty"), QVariant(-10.1));
@@ -1368,15 +1413,13 @@ void tst_qqmllanguage::dynamicPropertiesNested()
{
QQmlComponent component(&engine, testFileUrl("dynamicPropertiesNested.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("super_a").toInt(), 11); // Overridden
QCOMPARE(object->property("super_c").toInt(), 14); // Inherited
QCOMPARE(object->property("a").toInt(), 13); // New
QCOMPARE(object->property("b").toInt(), 12); // New
-
- delete object;
}
// Tests the creation and assignment to dynamic list properties
@@ -1384,8 +1427,8 @@ void tst_qqmllanguage::listProperties()
{
QQmlComponent component(&engine, testFileUrl("listProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 2);
}
@@ -1404,19 +1447,19 @@ void tst_qqmllanguage::dynamicObjectProperties()
{
QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
- QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)0));
- QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)0));
+ QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr));
+ QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)nullptr));
}
{
QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
- QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)0));
+ QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr));
}
}
@@ -1427,15 +1470,15 @@ void tst_qqmllanguage::dynamicSignalsAndSlots()
QQmlComponent component(&engine, testFileUrl("dynamicSignalsAndSlots.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVERIFY(object->metaObject()->indexOfMethod("signal1()") != -1);
QVERIFY(object->metaObject()->indexOfMethod("signal2()") != -1);
QVERIFY(object->metaObject()->indexOfMethod("slot1()") != -1);
QVERIFY(object->metaObject()->indexOfMethod("slot2()") != -1);
QCOMPARE(object->property("test").toInt(), 0);
- QMetaObject::invokeMethod(object, "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10)));
+ QMetaObject::invokeMethod(object.data(), "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10)));
QCOMPARE(object->property("test").toInt(), 10);
}
@@ -1443,13 +1486,44 @@ void tst_qqmllanguage::simpleBindings()
{
QQmlComponent component(&engine, testFileUrl("simpleBindings.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value1"), QVariant(10));
QCOMPARE(object->property("value2"), QVariant(10));
QCOMPARE(object->property("value3"), QVariant(21));
QCOMPARE(object->property("value4"), QVariant(10));
- QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object));
+ QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object.data()));
+}
+
+class EvaluationCounter : public QObject
+{
+ Q_OBJECT
+public:
+ int counter = 0;
+ Q_INVOKABLE void increaseEvaluationCounter() { ++counter; }
+};
+
+void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow("order1") << QString("noDoubleEvaluationForFlushedBindings.qml");
+ QTest::newRow("order2") << QString("noDoubleEvaluationForFlushedBindings.2.qml");
+}
+
+void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings()
+{
+ QFETCH(QString, fileName);
+ QQmlEngine engine;
+
+ EvaluationCounter stats;
+ engine.rootContext()->setContextProperty("stats", &stats);
+
+ QQmlComponent component(&engine, testFileUrl(fileName));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QCOMPARE(stats.counter, 1);
}
void tst_qqmllanguage::autoComponentCreation()
@@ -1457,21 +1531,21 @@ void tst_qqmllanguage::autoComponentCreation()
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreation.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->componentProperty() != 0);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
- QVERIFY(child != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
+ QVERIFY(object->componentProperty() != nullptr);
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
+ QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreation.2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->componentProperty() != 0);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
- QVERIFY(child != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
+ QVERIFY(object->componentProperty() != nullptr);
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
+ QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
}
@@ -1480,11 +1554,11 @@ void tst_qqmllanguage::autoComponentCreationInGroupProperty()
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreationInGroupProperties.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->componentProperty() != 0);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
- QVERIFY(child != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
+ QVERIFY(object->componentProperty() != nullptr);
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
+ QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
@@ -1493,8 +1567,8 @@ void tst_qqmllanguage::propertyValueSource()
{
QQmlComponent component(&engine, testFileUrl("propertyValueSource.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QList<QObject *> valueSources;
QObjectList allChildren = object->findChildren<QObject*>();
@@ -1506,16 +1580,16 @@ void tst_qqmllanguage::propertyValueSource()
QCOMPARE(valueSources.count(), 1);
MyPropertyValueSource *valueSource =
qobject_cast<MyPropertyValueSource *>(valueSources.at(0));
- QVERIFY(valueSource != 0);
- QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object));
+ QVERIFY(valueSource != nullptr);
+ QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data()));
QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty")));
}
{
QQmlComponent component(&engine, testFileUrl("propertyValueSource.2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QList<QObject *> valueSources;
QObjectList allChildren = object->findChildren<QObject*>();
@@ -1527,8 +1601,8 @@ void tst_qqmllanguage::propertyValueSource()
QCOMPARE(valueSources.count(), 1);
MyPropertyValueSource *valueSource =
qobject_cast<MyPropertyValueSource *>(valueSources.at(0));
- QVERIFY(valueSource != 0);
- QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object));
+ QVERIFY(valueSource != nullptr);
+ QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data()));
QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty")));
}
}
@@ -1537,10 +1611,10 @@ void tst_qqmllanguage::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("attachedProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object);
- QVERIFY(attached != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object.data());
+ QVERIFY(attached != nullptr);
QCOMPARE(attached->property("value"), QVariant(10));
QCOMPARE(attached->property("value2"), QVariant(13));
}
@@ -1550,8 +1624,8 @@ void tst_qqmllanguage::dynamicObjects()
{
QQmlComponent component(&engine, testFileUrl("dynamicObject.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
// Tests the registration of custom variant string converters
@@ -1559,8 +1633,8 @@ void tst_qqmllanguage::customVariantTypes()
{
QQmlComponent component(&engine, testFileUrl("customVariantTypes.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->customType().a, 10);
}
@@ -1573,8 +1647,8 @@ void tst_qqmllanguage::valueTypes()
QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->rectProperty(), QRect(10, 11, 12, 13));
@@ -1604,20 +1678,17 @@ void tst_qqmllanguage::cppnamespace()
{
QQmlComponent component(&engine, testFileUrl("cppnamespace.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("cppnamespace.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
}
@@ -1627,8 +1698,8 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
// Read through alias
QCOMPARE(object->property("valueAlias").toInt(), 10);
@@ -1639,41 +1710,37 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("valueAlias", QVariant(19));
QCOMPARE(object->property("valueAlias").toInt(), 19);
QCOMPARE(object->property("value").toInt(), 19);
-
- delete object;
}
// Complex object alias
{
QQmlComponent component(&engine, testFileUrl("alias.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
// Read through alias
MyQmlObject *v =
qvariant_cast<MyQmlObject *>(object->property("aliasObject"));
- QVERIFY(v != 0);
+ QVERIFY(v != nullptr);
QCOMPARE(v->value(), 10);
// Write through alias
MyQmlObject *v2 = new MyQmlObject();
- v2->setParent(object);
+ v2->setParent(object.data());
object->setProperty("aliasObject", qVariantFromValue(v2));
MyQmlObject *v3 =
qvariant_cast<MyQmlObject *>(object->property("aliasObject"));
- QVERIFY(v3 != 0);
+ QVERIFY(v3 != nullptr);
QCOMPARE(v3, v2);
-
- delete object;
}
// Nested aliases
{
QQmlComponent component(&engine, testFileUrl("alias.3.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 1892);
QCOMPARE(object->property("value2").toInt(), 1892);
@@ -1685,28 +1752,24 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("value2", QVariant(8080));
QCOMPARE(object->property("value").toInt(), 8080);
QCOMPARE(object->property("value2").toInt(), 8080);
-
- delete object;
}
// Enum aliases
{
QQmlComponent component(&engine, testFileUrl("alias.4.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("enumAlias").toInt(), 1);
-
- delete object;
}
// Id aliases
{
QQmlComponent component(&engine, testFileUrl("alias.5.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVariant v = object->property("otherAlias");
QCOMPARE(v.userType(), qMetaTypeId<MyQmlObject*>());
@@ -1719,16 +1782,14 @@ void tst_qqmllanguage::aliasProperties()
QCOMPARE(v.userType(), qMetaTypeId<MyQmlObject*>());
o = qvariant_cast<MyQmlObject*>(v);
QVERIFY(!o);
-
- delete object;
}
// Nested aliases - this used to cause a crash
{
QQmlComponent component(&engine, testFileUrl("alias.6.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 1923);
}
@@ -1739,23 +1800,23 @@ void tst_qqmllanguage::aliasProperties()
QQmlComponent component(&engine, testFileUrl("alias.7.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QObject *object1 = qvariant_cast<QObject *>(object->property("object"));
- QVERIFY(object1 != 0);
+ QVERIFY(object1 != nullptr);
QObject *object2 = qvariant_cast<QObject *>(object1->property("object"));
- QVERIFY(object2 != 0);
+ QVERIFY(object2 != nullptr);
QObject *alias = qvariant_cast<QObject *>(object->property("aliasedObject"));
QCOMPARE(alias, object2);
delete object1;
- QObject *alias2 = object; // "Random" start value
+ QObject *alias2 = object.data(); // "Random" start value
int status = -1;
- void *a[] = { &alias2, 0, &status };
- QMetaObject::metacall(object, QMetaObject::ReadProperty,
+ void *a[] = { &alias2, nullptr, &status };
+ QMetaObject::metacall(object.data(), QMetaObject::ReadProperty,
object->metaObject()->indexOfProperty("aliasedObject"), a);
QVERIFY(!alias2);
}
@@ -1764,24 +1825,20 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.8.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 10);
-
- delete object;
}
// Complex composite type
{
QQmlComponent component(&engine, testFileUrl("alias.9.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 10);
-
- delete object;
}
// Valuetype alias
@@ -1789,8 +1846,8 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.10.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
// Read through alias
QCOMPARE(object->property("valueAlias").toRect(), QRect(10, 11, 9, 8));
@@ -1801,16 +1858,14 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9)));
QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9));
QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9));
-
- delete object;
}
// Valuetype sub-alias
{
QQmlComponent component(&engine, testFileUrl("alias.11.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
// Read through alias
QCOMPARE(object->property("aliasProperty").toInt(), 19);
@@ -1821,8 +1876,6 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("aliasProperty", QVariant(4));
QCOMPARE(object->property("aliasProperty").toInt(), 4);
QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111));
-
- delete object;
}
// Nested aliases with a qml file
@@ -1866,6 +1919,30 @@ void tst_qqmllanguage::aliasProperties()
QVERIFY(subObject->property("success").toBool());
}
+
+ // Property bindings on group properties that are actually aliases (QTBUG-51043)
+ {
+ QQmlComponent component(&engine, testFileUrl("alias.15.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QObject> subItem = qvariant_cast<QObject*>(object->property("symbol"));
+ QVERIFY(!subItem.isNull());
+
+ QCOMPARE(subItem->property("y").toInt(), 1);
+ }
+
+ // Alias to sub-object with binding (QTBUG-57041)
+ {
+ // This is shold *not* crash.
+ QQmlComponent component(&engine, testFileUrl("alias.16.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -1873,10 +1950,9 @@ void tst_qqmllanguage::aliasPropertiesAndSignals()
{
QQmlComponent component(&engine, testFileUrl("aliasPropertiesAndSignals.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
QCOMPARE(o->property("test").toBool(), true);
- delete o;
}
// Test that the root element in a composite type can be a Component
@@ -1884,20 +1960,20 @@ void tst_qqmllanguage::componentCompositeType()
{
QQmlComponent component(&engine, testFileUrl("componentCompositeType.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
class TestType : public QObject {
Q_OBJECT
public:
- TestType(QObject *p=0) : QObject(p) {}
+ TestType(QObject *p=nullptr) : QObject(p) {}
};
class TestType2 : public QObject {
Q_OBJECT
public:
- TestType2(QObject *p=0) : QObject(p) {}
+ TestType2(QObject *p=nullptr) : QObject(p) {}
};
void tst_qqmllanguage::i18n_data()
@@ -1918,11 +1994,9 @@ void tst_qqmllanguage::i18n()
QFETCH(QString, stringProperty);
QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->stringProperty(), stringProperty);
-
- delete object;
}
// Check that the Component::onCompleted attached property works
@@ -1933,8 +2007,8 @@ void tst_qqmllanguage::onCompleted()
QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
QTest::ignoreMessage(QtDebugMsg, "Completed 10 11");
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
}
// Check that the Component::onDestruction attached property works
@@ -1942,12 +2016,11 @@ void tst_qqmllanguage::onDestruction()
{
QQmlComponent component(&engine, testFileUrl("onDestruction.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11");
- delete object;
}
// Check that assignments to QQmlScriptString properties work
@@ -1957,8 +2030,8 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QVERIFY(!object->scriptProperty().isEmpty());
QCOMPARE(object->scriptProperty().stringLiteral(), QString());
bool ok;
@@ -1966,24 +2039,24 @@ void tst_qqmllanguage::scriptString()
QCOMPARE(ok, false);
const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(object->scriptProperty());
- QVERIFY(scriptPrivate != 0);
+ QVERIFY(scriptPrivate != nullptr);
QCOMPARE(scriptPrivate->script, QString("foo + bar"));
- QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(scriptPrivate->context, qmlContext(object));
+ QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(scriptPrivate->context, qmlContext(object.data()));
- QVERIFY(object->grouped() != 0);
+ QVERIFY(object->grouped() != nullptr);
const QQmlScriptStringPrivate *groupedPrivate = QQmlScriptStringPrivate::get(object->grouped()->script());
QCOMPARE(groupedPrivate->script, QString("console.log(1921)"));
- QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(groupedPrivate->context, qmlContext(object));
+ QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(groupedPrivate->context, qmlContext(object.data()));
}
{
QQmlComponent component(&engine, testFileUrl("scriptString2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().stringLiteral(), QString("hello\\n\\\"world\\\""));
}
@@ -1991,8 +2064,8 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString3.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
bool ok;
QCOMPARE(object->scriptProperty().numberLiteral(&ok), qreal(12.345));
QCOMPARE(ok, true);
@@ -2003,8 +2076,8 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString4.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
bool ok;
QCOMPARE(object->scriptProperty().booleanLiteral(&ok), true);
QCOMPARE(ok, true);
@@ -2014,8 +2087,8 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString5.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().isNullLiteral(), true);
}
@@ -2023,20 +2096,20 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString6.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true);
}
{
QQmlComponent component(&engine, testFileUrl("scriptString7.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QQmlScriptString ss = object->scriptProperty();
{
- QQmlExpression expr(ss, /*context*/0, object);
+ QQmlExpression expr(ss, /*context*/nullptr, object.data());
QCOMPARE(expr.evaluate().toInt(), int(100));
}
@@ -2045,7 +2118,7 @@ void tst_qqmllanguage::scriptString()
QVERIFY(testScope.metaObject()->indexOfProperty("intProperty") != object->metaObject()->indexOfProperty("intProperty"));
testScope.setIntProperty(42);
- QQmlExpression expr(ss, /*context*/0, &testScope);
+ QQmlExpression expr(ss, /*context*/nullptr, &testScope);
QCOMPARE(expr.evaluate().toInt(), int(42));
}
}
@@ -2057,10 +2130,10 @@ void tst_qqmllanguage::scriptStringJs()
QQmlComponent component(&engine, testFileUrl("scriptStringJs.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
- QQmlContext *context = QQmlEngine::contextForObject(object);
- QVERIFY(context != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
+ QQmlContext *context = QQmlEngine::contextForObject(object.data());
+ QVERIFY(context != nullptr);
bool ok;
QCOMPARE(QQmlScriptStringPrivate::get(object->scriptProperty())->script, QString("\" hello \\\" world \""));
@@ -2071,8 +2144,8 @@ void tst_qqmllanguage::scriptStringJs()
QVERIFY(object->scriptProperty().numberLiteral(&ok) == 0.0 && !ok);
QVERIFY(!object->scriptProperty().booleanLiteral(&ok) && !ok);
- QJSValue inst = engine.newQObject(object);
- QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }");
+ QJSValue inst = engine.newQObject(object.data());
+ QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })");
func.callWithInstance(inst, QJSValueList() << "test a \"string ");
QCOMPARE(QQmlScriptStringPrivate::get(object->scriptProperty())->script, QString("\"test a \\\"string \""));
@@ -2134,26 +2207,27 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QUrl url = testFileUrl("scriptString7.qml");
{
QQmlEnginePrivate *eng = QQmlEnginePrivate::get(&engine);
- QQmlTypeData *td = eng->typeLoader.getType(url);
+ QQmlRefPointer<QQmlTypeData> td = eng->typeLoader.getType(url);
Q_ASSERT(td);
- const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data;
+ const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->unitData();
Q_ASSERT(readOnlyQmlUnit);
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize));
memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize);
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
- td->compilationUnit()->data = qmlUnit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = td->compilationUnit();
+ compilationUnit->setUnitData(qmlUnit);
- const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
- QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
+ const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
+ QCOMPARE(compilationUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
quint32 i;
for (i = 0; i < rootObject->nBindings; ++i) {
const QV4::CompiledData::Binding *binding = rootObject->bindingTable() + i;
- if (qmlUnit->stringAt(binding->propertyNameIndex) != QString("scriptProperty"))
+ if (compilationUnit->stringAt(binding->propertyNameIndex) != QString("scriptProperty"))
continue;
- QCOMPARE(binding->valueAsScriptString(qmlUnit), QString("intProperty"));
+ QCOMPARE(binding->valueAsScriptString(compilationUnit.data()), QString("intProperty"));
const_cast<QV4::CompiledData::Binding*>(binding)->stringIndex = 0; // empty string index
- QVERIFY(binding->valueAsScriptString(qmlUnit).isEmpty());
+ QVERIFY(binding->valueAsScriptString(compilationUnit.data()).isEmpty());
break;
}
QVERIFY(i < rootObject->nBindings);
@@ -2161,8 +2235,8 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QQmlComponent component(&engine, url);
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
+ QVERIFY(object != nullptr);
QQmlScriptString ss = object->scriptProperty();
QVERIFY(!ss.isEmpty());
QCOMPARE(ss.stringLiteral(), QString());
@@ -2171,13 +2245,13 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QCOMPARE(ok, false);
const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(ss);
- QVERIFY(scriptPrivate != 0);
+ QVERIFY(scriptPrivate != nullptr);
QVERIFY(scriptPrivate->script.isEmpty());
- QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(scriptPrivate->context, qmlContext(object));
+ QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(scriptPrivate->context, qmlContext(object.data()));
{
- QQmlExpression expr(ss, /*context*/0, object);
+ QQmlExpression expr(ss, /*context*/nullptr, object.data());
QCOMPARE(expr.evaluate().toInt(), int(100));
}
}
@@ -2188,23 +2262,23 @@ void tst_qqmllanguage::scriptStringComparison()
{
QQmlComponent component1(&engine, testFileUrl("scriptString.qml"));
QVERIFY(!component1.isError() && component1.errors().isEmpty());
- MyTypeObject *object1 = qobject_cast<MyTypeObject*>(component1.create());
- QVERIFY(object1 != 0);
+ QScopedPointer<MyTypeObject> object1(qobject_cast<MyTypeObject*>(component1.create()));
+ QVERIFY(object1 != nullptr);
QQmlComponent component2(&engine, testFileUrl("scriptString2.qml"));
QVERIFY(!component2.isError() && component2.errors().isEmpty());
- MyTypeObject *object2 = qobject_cast<MyTypeObject*>(component2.create());
- QVERIFY(object2 != 0);
+ QScopedPointer<MyTypeObject> object2(qobject_cast<MyTypeObject*>(component2.create()));
+ QVERIFY(object2 != nullptr);
QQmlComponent component3(&engine, testFileUrl("scriptString3.qml"));
QVERIFY(!component3.isError() && component3.errors().isEmpty());
- MyTypeObject *object3 = qobject_cast<MyTypeObject*>(component3.create());
- QVERIFY(object3 != 0);
+ QScopedPointer<MyTypeObject> object3(qobject_cast<MyTypeObject*>(component3.create()));
+ QVERIFY(object3 != nullptr);
//QJSValue inst1 = engine.newQObject(object1);
- QJSValue inst2 = engine.newQObject(object2);
- QJSValue inst3 = engine.newQObject(object3);
- QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }");
+ QJSValue inst2 = engine.newQObject(object2.data());
+ QJSValue inst3 = engine.newQObject(object3.data());
+ QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })");
const QString s = "hello\\n\\\"world\\\"";
const qreal n = 12.345;
@@ -2258,8 +2332,8 @@ void tst_qqmllanguage::scriptStringComparison()
// While this are two instances of the same object they are still considered different
// because the (none literal) script string may access variables which have different
// values in both instances and hence evaluated to different results.
- MyTypeObject *object1_2 = qobject_cast<MyTypeObject*>(component1.create());
- QVERIFY(object1_2 != 0);
+ QScopedPointer<MyTypeObject> object1_2(qobject_cast<MyTypeObject*>(component1.create()));
+ QVERIFY(object1_2 != nullptr);
QVERIFY(object1->scriptProperty() != object1_2->scriptProperty());
}
@@ -2270,8 +2344,8 @@ void tst_qqmllanguage::defaultPropertyListOrder()
QQmlComponent component(&engine, testFileUrl("defaultPropertyListOrder.qml"));
VERIFY_ERRORS(0);
- MyContainer *container = qobject_cast<MyContainer *>(component.create());
- QVERIFY(container != 0);
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer *>(component.create()));
+ QVERIFY(container != nullptr);
QCOMPARE(container->getChildren()->count(), 6);
QCOMPARE(container->getChildren()->at(0)->property("index"), QVariant(0));
@@ -2291,15 +2365,13 @@ void tst_qqmllanguage::declaredPropertyValues()
void tst_qqmllanguage::dontDoubleCallClassBegin()
{
QQmlComponent component(&engine, testFileUrl("dontDoubleCallClassBegin.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
MyParserStatus *o2 = qobject_cast<MyParserStatus *>(qvariant_cast<QObject *>(o->property("object")));
QVERIFY(o2);
QCOMPARE(o2->classBeginCount(), 1);
QCOMPARE(o2->componentCompleteCount(), 1);
-
- delete o;
}
void tst_qqmllanguage::reservedWords_data()
@@ -2399,10 +2471,9 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q
QCOMPARE(actualerror.left(partialMatch ? expectederror.length(): -1),expectederror);
} else {
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(QString(object->metaObject()->className()), type);
- delete object;
}
engine.setImportPathList(defaultImportPathList);
@@ -2413,10 +2484,9 @@ void tst_qqmllanguage::inlineAssignmentsOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("inlineAssignmentsOverrideBindings.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 11);
- delete o;
}
// QTBUG-19354
@@ -2847,10 +2917,9 @@ void tst_qqmllanguage::importsPath()
QTRY_VERIFY(component.isReady());
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toString(), value);
- delete object;
engine.setImportPathList(defaultImportPathList);
}
@@ -3058,40 +3127,102 @@ void tst_qqmllanguage::importJs()
}
if (performTest) {
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(),true);
- delete object;
}
engine.setImportPathList(defaultImportPathList);
}
+void tst_qqmllanguage::importJsModule_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QTest::newRow("plainImport")
+ << "importJsModule.1.qml";
+
+ QTest::newRow("ImportQmlStyle")
+ << "importJsModule.2.qml";
+
+ QTest::newRow("plainImportWithCycle")
+ << "importJsModule.3.qml";
+}
+
+void tst_qqmllanguage::importJsModule()
+{
+ QFETCH(QString, file);
+
+ engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));
+ auto importPathGuard = qScopeGuard([this]{
+ engine.setImportPathList(defaultImportPathList);
+ });
+
+ QQmlComponent component(&engine, testFileUrl(file));
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QCOMPARE(object->property("test").toBool(),true);
+}
+
+void tst_qqmllanguage::explicitSelfImport()
+{
+ engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));
+
+ QQmlComponent component(&engine, testFileUrl("mixedModuleWithSelfImport.qml"));
+ QVERIFY(component.errors().count() == 0);
+
+ engine.setImportPathList(defaultImportPathList);
+}
+
+void tst_qqmllanguage::importInternalType()
+{
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+
+ {
+ QQmlComponent component(&engine);
+ component.setData("import modulewithinternaltypes 1.0\nPublicType{}", QUrl());
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("myInternalType").value<QObject*>() != 0);
+ }
+ {
+ QQmlComponent component(&engine);
+ component.setData("import modulewithinternaltypes 1.0\nPublicTypeWithExplicitImport{}", QUrl());
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("myInternalType").value<QObject*>() != 0);
+ }
+}
+
void tst_qqmllanguage::qmlAttachedPropertiesObjectMethod()
{
QObject object;
- QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(&object, false), (QObject *)0);
+ QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(&object, false), (QObject *)nullptr);
QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(&object, true));
{
QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
- QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object, false), (QObject *)0);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != 0);
+ QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false), (QObject *)nullptr);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr);
}
{
QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, false) != 0);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != 0);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false) != nullptr);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr);
}
}
@@ -3112,12 +3243,10 @@ void tst_qqmllanguage::customOnProperty()
QQmlComponent component(&engine, testFileUrl("customOnProperty.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("on").toInt(), 10);
-
- delete object;
}
// QTBUG-12601
@@ -3126,12 +3255,10 @@ void tst_qqmllanguage::variantNotify()
QQmlComponent component(&engine, testFileUrl("variantNotify.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("notifyCount").toInt(), 1);
-
- delete object;
}
void tst_qqmllanguage::revisions()
@@ -3140,38 +3267,32 @@ void tst_qqmllanguage::revisions()
QQmlComponent component(&engine, testFileUrl("revisions11.qml"));
VERIFY_ERRORS(0);
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyRevisionedClass> object(qobject_cast<MyRevisionedClass*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->prop2(), 10.0);
-
- delete object;
}
{
QQmlEngine myEngine;
QQmlComponent component(&myEngine, testFileUrl("revisionssub11.qml"));
VERIFY_ERRORS(0);
- MyRevisionedSubclass *object = qobject_cast<MyRevisionedSubclass*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyRevisionedSubclass> object(qobject_cast<MyRevisionedSubclass*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->prop1(), 10.0);
QCOMPARE(object->prop2(), 10.0);
QCOMPARE(object->prop3(), 10.0);
QCOMPARE(object->prop4(), 10.0);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("versionedbase.qml"));
VERIFY_ERRORS(0);
- MySubclass *object = qobject_cast<MySubclass*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MySubclass> object(qobject_cast<MySubclass*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->prop1(), 10.0);
QCOMPARE(object->prop2(), 10.0);
-
- delete object;
}
}
@@ -3217,8 +3338,8 @@ void tst_qqmllanguage::subclassedUncreateableRevision()
QQmlComponent c(&engine);
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
- QCOMPARE(obj, static_cast<QObject*>(0));
+ QScopedPointer<QObject> obj(c.create());
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
QCOMPARE(c.errors().count(), 1);
QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass"));
}
@@ -3229,17 +3350,16 @@ void tst_qqmllanguage::subclassedUncreateableRevision()
if (!shouldWork)
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
if (!shouldWork) {
- QCOMPARE(obj, static_cast<QObject*>(0));
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
return;
}
QVERIFY(obj);
- MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj);
+ MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj.data());
QVERIFY(base);
QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
- delete obj;
}
void tst_qqmllanguage::subclassedExtendedUncreateableRevision_data()
@@ -3273,8 +3393,8 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision()
QQmlComponent c(&engine);
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
- QCOMPARE(obj, static_cast<QObject*>(0));
+ QScopedPointer<QObject> obj(c.create());
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
QCOMPARE(c.errors().count(), 1);
QCOMPARE(c.errors().first().description(), QString("Cannot create MyExtendedUncreateableBaseClass"));
}
@@ -3285,17 +3405,16 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision()
if (!shouldWork)
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
if (!shouldWork) {
- QCOMPARE(obj, static_cast<QObject*>(0));
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
return;
}
QVERIFY(obj);
- MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj);
+ MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj.data());
QVERIFY(base);
QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
- delete obj;
}
void tst_qqmllanguage::uncreatableTypesAsProperties()
@@ -3356,12 +3475,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals()
QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
}
// QTCREATORBUG-2769
@@ -3369,12 +3486,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals()
QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.2.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
}
}
@@ -3385,24 +3500,20 @@ void tst_qqmllanguage::propertyInit()
QQmlComponent component(&engine, testFileUrl("propertyInit.1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 1);
-
- delete o;
}
{
QQmlComponent component(&engine, testFileUrl("propertyInit.2.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 123);
-
- delete o;
}
}
@@ -3412,18 +3523,17 @@ void tst_qqmllanguage::registrationOrder()
{
QQmlComponent component(&engine, testFileUrl("registrationOrder.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->metaObject(), &MyVersion2Class::staticMetaObject);
- delete o;
}
void tst_qqmllanguage::readonly()
{
QQmlComponent component(&engine, testFileUrl("readonly.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toInt(), 10);
QCOMPARE(o->property("test2").toInt(), 18);
@@ -3448,8 +3558,6 @@ void tst_qqmllanguage::readonly()
QCOMPARE(o->property("test1").toInt(), 10);
QCOMPARE(o->property("test2").toInt(), 22);
QCOMPARE(o->property("test3").toInt(), 2);
-
- delete o;
}
void tst_qqmllanguage::readonlyObjectProperties()
@@ -3474,8 +3582,8 @@ void tst_qqmllanguage::receivers()
{
QQmlComponent component(&engine, testFileUrl("receivers.qml"));
- MyReceiversTestObject *o = qobject_cast<MyReceiversTestObject*>(component.create());
- QVERIFY(o != 0);
+ QScopedPointer<MyReceiversTestObject> o(qobject_cast<MyReceiversTestObject*>(component.create()));
+ QVERIFY(o != nullptr);
QCOMPARE(o->mySignalCount(), 1);
QCOMPARE(o->propChangedCount(), 2);
QCOMPARE(o->myUnconnectedSignalCount(), 0);
@@ -3483,8 +3591,6 @@ void tst_qqmllanguage::receivers()
QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::mySignal)));
QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::propChanged)));
QVERIFY(!o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::myUnconnectedSignal)));
-
- delete o;
}
void tst_qqmllanguage::registeredCompositeType()
@@ -3492,10 +3598,8 @@ void tst_qqmllanguage::registeredCompositeType()
QQmlComponent component(&engine, testFileUrl("registeredCompositeType.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- delete o;
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
}
// QTBUG-43582
@@ -3504,14 +3608,12 @@ void tst_qqmllanguage::registeredCompositeTypeWithEnum()
QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithEnum.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0));
QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42));
QCOMPARE(o->property("enumValue15").toInt(), static_cast<int>(MyCompositeBaseType::ScopedCompositeEnum::EnumValue15));
-
- delete o;
}
// QTBUG-43581
@@ -3520,12 +3622,10 @@ void tst_qqmllanguage::registeredCompositeTypeWithAttachedProperty()
QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithAttachedProperty.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
QCOMPARE(o->property("attachedProperty").toString(), QStringLiteral("test"));
-
- delete o;
}
// QTBUG-18268
@@ -3538,16 +3638,15 @@ void tst_qqmllanguage::remoteLoadCrash()
while (component.isLoading())
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50);
- QObject *o = component.create();
- delete o;
+ QScopedPointer<QObject> o(component.create());
}
void tst_qqmllanguage::signalWithDefaultArg()
{
QQmlComponent component(&engine, testFileUrl("signalWithDefaultArg.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("signalCount").toInt(), 0);
QCOMPARE(object->property("signalArg").toInt(), 0);
@@ -3561,15 +3660,13 @@ void tst_qqmllanguage::signalWithDefaultArg()
QCOMPARE(object->property("signalArg").toInt(), 15);
- QMetaObject::invokeMethod(object, "emitNoArgSignal");
+ QMetaObject::invokeMethod(object.data(), "emitNoArgSignal");
QCOMPARE(object->property("signalCount").toInt(), 3);
QCOMPARE(object->property("signalArg").toInt(), 5);
- QMetaObject::invokeMethod(object, "emitArgSignal");
+ QMetaObject::invokeMethod(object.data(), "emitArgSignal");
QCOMPARE(object->property("signalCount").toInt(), 4);
QCOMPARE(object->property("signalArg").toInt(), 22);
-
- delete object;
}
void tst_qqmllanguage::signalParameterTypes()
@@ -3577,19 +3674,17 @@ void tst_qqmllanguage::signalParameterTypes()
// bound signal handlers
{
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.1.qml"));
- QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
- delete obj;
}
// dynamic signal connections
{
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml"));
- QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
- delete obj;
}
}
@@ -3602,15 +3697,15 @@ void tst_qqmllanguage::globalEnums()
QQmlComponent component(&engine, testFileUrl("globalEnums.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
MyEnum1Class *enum1Class = o->findChild<MyEnum1Class *>(QString::fromLatin1("enum1Class"));
- QVERIFY(enum1Class != 0);
+ QVERIFY(enum1Class != nullptr);
QVERIFY(enum1Class->getValue() == -1);
MyEnumDerivedClass *enum2Class = o->findChild<MyEnumDerivedClass *>(QString::fromLatin1("enumDerivedClass"));
- QVERIFY(enum2Class != 0);
+ QVERIFY(enum2Class != nullptr);
QVERIFY(enum2Class->getValueA() == -1);
QVERIFY(enum2Class->getValueB() == -1);
QVERIFY(enum2Class->getValueC() == 0);
@@ -3628,7 +3723,7 @@ void tst_qqmllanguage::globalEnums()
QSignalSpy signalA(enum2Class, SIGNAL(valueAChanged(MyEnum1Class::EnumA)));
QSignalSpy signalB(enum2Class, SIGNAL(valueBChanged(MyEnum2Class::EnumB)));
- QMetaObject::invokeMethod(o, "setEnumValues");
+ QMetaObject::invokeMethod(o.data(), "setEnumValues");
QVERIFY(enum1Class->getValue() == MyEnum1Class::A_13);
QVERIFY(enum2Class->getValueA() == MyEnum1Class::A_11);
@@ -3647,8 +3742,6 @@ void tst_qqmllanguage::globalEnums()
QVERIFY(enum2Class->property("dValue") == 2);
QVERIFY(enum2Class->property("eValue") == 14);
QVERIFY(enum2Class->property("e2Value") == 76);
-
- delete o;
}
void tst_qqmllanguage::lowercaseEnumRuntime_data()
@@ -3694,19 +3787,89 @@ void tst_qqmllanguage::scopedEnum()
{
QQmlComponent component(&engine, testFileUrl("scopedEnum.qml"));
- MyTypeObject *o = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(o != 0);
+ QScopedPointer<MyTypeObject> o(qobject_cast<MyTypeObject *>(component.create()));
+ QVERIFY(o != nullptr);
QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal1);
QCOMPARE(o->intProperty(), (int)MyTypeObject::MyScopedEnum::ScopedVal2);
QCOMPARE(o->property("listValue").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal3);
QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal1);
- QMetaObject::invokeMethod(o, "assignNewValue");
+ QMetaObject::invokeMethod(o.data(), "assignNewValue");
QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal2);
QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal2);
}
+void tst_qqmllanguage::scopedEnumsWithNameClash()
+{
+ auto typeId = qmlRegisterUncreatableType<ScopedEnumsWithNameClash>("ScopedEnumsWithNameClashTest", 1, 0, "ScopedEnum", "Dummy reason");
+ auto registryGuard = qScopeGuard([typeId]() {
+ QQmlMetaType::unregisterType(typeId);
+ });
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("scopedEnumsWithNameClash.qml"));
+
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Previously registered enum will be overwritten due to name clash: ScopedEnumsWithNameClash.ScopedVal1");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Previously registered enum will be overwritten due to name clash: ScopedEnumsWithNameClash.ScopedVal2");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Previously registered enum will be overwritten due to name clash: ScopedEnumsWithNameClash.ScopedVal3");
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
+ QVERIFY(obj->property("success").toBool());
+}
+
+void tst_qqmllanguage::scopedEnumsWithResolvedNameClash()
+{
+ auto typeId = qmlRegisterUncreatableType<ScopedEnumsWithResolvedNameClash>("ScopedEnumsWithResolvedNameClashTest", 1, 0, "ScopedEnum", "Dummy reason");
+ auto registryGuard = qScopeGuard([typeId]() {
+ QQmlMetaType::unregisterType(typeId);
+ });
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("scopedEnumsWithResolvedNameClash.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != nullptr);
+ QVERIFY(obj->property("success").toBool());
+}
+
+void tst_qqmllanguage::qmlEnums()
+{
+ QQmlEngine engine;
+ engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));
+
+ {
+ QQmlComponent component(&engine, testFileUrl("TypeWithEnum.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("enumValue").toInt(), 1);
+ QCOMPARE(o->property("enumValue2").toInt(), 2);
+ QCOMPARE(o->property("scopedEnumValue").toInt(), 1);
+
+ QCOMPARE(o->property("otherEnumValue1").toInt(), 24);
+ QCOMPARE(o->property("otherEnumValue2").toInt(), 25);
+ QCOMPARE(o->property("otherEnumValue3").toInt(), 24);
+ QCOMPARE(o->property("otherEnumValue4").toInt(), 25);
+ QCOMPARE(o->property("otherEnumValue5").toInt(), 1);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("usingTypeWithEnum.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("enumValue").toInt(), 1);
+ QCOMPARE(o->property("enumValue2").toInt(), 0);
+ QCOMPARE(o->property("scopedEnumValue").toInt(), 2);
+ QCOMPARE(o->property("enumValueFromSingleton").toInt(), 42);
+ // while this next test verifies current duplication behavior, I'm not sure it should be codified
+ QCOMPARE(o->property("duplicatedEnumValueFromSingleton").toInt(), 2);
+ QCOMPARE(o->property("scopedEnumValueFromSingleton1").toInt(), 43);
+ QCOMPARE(o->property("scopedEnumValueFromSingleton2").toInt(), 2);
+ QCOMPARE(o->property("scopedEnumValueFromSingleton3").toInt(), 2);
+ }
+}
+
void tst_qqmllanguage::literals_data()
{
QTest::addColumn<QString>("property");
@@ -3744,10 +3907,9 @@ void tst_qqmllanguage::literals()
QQmlComponent component(&engine, testFile("literals.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property(property.toLatin1()), value);
- delete object;
}
void tst_qqmllanguage::objectDeletionNotify_data()
@@ -3766,19 +3928,17 @@ void tst_qqmllanguage::objectDeletionNotify()
QQmlComponent component(&engine, testFile(file));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
- QMetaObject::invokeMethod(object, "destroyObject");
+ QMetaObject::invokeMethod(object.data(), "destroyObject");
// Process the deletion event
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QCOMPARE(object->property("success").toBool(), true);
-
- delete object;
}
void tst_qqmllanguage::scopedProperties()
@@ -3786,7 +3946,7 @@ void tst_qqmllanguage::scopedProperties()
QQmlComponent component(&engine, testFile("scopedProperties.qml"));
QScopedPointer<QObject> o(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QVERIFY(o->property("success").toBool());
}
@@ -3794,7 +3954,7 @@ void tst_qqmllanguage::deepProperty()
{
QQmlComponent component(&engine, testFile("deepProperty.qml"));
QScopedPointer<QObject> o(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
QFont font = qvariant_cast<QFont>(qvariant_cast<QObject*>(o->property("someObject"))->property("font"));
QCOMPARE(font.family(), QStringLiteral("test"));
}
@@ -3812,11 +3972,11 @@ void tst_qqmllanguage::implicitImportsLast()
QQmlComponent component(&engine, testFile("localOrderTest.qml"));
VERIFY_ERRORS(0);
- QObject *object = qobject_cast<QObject *>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QQuickMouseArea")));
QObject* object2 = object->property("item").value<QObject*>();
- QVERIFY(object2 != 0);
+ QVERIFY(object2 != nullptr);
QCOMPARE(QString(object2->metaObject()->className()), QLatin1String("QQuickRectangle"));
engine.setImportPathList(defaultImportPathList);
@@ -3824,36 +3984,38 @@ void tst_qqmllanguage::implicitImportsLast()
void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* fileName, const char* propertyName, QObject** result /* out */)
{
- QVERIFY(fileName != 0);
- QVERIFY(propertyName != 0);
+ QVERIFY(fileName != nullptr);
+ QVERIFY(propertyName != nullptr);
if (!fileName || !propertyName)
return;
QQmlComponent component(&engine, testFile(fileName));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
- getSingletonInstance(object, propertyName, result);
+ getSingletonInstance(object.data(), propertyName, result);
}
void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */)
{
- QVERIFY(o != 0);
- QVERIFY(propertyName != 0);
+ QVERIFY(o != nullptr);
+ QVERIFY(propertyName != nullptr);
if (!o || !propertyName)
return;
QVariant variant = o->property(propertyName);
- QVERIFY(variant.userType() == qMetaTypeId<QObject *>());
+ QVERIFY(variant.isValid());
- QObject *singleton = NULL;
- if (variant.canConvert<QObject*>())
+ QObject *singleton = nullptr;
+ if (variant.userType() == qMetaTypeId<QObject *>())
singleton = variant.value<QObject*>();
+ else if (variant.userType() == qMetaTypeId<QJSValue>())
+ singleton = variant.value<QJSValue>().toQObject();
- QVERIFY(singleton != 0);
+ QVERIFY(singleton != nullptr);
*result = singleton;
}
@@ -3872,24 +4034,24 @@ void tst_qqmllanguage::compositeSingletonProperties()
{
QQmlComponent component(&engine, testFile("singletonTest1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
}
// Checks that the addresses of the composite singletons used in the same
// engine are the same.
void tst_qqmllanguage::compositeSingletonSameEngine()
{
- QObject* s1 = NULL;
+ QObject* s1 = nullptr;
getSingletonInstance(engine, "singletonTest2.qml", "singleton1", &s1);
- QVERIFY(s1 != 0);
+ QVERIFY(s1 != nullptr);
s1->setProperty("testProp2", QVariant(13));
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(engine, "singletonTest3.qml", "singleton2", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s2->property("testProp2"), QVariant(13));
QCOMPARE(s1, s2);
@@ -3901,14 +4063,14 @@ void tst_qqmllanguage::compositeSingletonDifferentEngine()
{
QQmlEngine e2;
- QObject* s1 = NULL;
+ QObject* s1 = nullptr;
getSingletonInstance(engine, "singletonTest2.qml", "singleton1", &s1);
- QVERIFY(s1 != 0);
+ QVERIFY(s1 != nullptr);
s1->setProperty("testProp2", QVariant(13));
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(e2, "singletonTest3.qml", "singleton2", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s2->property("testProp2"), QVariant(25));
QVERIFY(s1 != s2);
@@ -3926,20 +4088,20 @@ void tst_qqmllanguage::compositeSingletonQualifiedNamespace()
{
QQmlComponent component(&engine, testFile("singletonTest5.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file (without namespace!)
- QObject *s1 = NULL;
- getSingletonInstance(o, "singletonInstance", &s1);
- QVERIFY(s1 != 0);
+ QObject *s1 = nullptr;
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
+ QVERIFY(s1 != nullptr);
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(engine, "singletonTest5a.qml", "singletonInstance", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s1, s2);
}
@@ -3951,21 +4113,21 @@ void tst_qqmllanguage::compositeSingletonModule()
QQmlComponent component(&engine, testFile("singletonTest6.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
- verifyCompositeSingletonPropertyValues(o, "value3", 125, "value4", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 125, "value4", -55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
- QObject *s1 = NULL;
- getSingletonInstance(o, "singletonInstance", &s1);
- QVERIFY(s1 != 0);
+ QObject *s1 = nullptr;
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
+ QVERIFY(s1 != nullptr);
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(engine, "singletonTest6a.qml", "singletonInstance", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s1, s2);
}
@@ -3977,21 +4139,21 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned()
QQmlComponent component(&engine, testFile("singletonTest7.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
- verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
- QObject *s1 = NULL;
- getSingletonInstance(o, "singletonInstance", &s1);
- QVERIFY(s1 != 0);
+ QObject *s1 = nullptr;
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
+ QVERIFY(s1 != nullptr);
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(engine, "singletonTest7a.qml", "singletonInstance", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s1, s2);
}
@@ -4003,21 +4165,21 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
QQmlComponent component(&engine, testFile("singletonTest8.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
- verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
- QObject *s1 = NULL;
- getSingletonInstance(o, "singletonInstance", &s1);
- QVERIFY(s1 != 0);
+ QObject *s1 = nullptr;
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
+ QVERIFY(s1 != nullptr);
- QObject* s2 = NULL;
+ QObject* s2 = nullptr;
getSingletonInstance(engine, "singletonTest8a.qml", "singletonInstance", &s2);
- QVERIFY(s2 != 0);
+ QVERIFY(s2 != nullptr);
QCOMPARE(s1, s2);
}
@@ -4042,10 +4204,10 @@ void tst_qqmllanguage::compositeSingletonDynamicSignal()
{
QQmlComponent component(&engine, testFile("singletonTest11.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55);
}
// Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it.
@@ -4091,10 +4253,10 @@ void tst_qqmllanguage::compositeSingletonRemote()
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50);
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 525, "value2", 355);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 525, "value2", 355);
}
// Load a composite singleton type and a javascript file that has .pragma library
@@ -4104,14 +4266,14 @@ void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
{
QQmlComponent component(&engine, testFile("singletonTest16.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 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, "value1", 99, "value2", 333);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333);
}
// Reads values from a Singleton accessed through selectors.
@@ -4122,10 +4284,10 @@ void tst_qqmllanguage::compositeSingletonSelectors()
qmlSelector.setExtraSelectors(QStringList() << "basicSelector");
QQmlComponent component(&e2, testFile("singletonTest1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 625, "value2", 455);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 625, "value2", 455);
}
// Reads values from a Singleton that was registered through the C++ API:
@@ -4134,10 +4296,44 @@ void tst_qqmllanguage::compositeSingletonRegistered()
{
QQmlComponent component(&engine, testFile("singletonTest17.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
+
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 925, "value2", 755);
+}
+
+void tst_qqmllanguage::compositeSingletonCircular()
+{
+ QQmlComponent component(&engine, testFile("circularSingleton.qml"));
+ VERIFY_ERRORS(0);
+
+ QQmlTestMessageHandler messageHandler;
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
+
+ // ensure we aren't hitting the recursion warning
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+
+ QCOMPARE(o->property("value").toInt(), 2);
+}
+
+void tst_qqmllanguage::singletonsHaveContextAndEngine()
+{
+ QObject *qmlSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "qmlSingleton", &qmlSingleton);
+ QVERIFY(qmlContext(qmlSingleton));
+ QCOMPARE(qmlEngine(qmlSingleton), &engine);
- verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755);
+ QObject *jsSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "jsSingleton", &jsSingleton);
+ QVERIFY(qmlContext(jsSingleton));
+ QCOMPARE(qmlEngine(jsSingleton), &engine);
+
+ QObject *cppSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "cppSingleton", &cppSingleton);
+ QVERIFY(qmlContext(cppSingleton));
+ QCOMPARE(qmlEngine(cppSingleton), &engine);
}
void tst_qqmllanguage::customParserBindingScopes()
@@ -4219,7 +4415,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects()
QVERIFY(ddata);
QQmlPropertyCache *subCache = ddata->propertyCache;
QVERIFY(subCache);
- QQmlPropertyData *pd = subCache->property(QStringLiteral("newProperty"), /*object*/0, /*context*/0);
+ QQmlPropertyData *pd = subCache->property(QStringLiteral("newProperty"), /*object*/nullptr, /*context*/nullptr);
QVERIFY(pd);
QCOMPARE(pd->propType(), qMetaTypeId<int>());
}
@@ -4269,13 +4465,225 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
QVERIFY(!ddata->rootObjectInCreation);
}
+// QTBUG-63036
+void tst_qqmllanguage::lazyDeferredSubObject()
+{
+ QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObject *subObject = qvariant_cast<QObject *>(object->property("subObject"));
+ QVERIFY(subObject);
+
+ QCOMPARE(object->objectName(), QStringLiteral("custom"));
+ QCOMPARE(subObject->objectName(), QStringLiteral("custom"));
+}
+
+// QTBUG-63200
+void tst_qqmllanguage::deferredProperties()
+{
+ QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObject *innerObj = object->findChild<QObject *>(QStringLiteral("innerobj"));
+ QVERIFY(!innerObj);
+
+ QObject *outerObj = object->findChild<QObject *>(QStringLiteral("outerobj"));
+ QVERIFY(!outerObj);
+
+ QObject *groupProperty = object->property("groupProperty").value<QObject *>();
+ QVERIFY(!groupProperty);
+
+ QQmlListProperty<QObject> listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ QQmlData *qmlData = QQmlData::get(object.data());
+ QVERIFY(qmlData);
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 3); // "innerobj", "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 3); // "outerobj", "outerlist1", "outerlist2"
+
+ qmlExecuteDeferred(object.data());
+
+ QCOMPARE(qmlData->deferredData.count(), 0);
+
+ innerObj = object->findChild<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
+ QVERIFY(innerObj);
+ QCOMPARE(innerObj->property("wasCompleted"), QVariant(true));
+
+ outerObj = object->findChild<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml
+ QVERIFY(outerObj);
+ QCOMPARE(outerObj->property("wasCompleted"), QVariant(true));
+
+ groupProperty = object->property("groupProperty").value<QObject *>();
+ QCOMPARE(groupProperty, outerObj);
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 4);
+
+ QCOMPARE(listProperty.at(&listProperty, 0)->objectName(), QStringLiteral("innerlist1")); // MyDeferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 0)->property("wasCompleted"), QVariant(true));
+ QCOMPARE(listProperty.at(&listProperty, 1)->objectName(), QStringLiteral("innerlist2")); // MyDeferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 1)->property("wasCompleted"), QVariant(true));
+
+ QCOMPARE(listProperty.at(&listProperty, 2)->objectName(), QStringLiteral("outerlist1")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 2)->property("wasCompleted"), QVariant(true));
+ QCOMPARE(listProperty.at(&listProperty, 3)->objectName(), QStringLiteral("outerlist2")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 3)->property("wasCompleted"), QVariant(true));
+}
+
+static void beginDeferredOnce(QQmlEnginePrivate *enginePriv,
+ const QQmlProperty &property, QQmlComponentPrivate::DeferredState *deferredState)
+{
+ QObject *object = property.object();
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(!ddata->deferredData.isEmpty());
+
+ int propertyIndex = property.index();
+
+ for (auto dit = ddata->deferredData.rbegin(); dit != ddata->deferredData.rend(); ++dit) {
+ QQmlData::DeferredData *deferData = *dit;
+
+ auto range = deferData->bindings.equal_range(propertyIndex);
+ if (range.first == deferData->bindings.end())
+ continue;
+
+ QQmlComponentPrivate::ConstructionState *state = new QQmlComponentPrivate::ConstructionState;
+ state->completePending = true;
+
+ QQmlContextData *creationContext = nullptr;
+ state->creator.reset(new QQmlObjectCreator(deferData->context->parent, deferData->compilationUnit, creationContext));
+
+ enginePriv->inProgressCreations++;
+
+ typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash;
+ auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second);
+ auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first);
+ while (it != last) {
+ if (!state->creator->populateDeferredBinding(property, deferData, *it))
+ state->errors << state->creator->errors;
+ ++it;
+ }
+
+ deferredState->constructionStates += state;
+
+ // Cleanup any remaining deferred bindings for this property, also in inner contexts,
+ // to avoid executing them later and overriding the property that was just populated.
+ while (dit != ddata->deferredData.rend()) {
+ (*dit)->bindings.remove(propertyIndex);
+ ++dit;
+ }
+ break;
+ }
+}
+
+static void testExecuteDeferredOnce(const QQmlProperty &property)
+{
+ QObject *object = property.object();
+ QQmlData *data = QQmlData::get(object);
+ if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
+
+ QQmlComponentPrivate::DeferredState state;
+ beginDeferredOnce(ep, property, &state);
+
+ // Release deferred data for those compilation units that no longer have deferred bindings
+ data->releaseDeferredData();
+
+ QQmlComponentPrivate::completeDeferred(ep, &state);
+ }
+}
+
+void tst_qqmllanguage::executeDeferredPropertiesOnce()
+{
+ QQmlComponent component(&engine, testFile("deferredProperties.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObjectList innerObjsAtCreation = object->findChildren<QObject *>(QStringLiteral("innerobj"));
+ QVERIFY(innerObjsAtCreation.isEmpty());
+
+ QObjectList outerObjsAtCreation = object->findChildren<QObject *>(QStringLiteral("outerobj"));
+ QVERIFY(outerObjsAtCreation.isEmpty());
+
+ QObject *groupProperty = object->property("groupProperty").value<QObject *>();
+ QVERIFY(!groupProperty);
+
+ QQmlListProperty<QObject> listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ QQmlData *qmlData = QQmlData::get(object.data());
+ QVERIFY(qmlData);
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 3); // "innerobj", "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 3); // "outerobj", "outerlist1", "outerlist2"
+
+ // first execution creates the outer object
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "groupProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 2); // "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 2); // "outerlist1", "outerlist2"
+
+ QObjectList innerObjsAfterFirstExecute = object->findChildren<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
+ QVERIFY(innerObjsAfterFirstExecute.isEmpty());
+
+ QObjectList outerObjsAfterFirstExecute = object->findChildren<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml
+ QCOMPARE(outerObjsAfterFirstExecute.count(), 1);
+ QCOMPARE(outerObjsAfterFirstExecute.first()->property("wasCompleted"), QVariant(true));
+
+ groupProperty = object->property("groupProperty").value<QObject *>();
+ QCOMPARE(groupProperty, outerObjsAfterFirstExecute.first());
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ // re-execution does nothing (to avoid overriding the property)
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "groupProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 2); // MyDeferredListProperty.qml + deferredListProperty.qml
+ QCOMPARE(qmlData->deferredData.first()->bindings.count(), 2); // "innerlist1", "innerlist2"
+ QCOMPARE(qmlData->deferredData.last()->bindings.count(), 2); // "outerlist1", "outerlist2"
+
+ QObjectList innerObjsAfterSecondExecute = object->findChildren<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml
+ QVERIFY(innerObjsAfterSecondExecute.isEmpty());
+
+ QObjectList outerObjsAfterSecondExecute = object->findChildren<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml
+ QCOMPARE(outerObjsAfterFirstExecute, outerObjsAfterSecondExecute);
+
+ groupProperty = object->property("groupProperty").value<QObject *>();
+ QCOMPARE(groupProperty, outerObjsAfterFirstExecute.first());
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 0);
+
+ // execution of a list property should execute all outer list bindings
+ testExecuteDeferredOnce(QQmlProperty(object.data(), "listProperty"));
+
+ QCOMPARE(qmlData->deferredData.count(), 0);
+
+ listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>();
+ QCOMPARE(listProperty.count(&listProperty), 2);
+
+ QCOMPARE(listProperty.at(&listProperty, 0)->objectName(), QStringLiteral("outerlist1")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 0)->property("wasCompleted"), QVariant(true));
+ QCOMPARE(listProperty.at(&listProperty, 1)->objectName(), QStringLiteral("outerlist2")); // deferredListProperty.qml
+ QCOMPARE(listProperty.at(&listProperty, 1)->property("wasCompleted"), QVariant(true));
+}
+
void tst_qqmllanguage::noChildEvents()
{
QQmlComponent component(&engine);
component.setData("import QtQml 2.0; import Test 1.0; MyQmlObject { property QtObject child: QtObject {} }", QUrl());
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
+ QVERIFY(object != nullptr);
QCOMPARE(object->childAddedEventCount(), 0);
}
@@ -4294,15 +4702,15 @@ void tst_qqmllanguage::deleteSingletons()
QQmlEngine tmpEngine;
QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
- QVERIFY(o != 0);
- QObject *s1 = NULL;
- getSingletonInstance(o, "singletonInstance", &s1);
- QVERIFY(s1 != 0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != nullptr);
+ QObject *s1 = nullptr;
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
+ QVERIFY(s1 != nullptr);
singleton = s1;
- QVERIFY(singleton.data() != 0);
+ QVERIFY(singleton.data() != nullptr);
}
- QVERIFY(singleton.data() == 0);
+ QVERIFY(singleton.data() == nullptr);
}
void tst_qqmllanguage::arrayBuffer_data()
@@ -4321,8 +4729,8 @@ void tst_qqmllanguage::arrayBuffer()
QFETCH(QString, file);
QQmlComponent component(&engine, testFile(file));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("ok").toBool(), true);
}
@@ -4541,9 +4949,9 @@ void tst_qqmllanguage::instanceof()
VERIFY_ERRORS(0);
QScopedPointer<QObject> o(component.create());
- QVERIFY(o != 0);
+ QVERIFY(o != nullptr);
- QQmlExpression expr(engine.contextForObject(o.data()), 0, QString::fromLatin1(QTest::currentDataTag()));
+ QQmlExpression expr(engine.contextForObject(o.data()), nullptr, QString::fromLatin1(QTest::currentDataTag()));
QVariant ret = expr.evaluate();
if (expectedValue.type() == QVariant::Bool) {
@@ -4575,6 +4983,92 @@ void tst_qqmllanguage::concurrentLoadQmlDir()
engine.setImportPathList(defaultImportPathList);
}
+// Test that deleting an object and then accessing it doesn't crash.
+// QTBUG-44153
+class ObjectCreator : public QObject
+{
+ Q_OBJECT
+public slots:
+ QObject *create() { return (new ObjectCreator); }
+ void del() { delete this; }
+};
+
+void tst_qqmllanguage::accessDeletedObject()
+{
+ QQmlEngine engine;
+
+ engine.rootContext()->setContextProperty("objectCreator", new ObjectCreator);
+ QQmlComponent component(&engine, testFileUrl("accessDeletedObject.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+}
+
+void tst_qqmllanguage::lowercaseTypeNames()
+{
+ QCOMPARE(qmlRegisterType<QObject>("Test", 1, 0, "lowerCaseTypeName"), -1);
+ QCOMPARE(qmlRegisterSingletonType<QObject>("Test", 1, 0, "lowerCaseTypeName", nullptr), -1);
+}
+
+void tst_qqmllanguage::thisInQmlScope()
+{
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("thisInQmlScope.qml"));
+ QTRY_VERIFY(component.isReady());
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("x"), QVariant(42));
+ QCOMPARE(o->property("y"), QVariant(42));
+}
+
+void tst_qqmllanguage::valueTypeGroupPropertiesInBehavior()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("groupPropertyInPropertyValueSource.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ QObject *animation = qmlContext(o.data())->contextProperty("animation").value<QObject*>();
+ QVERIFY(animation);
+
+ QCOMPARE(animation->property("easing").value<QEasingCurve>().type(), QEasingCurve::InOutQuad);
+}
+
+void tst_qqmllanguage::retrieveQmlTypeId()
+{
+ // Register in reverse order to provoke wrong minor version matching.
+ int id2 = qmlRegisterType<QObject>("Test", 2, 3, "SomeTestType");
+ int id1 = qmlRegisterType<QObject>("Test", 2, 1, "SomeTestType");
+ QCOMPARE(qmlTypeId("Test", 2, 1, "SomeTestType"), id1);
+ QCOMPARE(qmlTypeId("Test", 2, 2, "SomeTestType"), id1);
+ QCOMPARE(qmlTypeId("Test", 2, 3, "SomeTestType"), id2);
+
+ // Error cases
+ QCOMPARE(qmlTypeId("Test", 2, 0, "SomeTestType"), -1);
+ QCOMPARE(qmlTypeId("Test", 2, 3, "DoesNotExist"), -1);
+ QCOMPARE(qmlTypeId("DoesNotExist", 2, 3, "SomeTestType"), -1);
+
+ // Must also work for other types (defined in testtpes.cpp)
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyExtendedUncreateableBaseClass") >= 0);
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyUncreateableBaseClass") >= 0);
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyTypeObjectSingleton") >= 0);
+}
+
+void tst_qqmllanguage::polymorphicFunctionLookup()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("polymorphicFunctionLookup.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+
+ QVERIFY(o->property("ok").toBool());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
index 513bea2e16..b49832499e 100644
--- a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
+++ b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp
@@ -45,13 +45,13 @@ struct Range
template <typename T> struct Array
{
- Array() : array(0), count(0) {}
+ Array() : array(nullptr) {}
template<int N> Array(const T (&array)[N]) : array(array), count(N) {}
T operator [](int index) const { return array[index]; }
const T *array;
- int count;
+ int count = 0;
};
typedef Array<int> IndexArray;
@@ -181,7 +181,7 @@ void tst_qqmllistcompositor::find_data()
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag))
- << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag)))
+ << Range(nullptr, 0, 1, int(VisibleFlag| C::CacheFlag)))
<< C::Cache << 2
<< Selection << 0
<< 0 << 0 << 0 << 0
@@ -238,7 +238,7 @@ void tst_qqmllistcompositor::findInsertPosition_data()
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag))
- << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag)))
+ << Range(nullptr, 0, 1, int(VisibleFlag| C::CacheFlag)))
<< Selection << 0
<< 0 << 0 << 0 << 0
<< uint(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) << 0;
@@ -246,7 +246,7 @@ void tst_qqmllistcompositor::findInsertPosition_data()
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag))
- << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag)))
+ << Range(nullptr, 0, 1, int(VisibleFlag| C::CacheFlag)))
<< Selection << 1
<< 1 << 1 << 1 << 3
<< uint(0) << 0;
@@ -390,17 +390,17 @@ void tst_qqmllistcompositor::clearFlags_data()
int listA; void *a = &listA;
{ static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int visibleIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *visibleLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *visibleLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int selectionIndexes[] = {0,1,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
QTest::newRow("Default, 2, 2, Selection")
<< (RangeList()
<< Range(a, 0, 12, int(C::AppendFlag | C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
- << Range(0, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
+ << Range(nullptr, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
<< C::Default << 2 << 2 << int(SelectionFlag)
<< (RemoveList()
<< Remove(2, 2, 2, 2, 2, SelectionFlag | C::CacheFlag))
@@ -409,19 +409,19 @@ void tst_qqmllistcompositor::clearFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray(selectionIndexes) << ListArray(selectionLists);
} { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int visibleIndexes[] = {0,2,3,5,6,7,8,9,10,11,0,0,0,0};
- static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int selectionIndexes[] = {0,1,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
QTest::newRow("Selection, 1, 2, Visible")
<< (RangeList()
<< Range(a, 0, 2, int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 2, 2, int(C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 4, 8, int(C::AppendFlag | C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
- << Range(0, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
+ << Range(nullptr, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
<< Selection << 1 << 2 << int(VisibleFlag)
<< (RemoveList()
<< Remove(1, 1, 1, 1, 1, VisibleFlag | C::CacheFlag)
@@ -431,13 +431,13 @@ void tst_qqmllistcompositor::clearFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray(selectionIndexes) << ListArray(selectionLists);
} { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0,0};
- static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0,0};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0};
- static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
static const int visibleIndexes[] = {0,2,3,5,6,7,8,9,10,11,0,0,0};
- static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
static const int selectionIndexes[] = {0,1,4,5,6,7,8,9,10,11,0,0,0};
- static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
QTest::newRow("Default, 13, 1, Prepend | Selection | Visible | Default")
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
@@ -445,7 +445,7 @@ void tst_qqmllistcompositor::clearFlags_data()
<< Range(a, 2, 2, int(C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 4, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 5, 7, int(C::AppendFlag | C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
- << Range(0, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
+ << Range(nullptr, 0, 4, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
<< C::Default << 13 << 1 << int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag)
<< (RemoveList()
<< Remove(11, 11, 13, 13, 1, SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
@@ -454,13 +454,13 @@ void tst_qqmllistcompositor::clearFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray(selectionIndexes) << ListArray(selectionLists);
} { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,0};
- static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a,0};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11,0,0,0};
- static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
static const int visibleIndexes[] = {0,2,3,5,6,7,8,9,10,11,0,0,0};
- static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
static const int selectionIndexes[] = {0,1,4,5,6,7,8,9,10,11,0,0,0};
- static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,0,0,0};
+ static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a, a,nullptr,nullptr,nullptr};
QTest::newRow("Cache, 11, 4, Cache")
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
@@ -468,8 +468,8 @@ void tst_qqmllistcompositor::clearFlags_data()
<< Range(a, 2, 2, int(C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 4, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 5, 7, int(C::AppendFlag | C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
- << Range(0, 0, 1, int(C::CacheFlag))
- << Range(0, 0, 3, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
+ << Range(nullptr, 0, 1, int(C::CacheFlag))
+ << Range(nullptr, 0, 3, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
<< C::Cache << 11 << 4 << int(C::CacheFlag)
<< (RemoveList())
<< IndexArray(cacheIndexes) << ListArray(cacheLists)
@@ -477,13 +477,13 @@ void tst_qqmllistcompositor::clearFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray(selectionIndexes) << ListArray(selectionLists);
} { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,0};
- static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a,0};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,0};
- static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a,0};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a,nullptr};
static const int visibleIndexes[] = {0,2,3,5,6,7,8,9,10,0};
- static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a,0};
+ static const void *visibleLists[] = {a,a,a,a,a,a,a,a, a,nullptr};
static const int selectionIndexes[] = {0,1,4,5,6,7,8,9,10,0};
- static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a,0};
+ static const void *selectionLists[] = {a,a,a,a,a,a,a,a, a,nullptr};
QTest::newRow("Default, 11, 3, Default | Visible | Selection")
<< (RangeList()
<< Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
@@ -492,8 +492,8 @@ void tst_qqmllistcompositor::clearFlags_data()
<< Range(a, 4, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 5, 6, int(C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag))
<< Range(a, 11, 1, int(C::AppendFlag | C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag))
- << Range(0, 0, 2, int(SelectionFlag | VisibleFlag | C::DefaultFlag))
- << Range(0, 0, 1, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
+ << Range(nullptr, 0, 2, int(SelectionFlag | VisibleFlag | C::DefaultFlag))
+ << Range(nullptr, 0, 1, int(SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)))
<< C::Default << 11 << 3 << int(C::DefaultFlag | VisibleFlag| SelectionFlag)
<< (RemoveList()
<< Remove(9, 9, 11, 11, 1, SelectionFlag | VisibleFlag | C::DefaultFlag)
@@ -584,13 +584,13 @@ void tst_qqmllistcompositor::setFlags_data()
int listA; void *a = &listA;
{ static const int cacheIndexes[] = {0,0,0,0};
- static const void *cacheLists[] = {0,0,0,0};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a};
QTest::newRow("Default, 2, 2, Default")
<< (RangeList()
<< Range(a, 0, 12, C::DefaultFlag)
- << Range(0, 0, 4, C::CacheFlag))
+ << Range(nullptr, 0, 4, C::CacheFlag))
<< C::Default << 2 << 2 << int(C::DefaultFlag)
<< (InsertList())
<< IndexArray(cacheIndexes) << ListArray(cacheLists)
@@ -598,7 +598,7 @@ void tst_qqmllistcompositor::setFlags_data()
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {0,0,0,0};
- static const void *cacheLists[] = {0,0,0,0};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a};
static const int visibleIndexes[] = {2,3};
@@ -606,7 +606,7 @@ void tst_qqmllistcompositor::setFlags_data()
QTest::newRow("Default, 2, 2, Visible")
<< (RangeList()
<< Range(a, 0, 12, C::DefaultFlag)
- << Range(0, 0, 4, C::CacheFlag))
+ << Range(nullptr, 0, 4, C::CacheFlag))
<< C::Default << 2 << 2 << int(VisibleFlag)
<< (InsertList()
<< Insert(0, 0, 2, 0, 2, VisibleFlag))
@@ -615,7 +615,7 @@ void tst_qqmllistcompositor::setFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {3,6,0,0,0,0};
- static const void *cacheLists[] = {a,a,0,0,0,0};
+ static const void *cacheLists[] = {a,a,nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a};
static const int visibleIndexes[] = {2,3,6,7};
@@ -629,7 +629,7 @@ void tst_qqmllistcompositor::setFlags_data()
<< Range(a, 4, 2, C::DefaultFlag)
<< Range(a, 6, 2, VisibleFlag | C::DefaultFlag)
<< Range(a, 8, 4, C::DefaultFlag)
- << Range(0, 0, 4, C::CacheFlag))
+ << Range(nullptr, 0, 4, C::CacheFlag))
<< Visible << 1 << 2 << int(SelectionFlag | C::CacheFlag)
<< (InsertList()
<< Insert(0, 1, 3, 0, 1, SelectionFlag | C::CacheFlag)
@@ -639,11 +639,11 @@ void tst_qqmllistcompositor::setFlags_data()
<< IndexArray(visibleIndexes) << ListArray(visibleLists)
<< IndexArray(selectionIndexes) << ListArray(selectionLists);
} { static const int cacheIndexes[] = {3,6,0,0,0,0};
- static const void *cacheLists[] = {a,a,0,0,0,0};
+ static const void *cacheLists[] = {a,a,nullptr,nullptr,nullptr,nullptr};
static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a};
static const int visibleIndexes[] = {2,3,6,7,0};
- static const void *visibleLists[] = {a,a,a,a,0};
+ static const void *visibleLists[] = {a,a,a,a,nullptr};
static const int selectionIndexes[] = {3,6};
static const void *selectionLists[] = {a,a};
QTest::newRow("Cache, 3, 1, Visible")
@@ -655,7 +655,7 @@ void tst_qqmllistcompositor::setFlags_data()
<< Range(a, 6, 1, SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)
<< Range(a, 7, 1, VisibleFlag | C::DefaultFlag)
<< Range(a, 8, 4, C::DefaultFlag)
- << Range(0, 0, 4, C::CacheFlag))
+ << Range(nullptr, 0, 4, C::CacheFlag))
<< C::Cache << 3 << 1 << int(VisibleFlag)
<< (InsertList()
<< Insert(2, 4, 12, 3, 1, VisibleFlag | C::CacheFlag))
@@ -770,14 +770,14 @@ void tst_qqmllistcompositor::move_data()
int listC; void *c = &listC;
{ static const int cacheIndexes[] = {0,0,0,0,2,3};
- static const void *cacheLists[] = {0,0,0,0,c,c};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr,c,c};
static const int defaultIndexes[] = {0,0,1,2,3,4,5,0,1,2,3,4,5,1,2,3,0,1,2,3,4,5};
- static const void *defaultLists[] = {0,a,a,a,a,a,a,b,b,b,b,b,b,0,0,0,c,c,c,c,c,c};
+ static const void *defaultLists[] = {nullptr,a,a,a,a,a,a,b,b,b,b,b,b,nullptr,nullptr,nullptr,c,c,c,c,c,c};
QTest::newRow("15, 0, 1")
<< (RangeList()
<< Range(a, 0, 6, C::DefaultFlag)
<< Range(b, 0, 6, C::AppendFlag | C::PrependFlag | C::DefaultFlag)
- << Range(0, 0, 4, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 4, C::DefaultFlag | C::CacheFlag)
<< Range(c, 0, 2, C::PrependFlag | C::DefaultFlag)
<< Range(c, 2, 2, C::PrependFlag | C::DefaultFlag | C::CacheFlag)
<< Range(c, 4, 2, C::AppendFlag | C::PrependFlag | C::DefaultFlag))
@@ -791,15 +791,15 @@ void tst_qqmllistcompositor::move_data()
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {0,0,0,0,2,3};
- static const void *cacheLists[] = {0,0,0,0,c,c};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr,c,c};
static const int defaultIndexes[] = {0,1,0,1,2,3,4,5,0,1,2,3,4,5,2,3,0,1,2,3,4,5};
- static const void *defaultLists[] = {0,0,a,a,a,a,a,a,b,b,b,b,b,b,0,0,c,c,c,c,c,c};
+ static const void *defaultLists[] = {nullptr,nullptr,a,a,a,a,a,a,b,b,b,b,b,b,nullptr,nullptr,c,c,c,c,c,c};
QTest::newRow("15, 1, 1")
<< (RangeList()
- << Range(0, 0, 1, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 1, C::DefaultFlag | C::CacheFlag)
<< Range(a, 0, 6, C::DefaultFlag)
<< Range(b, 0, 6, C::AppendFlag | C::PrependFlag | C::DefaultFlag)
- << Range(0, 0, 3, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 3, C::DefaultFlag | C::CacheFlag)
<< Range(c, 0, 2, C::PrependFlag | C::DefaultFlag)
<< Range(c, 2, 2, C::PrependFlag | C::DefaultFlag | C::CacheFlag)
<< Range(c, 4, 2, C::AppendFlag | C::PrependFlag | C::DefaultFlag))
@@ -813,15 +813,15 @@ void tst_qqmllistcompositor::move_data()
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {0,0,0,0,2,3};
- static const void *cacheLists[] = {0,0,0,0,c,c};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr,c,c};
static const int defaultIndexes[] = {0,1,2,0,1,3,4,5,0,1,2,3,4,5,2,3,0,1,2,3,4,5};
- static const void *defaultLists[] = {a,a,a,0,0,a,a,a,b,b,b,b,b,b,0,0,c,c,c,c,c,c};
+ static const void *defaultLists[] = {a,a,a,nullptr,nullptr,a,a,a,b,b,b,b,b,b,nullptr,nullptr,c,c,c,c,c,c};
QTest::newRow("0, 3, 2")
<< (RangeList()
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(a, 0, 6, C::DefaultFlag)
<< Range(b, 0, 6, C::AppendFlag | C::PrependFlag | C::DefaultFlag)
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(c, 0, 2, C::PrependFlag | C::DefaultFlag)
<< Range(c, 2, 2, C::PrependFlag | C::DefaultFlag | C::CacheFlag)
<< Range(c, 4, 2, C::AppendFlag | C::PrependFlag | C::DefaultFlag))
@@ -835,16 +835,16 @@ void tst_qqmllistcompositor::move_data()
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {0,0,0,0,2,3};
- static const void *cacheLists[] = {0,0,0,0,c,c};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr,c,c};
static const int defaultIndexes[] = {0,5,0,1,2,3,4,5,0,1,0,1,2,2,3,3,4,1,2,3,4,5};
- static const void *defaultLists[] = {a,a,b,b,b,b,b,b,0,0,c,a,a,0,0,a,a,c,c,c,c,c};
+ static const void *defaultLists[] = {a,a,b,b,b,b,b,b,nullptr,nullptr,c,a,a,nullptr,nullptr,a,a,c,c,c,c,c};
QTest::newRow("7, 1, 10")
<< (RangeList()
<< Range(a, 0, 3, C::DefaultFlag)
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(a, 3, 3, C::DefaultFlag)
<< Range(b, 0, 6, C::AppendFlag | C::PrependFlag | C::DefaultFlag)
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(c, 0, 2, C::PrependFlag | C::DefaultFlag)
<< Range(c, 2, 2, C::PrependFlag | C::DefaultFlag | C::CacheFlag)
<< Range(c, 4, 2, C::AppendFlag | C::PrependFlag | C::DefaultFlag))
@@ -864,18 +864,18 @@ void tst_qqmllistcompositor::move_data()
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
} { static const int cacheIndexes[] = {0,0,0,0,3,2};
- static const void *cacheLists[] = {0,0,0,0,c,c};
+ static const void *cacheLists[] = {nullptr,nullptr,nullptr,nullptr,c,c};
static const int defaultIndexes[] = {0,5,0,1,2,3,4,5,0,1,0,1,2,2,3,3,4,3,4,5,1,2};
- static const void *defaultLists[] = {a,a,b,b,b,b,b,b,0,0,c,a,a,0,0,a,a,c,c,c,c,c};
+ static const void *defaultLists[] = {a,a,b,b,b,b,b,b,nullptr,nullptr,c,a,a,nullptr,nullptr,a,a,c,c,c,c,c};
QTest::newRow("17, 20, 2")
<< (RangeList()
<< Range(a, 0, 1, C::DefaultFlag)
<< Range(a, 5, 1, C::DefaultFlag)
<< Range(b, 0, 6, C::DefaultFlag)
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(c, 0, 1, C::DefaultFlag)
<< Range(a, 1, 2, C::DefaultFlag)
- << Range(0, 0, 2, C::DefaultFlag | C::CacheFlag)
+ << Range(nullptr, 0, 2, C::DefaultFlag | C::CacheFlag)
<< Range(a, 3, 2, C::DefaultFlag)
<< Range(b, 0, 6, C::AppendFlag | C::PrependFlag)
<< Range(c, 0, 1, C::PrependFlag)
@@ -1072,7 +1072,7 @@ void tst_qqmllistcompositor::clear()
compositor.append(a, 0, 8, C::AppendFlag | C::PrependFlag | VisibleFlag | C::DefaultFlag);
compositor.append(b, 4, 5, VisibleFlag | C::DefaultFlag);
- compositor.append(0, 0, 3, VisibleFlag | C::DefaultFlag | C::CacheFlag);
+ compositor.append(nullptr, 0, 3, VisibleFlag | C::DefaultFlag | C::CacheFlag);
QCOMPARE(compositor.count(C::Default), 16);
QCOMPARE(compositor.count(Visible), 16);
diff --git a/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml b/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml
new file mode 100644
index 0000000000..7d3650c3b9
--- /dev/null
+++ b/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ ListModel {
+ id: listModel
+ objectName: "listModel"
+ dynamicRoles: true
+
+ // have to add elements dynamically when dynamicRoles = true
+ function appendNewElement() {
+ listModel.append({"name": "test", "obj": null})
+ }
+
+ function setElementAgain() {
+ var element = listModel.get(0)
+ listModel.set(0, element)
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml b/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml
new file mode 100644
index 0000000000..0abf221f60
--- /dev/null
+++ b/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+import QtTest 1.0
+
+Item {
+
+ Item {
+ id : testItem
+ property string name : "testObject"
+ property var object : this
+ function testMethod() {
+ return -1;
+ }
+ }
+
+ ListModel {
+ id : listModel
+ dynamicRoles : true
+ }
+
+ function exec() {
+ listModel.append(testItem);
+ listModel.append({ item : testItem });
+ return true;
+ }
+}
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index e442dd1421..771f3e5c4e 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -49,7 +49,7 @@ Q_DECLARE_METATYPE(QList<QVariantHash>)
inline QVariant runexpr(QQmlEngine *engine, const QString &str)
{
- QQmlExpression expr(engine->rootContext(), 0, str);
+ QQmlExpression expr(engine->rootContext(), nullptr, str);
return expr.evaluate();
}
@@ -106,6 +106,7 @@ private slots:
void get_nested_data();
void crash_model_with_multiple_roles();
void crash_model_with_unknown_roles();
+ void crash_model_with_dynamic_roles();
void set_model_cache();
void property_changes();
void property_changes_data();
@@ -123,6 +124,10 @@ private slots:
void about_to_be_signals();
void modify_through_delegate();
void bindingsOnGetResult();
+ void stringifyModelEntry();
+ void qobjectTrackerForDynamicModelObjects();
+ void crash_append_empty_array();
+ void dynamic_roles_crash_QTBUG_38907();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -130,7 +135,7 @@ bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVarian
bool allOk = true;
QQmlListModel *model = qobject_cast<QQmlListModel *>(object.value<QObject *>());
- if (model == 0)
+ if (model == nullptr)
return false;
if (model->count() != testList.count())
@@ -253,7 +258,7 @@ void tst_qqmllistmodel::static_types()
QVERIFY(!component.isError());
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
if (error.isEmpty()) {
QVariant actual = obj->property("test");
@@ -324,7 +329,7 @@ void tst_qqmllistmodel::static_i18n()
QVERIFY(!component.isError());
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVariant actual = obj->property("test");
@@ -373,7 +378,7 @@ void tst_qqmllistmodel::dynamic_i18n()
QVERIFY(!component.isError());
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVariant actual = obj->property("test");
@@ -411,7 +416,7 @@ void tst_qqmllistmodel::static_nestedElements()
component.setData(componentStr.toUtf8(), QUrl::fromLocalFile(""));
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVariant count = obj->property("count");
QCOMPARE(count.type(), QVariant::Int);
@@ -447,6 +452,7 @@ void tst_qqmllistmodel::dynamic_data()
QTest::newRow("get2") << "{get(-1) === undefined}" << 1 << "" << dr;
QTest::newRow("get3") << "{append({'foo':123});get(0) != undefined}" << 1 << "" << dr;
QTest::newRow("get4") << "{append({'foo':123});get(0).foo}" << 123 << "" << dr;
+ QTest::newRow("get5") << "{append({'foo':123});get(0) == get(0)}" << 1 << "" << dr;
QTest::newRow("get-modify1") << "{append({'foo':123,'bar':456});get(0).foo = 333;get(0).foo}" << 333 << "" << dr;
QTest::newRow("get-modify2") << "{append({'z':1});append({'foo':123,'bar':456});get(1).bar = 999;get(1).bar}" << 999 << "" << dr;
@@ -610,7 +616,7 @@ void tst_qqmllistmodel::enumerate()
QQmlComponent component(&eng, testFileUrl("enumerate.qml"));
QVERIFY(!component.isError());
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QLatin1String expectedStrings[] = {
QLatin1String("val1=1Y"),
@@ -955,9 +961,9 @@ void tst_qqmllistmodel::crash_model_with_multiple_roles()
QQmlComponent component(&eng, testFileUrl("multipleroles.qml"));
QObject *rootItem = component.create();
QVERIFY(component.errorString().isEmpty());
- QVERIFY(rootItem != 0);
+ QVERIFY(rootItem != nullptr);
QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
- QVERIFY(model != 0);
+ QVERIFY(model != nullptr);
// used to cause a crash
model->setProperty(0, "black", true);
@@ -971,15 +977,106 @@ void tst_qqmllistmodel::crash_model_with_unknown_roles()
QQmlComponent component(&eng, testFileUrl("multipleroles.qml"));
QScopedPointer<QObject> rootItem(component.create());
QVERIFY(component.errorString().isEmpty());
- QVERIFY(rootItem != 0);
+ QVERIFY(rootItem != nullptr);
QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
- QVERIFY(model != 0);
+ QVERIFY(model != nullptr);
// used to cause a crash in debug builds
model->index(0, 0, QModelIndex()).data(Qt::DisplayRole);
model->index(0, 0, QModelIndex()).data(Qt::UserRole);
}
+//QTBUG-35639
+void tst_qqmllistmodel::crash_model_with_dynamic_roles()
+{
+ {
+ // setting a dynamic role to a QObject value, then triggering dtor
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+
+ // delete the root item, which will cause the model dtor to run
+ // previously, this would crash as it attempted to delete testObj.
+ delete rootItem;
+ }
+
+ {
+ // setting a dynamic role to a QObject value, then triggering
+ // DynamicRoleModelNode::updateValues() to trigger unsafe qobject_cast
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+
+ QMetaObject::invokeMethod(model, "setElementAgain");
+
+ delete rootItem;
+ }
+
+ {
+ // setting a dynamic role to a QObject value, then triggering
+ // DynamicRoleModelNodeMetaObject::propertyWrite()
+
+ /*
+ XXX TODO: I couldn't reproduce this one simply - I think it
+ requires a WorkerScript sync() call, and that's non-trivial.
+ I thought I could do it simply via:
+
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+ QObject *testObj2 = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj2));
+
+ But it turns out that that doesn't work (the setValue() call within
+ setProperty() doesn't seem to trigger the right codepath, for some
+ reason), and you can't trigger it manually via:
+
+ QObject *testObj2 = new QObject;
+ void *a[] = { testObj2, 0 };
+ QMetaObject::metacall(dynamicNodeModel, QMetaObject::WriteProperty, 0, a);
+
+ because the dynamicNodeModel for that index cannot be retrieved
+ using the public API.
+
+ But, anyway, I think the above two test cases are sufficient to
+ show that QObject* values should be guarded internally.
+ */
+ }
+}
+
//QTBUG-15190
void tst_qqmllistmodel::set_model_cache()
{
@@ -987,7 +1084,7 @@ void tst_qqmllistmodel::set_model_cache()
QQmlComponent component(&eng, testFileUrl("setmodelcachelist.qml"));
QObject *model = component.create();
QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString()));
- QVERIFY(model != 0);
+ QVERIFY(model != nullptr);
QVERIFY(model->property("ok").toBool());
delete model;
@@ -1185,10 +1282,10 @@ void tst_qqmllistmodel::signal_handlers()
QQmlComponent component(&eng, testFileUrl("signalhandlers.qml"));
QObject *model = component.create();
QQmlListModel *lm = qobject_cast<QQmlListModel *>(model);
- QVERIFY(lm != 0);
+ QVERIFY(lm != nullptr);
lm->setDynamicRoles(dynamicRoles);
QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString()));
- QVERIFY(model != 0);
+ QVERIFY(model != nullptr);
QVERIFY(model->property("ok").toBool());
delete model;
@@ -1272,7 +1369,7 @@ void tst_qqmllistmodel::empty_element_warning()
QVERIFY(!component.isError());
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
delete obj;
}
@@ -1482,6 +1579,94 @@ void tst_qqmllistmodel::bindingsOnGetResult()
QVERIFY(obj->property("success").toBool());
}
+void tst_qqmllistmodel::stringifyModelEntry()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\"\n"
+ " ListElement { name: \"Joe\"; age: 22 }\n"
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QQmlExpression expr(engine.rootContext(), model, "JSON.stringify(get(0));");
+ QVariant v = expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+ const QString expectedString = QStringLiteral("{\"age\":22,\"name\":\"Joe\"}");
+ QCOMPARE(v.toString(), expectedString);
+}
+
+void tst_qqmllistmodel::qobjectTrackerForDynamicModelObjects()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\"\n"
+ " ListElement { name: \"Joe\"; age: 22 }\n"
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QQmlExpression expr(engine.rootContext(), model, "get(0);");
+ QVariant v = expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+
+ QObject *obj = v.value<QObject*>();
+ QVERIFY(obj);
+
+ QQmlData *ddata = QQmlData::get(obj, /*create*/false);
+ QVERIFY(ddata);
+ QVERIFY(!ddata->jsWrapper.isNullOrUndefined());
+}
+
+void tst_qqmllistmodel::crash_append_empty_array()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\""
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QSignalSpy spy(model, &QQmlListModel::rowsAboutToBeInserted);
+ QQmlExpression expr(engine.rootContext(), model, "append(new Array())");
+ expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+ QCOMPARE(spy.count(), 0);
+}
+
+void tst_qqmllistmodel::dynamic_roles_crash_QTBUG_38907()
+{
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("qtbug38907.qml"));
+ QVERIFY(!component.isError());
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create()));
+ QVERIFY(item != 0);
+
+ QVariant retVal;
+
+ QMetaObject::invokeMethod(item.data(),
+ "exec",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, retVal));
+
+ QVERIFY(retVal.toBool());
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
index 9564d6a8b2..21b0508e4d 100644
--- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
+++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp
@@ -48,7 +48,7 @@ Q_DECLARE_METATYPE(QList<QVariantHash>)
inline QVariant runexpr(QQmlEngine *engine, const QString &str)
{
- QQmlExpression expr(engine->rootContext(), 0, str);
+ QQmlExpression expr(engine->rootContext(), nullptr, str);
return expr.evaluate();
}
@@ -111,7 +111,7 @@ bool tst_qqmllistmodelworkerscript::compareVariantList(const QVariantList &testL
bool allOk = true;
QQmlListModel *model = qobject_cast<QQmlListModel *>(object.value<QObject *>());
- if (model == 0)
+ if (model == nullptr)
return false;
if (model->count() != testList.count())
@@ -192,7 +192,7 @@ void tst_qqmllistmodelworkerscript::dynamic_data()
QTest::addColumn<QString>("warning");
QTest::addColumn<bool>("dynamicRoles");
- for (int i=0 ; i < 2 ; ++i) {
+ for (int i = 0; i < 2; ++i) {
bool dr = (i != 0);
// Simple flat model
@@ -204,6 +204,7 @@ void tst_qqmllistmodelworkerscript::dynamic_data()
QTest::newRow("get4") << "{append({'foo':123});get(0).foo}" << 123 << "" << dr;
QTest::newRow("get-modify1") << "{append({'foo':123,'bar':456});get(0).foo = 333;get(0).foo}" << 333 << "" << dr;
QTest::newRow("get-modify2") << "{append({'z':1});append({'foo':123,'bar':456});get(1).bar = 999;get(1).bar}" << 999 << "" << dr;
+ QTest::newRow("get-set") << "{append({'foo':123});get(0).foo;setProperty(0, 'foo', 999);get(0).foo}" << 999 << "" << dr;
QTest::newRow("append1") << "{append({'foo':123});count}" << 1 << "" << dr;
QTest::newRow("append2") << "{append({'foo':123,'bar':456});count}" << 1 << "" << dr;
@@ -349,7 +350,7 @@ void tst_qqmllistmodelworkerscript::dynamic_worker()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("model.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QSignalSpy spyCount(&model, SIGNAL(countChanged()));
@@ -400,7 +401,7 @@ void tst_qqmllistmodelworkerscript::dynamic_worker_sync()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("model.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
if (script[0] == QLatin1Char('{') && script[script.length()-1] == QLatin1Char('}'))
script = script.mid(1, script.length() - 2);
@@ -434,7 +435,7 @@ void tst_qqmllistmodelworkerscript::get_data()
QTest::addColumn<QVariant>("roleValue");
QTest::addColumn<bool>("dynamicRoles");
- for (int i=0 ; i < 2 ; ++i) {
+ for (int i =0; i < 2; ++i) {
bool dr = (i != 0);
QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500) << dr;
@@ -463,7 +464,7 @@ void tst_qqmllistmodelworkerscript::get_worker()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("model.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
// Add some values like get() test
RUNEVAL(item, "model.append({roleA: 100})");
@@ -515,7 +516,7 @@ void tst_qqmllistmodelworkerscript::property_changes_data()
QTest::addColumn<QString>("testExpression");
QTest::addColumn<bool>("dynamicRoles");
- for (int i=0 ; i < 2 ; ++i) {
+ for (int i=1 ; i < 2 ; ++i) {
bool dr = (i != 0);
QTest::newRow("set: plain") << "append({'a':123, 'b':456, 'c':789});" << "set(0,{'b':123});"
@@ -574,7 +575,7 @@ void tst_qqmllistmodelworkerscript::property_changes_data()
<< "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 2 && get(0).b.get(2).a == 3" << dr;
QTest::newRow("nested-set: list, no changes, empty") << "append({'a':123, 'b':[], 'c':789});" << "set(0,{'b':[]});"
- << "b" << 0 << true << "get(0).b.count == 0" << dr;
+ << "b" << 0 << false << "get(0).b.count == 0" << dr;
}
}
@@ -593,7 +594,7 @@ void tst_qqmllistmodelworkerscript::property_changes_worker()
QQmlComponent component(&engine, testFileUrl("model.qml"));
QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8());
QQuickItem *item = createWorkerTest(&engine, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QQmlExpression expr(engine.rootContext(), &model, script_setup);
expr.evaluate();
@@ -640,7 +641,7 @@ void tst_qqmllistmodelworkerscript::worker_sync()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("workersync.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QCOMPARE(model.count(), 0);
@@ -705,7 +706,7 @@ void tst_qqmllistmodelworkerscript::worker_remove_element()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("workerremoveelement.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QSignalSpy spyModelRemoved(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
@@ -738,7 +739,7 @@ void tst_qqmllistmodelworkerscript::worker_remove_element()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("workerremoveelement.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QVERIFY(QMetaObject::invokeMethod(item, "addItem"));
@@ -768,7 +769,7 @@ void tst_qqmllistmodelworkerscript::worker_remove_list()
QQmlEngine eng;
QQmlComponent component(&eng, testFileUrl("workerremovelist.qml"));
QQuickItem *item = createWorkerTest(&eng, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QSignalSpy spyModelRemoved(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)));
@@ -815,7 +816,7 @@ void tst_qqmllistmodelworkerscript::dynamic_role()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("model.qml"));
QQuickItem *item = createWorkerTest(&engine, &component, &model);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QQmlExpression preExp(engine.rootContext(), &model, preamble);
QCOMPARE(preExp.evaluate().toInt(), 0);
diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
index 5c16a48378..199f7bc7e4 100644
--- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
+++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp
@@ -115,7 +115,7 @@ void tst_qqmllistreference::qmllistreference_invalid()
QVERIFY(!r.canAt());
QVERIFY(!r.canClear());
QVERIFY(!r.canCount());
- QVERIFY(!r.append(0));
+ QVERIFY(!r.append(nullptr));
QVERIFY(!r.at(10));
QVERIFY(!r.clear());
QCOMPARE(r.count(), 0);
@@ -132,7 +132,7 @@ void tst_qqmllistreference::qmllistreference_invalid()
QVERIFY(!r.canAt());
QVERIFY(!r.canClear());
QVERIFY(!r.canCount());
- QVERIFY(!r.append(0));
+ QVERIFY(!r.append(nullptr));
QVERIFY(!r.at(10));
QVERIFY(!r.clear());
QCOMPARE(r.count(), 0);
@@ -149,7 +149,7 @@ void tst_qqmllistreference::qmllistreference_invalid()
QVERIFY(!r.canAt());
QVERIFY(!r.canClear());
QVERIFY(!r.canCount());
- QVERIFY(!r.append(0));
+ QVERIFY(!r.append(nullptr));
QVERIFY(!r.at(10));
QVERIFY(!r.clear());
QCOMPARE(r.count(), 0);
@@ -247,7 +247,7 @@ void tst_qqmllistreference::canAppend()
{
TestType tt;
- tt.property.append = 0;
+ tt.property.append = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.canAppend());
}
@@ -276,7 +276,7 @@ void tst_qqmllistreference::canAt()
{
TestType tt;
- tt.property.at = 0;
+ tt.property.at = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.canAt());
}
@@ -305,7 +305,7 @@ void tst_qqmllistreference::canClear()
{
TestType tt;
- tt.property.clear = 0;
+ tt.property.clear = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.canClear());
}
@@ -334,7 +334,7 @@ void tst_qqmllistreference::canCount()
{
TestType tt;
- tt.property.count = 0;
+ tt.property.count = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.canCount());
}
@@ -363,7 +363,7 @@ void tst_qqmllistreference::isReadable()
{
TestType tt;
- tt.property.count = 0;
+ tt.property.count = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.isReadable());
}
@@ -392,7 +392,7 @@ void tst_qqmllistreference::isManipulable()
{
TestType tt;
- tt.property.count = 0;
+ tt.property.count = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.isManipulable());
}
@@ -421,17 +421,17 @@ void tst_qqmllistreference::append()
QVERIFY(!ref.append(&object));
QCOMPARE(tt->data.count(), 1);
QCOMPARE(tt->data.at(0), tt);
- QVERIFY(ref.append(0));
+ QVERIFY(ref.append(nullptr));
QCOMPARE(tt->data.count(), 2);
QCOMPARE(tt->data.at(0), tt);
QVERIFY(!tt->data.at(1));
delete tt;
- QVERIFY(!ref.append(0));
+ QVERIFY(!ref.append(nullptr));
}
{
TestType tt;
- tt.property.append = 0;
+ tt.property.append = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.append(&tt));
}
@@ -466,7 +466,7 @@ void tst_qqmllistreference::at()
{
TestType tt;
tt.data.append(&tt);
- tt.property.at = 0;
+ tt.property.at = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.at(0));
}
@@ -499,7 +499,7 @@ void tst_qqmllistreference::clear()
{
TestType tt;
- tt.property.clear = 0;
+ tt.property.clear = nullptr;
QQmlListReference ref(&tt, "data");
QVERIFY(!ref.clear());
}
@@ -534,7 +534,7 @@ void tst_qqmllistreference::count()
{
TestType tt;
tt.data.append(&tt);
- tt.property.count = 0;
+ tt.property.count = nullptr;
QQmlListReference ref(&tt, "data");
QCOMPARE(ref.count(), 0);
}
@@ -626,17 +626,17 @@ void tst_qqmllistreference::listProperty()
QQmlComponent component(&engine, testFileUrl("propertyList.qml"));
QScopedPointer<QObject> object( component.create() );
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE( object->property("state").toString(), QStringLiteral("MyState2") );
QQmlListReference list( object.data(), "states");
QCOMPARE( list.count(), 2 );
QQuickState* state1 = dynamic_cast<QQuickState*>( list.at( 0 ) );
- QVERIFY(state1 != 0);
+ QVERIFY(state1 != nullptr);
QCOMPARE( state1->name(), QStringLiteral("MyState1") );
QQuickState* state2 = dynamic_cast<QQuickState*>( list.at( 1 ) );
- QVERIFY(state2 != 0);
+ QVERIFY(state2 != nullptr);
QCOMPARE( state2->name(), QStringLiteral("MyState2") );
}
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index d0ce83b997..eb6eb62648 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -152,7 +152,7 @@ void tst_qqmllocale::addPropertyData(const QString &l)
LOCALE_PROP(QString,exponential),
LOCALE_PROP(int,measurementSystem),
LOCALE_PROP(int,textDirection),
- { 0, QVariant() }
+ { nullptr, QVariant() }
};
int i = 0;
@@ -663,7 +663,7 @@ void tst_qqmllocale::addDateTimeFormatData(const QString &l)
"h:m:sap ddd MMMM d yy",
"'The date and time is: 'H:mm:ss:zzz dd/MM/yy",
"MMM d yyyy HH:mm t",
- 0
+ nullptr
};
QByteArray locale = l.toLatin1();
int i = 0;
@@ -751,7 +751,7 @@ void tst_qqmllocale::addDateFormatData(const QString &l)
"ddd MMMM d yy",
"'The date is: 'dd/MM/yy",
"MMM d yyyy",
- 0
+ nullptr
};
QByteArray locale = l.toLatin1();
int i = 0;
@@ -839,7 +839,7 @@ void tst_qqmllocale::addTimeFormatData(const QString &l)
"h:m:sap",
"'The time is: 'H:mm:ss:zzz",
"HH:mm t",
- 0
+ nullptr
};
QByteArray locale = l.toLatin1();
int i = 0;
@@ -1232,7 +1232,7 @@ class DateFormatter : public QObject
{
Q_OBJECT
public:
- DateFormatter() : QObject() {}
+ DateFormatter() {}
Q_INVOKABLE QString getLocalizedForm(const QString &isoTimestamp);
};
@@ -1268,8 +1268,8 @@ void tst_qqmllocale::timeZoneUpdated()
{
QByteArray original(qgetenv("TZ"));
- // Set the timezone to Brisbane time
- setTimeZone(QByteArray("AEST-10:00"));
+ // Set the timezone to Brisbane time, AEST-10:00
+ setTimeZone(QByteArray("Australia/Brisbane"));
DateFormatter formatter;
@@ -1281,8 +1281,8 @@ void tst_qqmllocale::timeZoneUpdated()
QVERIFY(obj);
QVERIFY(obj->property("success").toBool());
- // Change to Indian time
- setTimeZone(QByteArray("IST-05:30"));
+ // Change to Indian time, IST-05:30
+ setTimeZone(QByteArray("Asia/Kolkata"));
QMetaObject::invokeMethod(obj.data(), "check");
diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp
index 9467af6754..ea157a7d15 100644
--- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp
+++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp
@@ -186,10 +186,10 @@ void tst_QQmlMetaObject::property()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(testFile));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
const QMetaObject *mo = object->metaObject();
- QVERIFY(mo->superClass() != 0);
+ QVERIFY(mo->superClass() != nullptr);
QVERIFY(QByteArray(mo->className()).contains("_QML_"));
QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount());
QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1);
@@ -361,10 +361,10 @@ void tst_QQmlMetaObject::method()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(testFile));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
const QMetaObject *mo = object->metaObject();
- QVERIFY(mo->superClass() != 0);
+ QVERIFY(mo->superClass() != nullptr);
QVERIFY(QByteArray(mo->className()).contains("_QML_"));
QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount());
QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1);
diff --git a/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml
new file mode 100644
index 0000000000..df6d801cde
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import GroupedTest 1.0
+
+MyItem {
+ grouped.prop: 5
+}
diff --git a/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml
new file mode 100644
index 0000000000..b7ea017acf
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import GroupedTest 1.1
+
+MyItem {
+ grouped.prop: 5
+}
diff --git a/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml
new file mode 100644
index 0000000000..85b8f5ac8b
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomSingletonType.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.7
+import mytypes 1.0
+
+Item {
+ id: root
+ property string text: StaticProvider.singletonGetString()
+}
+
diff --git a/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml
new file mode 100644
index 0000000000..f6ee4e9b77
--- /dev/null
+++ b/tests/auto/qml/qqmlmetatype/data/testUnregisterCustomType.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.7
+import mytypes 1.0
+
+Item {
+ id: root
+ Controller { id: controller; objectName: "controller" }
+}
+
diff --git a/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro b/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro
index 0d8de91931..345bc59615 100644
--- a/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro
+++ b/tests/auto/qml/qqmlmetatype/qqmlmetatype.pro
@@ -6,4 +6,8 @@ macx:CONFIG -= app_bundle
TESTDATA = data/*
include (../../shared/util.pri)
+qmlfiles.files = data/CompositeType.qml
+qmlfiles.prefix = /tstqqmlmetatype
+RESOURCES += qmlfiles
+
QT += core-private gui-private qml-private testlib
diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
index 30e517c8f9..ac75eeab26 100644
--- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
+++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
@@ -35,7 +35,7 @@
#include <private/qqmlmetatype_p.h>
#include <private/qqmlpropertyvalueinterceptor_p.h>
-#include <private/qhashedstring_p.h>
+#include <private/qqmlengine_p.h>
#include "../../shared/util.h"
class tst_qqmlmetatype : public QQmlDataTest
@@ -60,6 +60,12 @@ private slots:
void isList();
void defaultObject();
+ void unregisterCustomType();
+ void unregisterCustomSingletonType();
+
+ void normalizeUrls();
+ void unregisterAttachedProperties();
+ void revisionedGroupedProperties();
};
class TestType : public QObject
@@ -148,14 +154,14 @@ void tst_qqmlmetatype::initTestCase()
void tst_qqmlmetatype::qmlParserStatusCast()
{
- QVERIFY(!QQmlMetaType::qmlType(QVariant::Int));
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>())->parserStatusCast(), -1);
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>())->parserStatusCast(), -1);
-
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()) != 0);
- int cast = QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>())->parserStatusCast();
+ QVERIFY(!QQmlMetaType::qmlType(QVariant::Int).isValid());
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).parserStatusCast(), -1);
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()).parserStatusCast(), -1);
+
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).isValid());
+ int cast = QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).parserStatusCast();
QVERIFY(cast != -1);
QVERIFY(cast != 0);
@@ -168,14 +174,14 @@ void tst_qqmlmetatype::qmlParserStatusCast()
void tst_qqmlmetatype::qmlPropertyValueSourceCast()
{
- QVERIFY(!QQmlMetaType::qmlType(QVariant::Int));
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>())->propertyValueSourceCast(), -1);
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>())->propertyValueSourceCast(), -1);
-
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()) != 0);
- int cast = QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>())->propertyValueSourceCast();
+ QVERIFY(!QQmlMetaType::qmlType(QVariant::Int).isValid());
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).propertyValueSourceCast(), -1);
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).propertyValueSourceCast(), -1);
+
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()).isValid());
+ int cast = QQmlMetaType::qmlType(qMetaTypeId<ValueSourceTestType *>()).propertyValueSourceCast();
QVERIFY(cast != -1);
QVERIFY(cast != 0);
@@ -188,14 +194,14 @@ void tst_qqmlmetatype::qmlPropertyValueSourceCast()
void tst_qqmlmetatype::qmlPropertyValueInterceptorCast()
{
- QVERIFY(!QQmlMetaType::qmlType(QVariant::Int));
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>())->propertyValueInterceptorCast(), -1);
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()) != 0);
- QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>())->propertyValueInterceptorCast(), -1);
-
- QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueInterceptorTestType *>()) != 0);
- int cast = QQmlMetaType::qmlType(qMetaTypeId<ValueInterceptorTestType *>())->propertyValueInterceptorCast();
+ QVERIFY(!QQmlMetaType::qmlType(QVariant::Int).isValid());
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<TestType *>()).propertyValueInterceptorCast(), -1);
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).isValid());
+ QCOMPARE(QQmlMetaType::qmlType(qMetaTypeId<ParserStatusTestType *>()).propertyValueInterceptorCast(), -1);
+
+ QVERIFY(QQmlMetaType::qmlType(qMetaTypeId<ValueInterceptorTestType *>()).isValid());
+ int cast = QQmlMetaType::qmlType(qMetaTypeId<ValueInterceptorTestType *>()).propertyValueInterceptorCast();
QVERIFY(cast != -1);
QVERIFY(cast != 0);
@@ -208,32 +214,28 @@ void tst_qqmlmetatype::qmlPropertyValueInterceptorCast()
void tst_qqmlmetatype::qmlType()
{
- QQmlType *type = QQmlMetaType::qmlType(QString("ParserStatusTestType"), QString("Test"), 1, 0);
- QVERIFY(type);
- QVERIFY(type->module() == QLatin1String("Test"));
- QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType"));
- QCOMPARE(type->qmlTypeName(), QLatin1String("Test/ParserStatusTestType"));
+ QQmlType type = QQmlMetaType::qmlType(QString("ParserStatusTestType"), QString("Test"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(type.module() == QLatin1String("Test"));
+ QVERIFY(type.elementName() == QLatin1String("ParserStatusTestType"));
+ QCOMPARE(type.qmlTypeName(), QLatin1String("Test/ParserStatusTestType"));
type = QQmlMetaType::qmlType("Test/ParserStatusTestType", 1, 0);
- QVERIFY(type);
- QVERIFY(type->module() == QLatin1String("Test"));
- QVERIFY(type->elementName() == QLatin1String("ParserStatusTestType"));
- QCOMPARE(type->qmlTypeName(), QLatin1String("Test/ParserStatusTestType"));
+ QVERIFY(type.isValid());
+ QVERIFY(type.module() == QLatin1String("Test"));
+ QVERIFY(type.elementName() == QLatin1String("ParserStatusTestType"));
+ QCOMPARE(type.qmlTypeName(), QLatin1String("Test/ParserStatusTestType"));
}
void tst_qqmlmetatype::invalidQmlTypeName()
{
- QStringList currFailures = QQmlMetaType::typeRegistrationFailures();
+ QTest::ignoreMessage(QtWarningMsg, "Invalid QML element name \"testtype\"; type names must begin with an uppercase letter");
+ QTest::ignoreMessage(QtWarningMsg, "Invalid QML element name \"Test$Type\"");
+ QTest::ignoreMessage(QtWarningMsg, "Invalid QML element name \"EndingInSlash/\"");
+
QCOMPARE(qmlRegisterType<TestType>("TestNamespace", 1, 0, "Test$Type"), -1); // should fail due to invalid QML type name.
QCOMPARE(qmlRegisterType<TestType>("Test", 1, 0, "EndingInSlash/"), -1);
- QStringList nowFailures = QQmlMetaType::typeRegistrationFailures();
-
- foreach (const QString &f, currFailures)
- nowFailures.removeOne(f);
-
- QCOMPARE(nowFailures.size(), 2);
- QCOMPARE(nowFailures.at(0), QStringLiteral("Invalid QML element name \"Test$Type\""));
- QCOMPARE(nowFailures.at(1), QStringLiteral("Invalid QML element name \"EndingInSlash/\""));
+ QCOMPARE(qmlRegisterType<TestType>("Test", 1, 0, "testtype"), -1);
}
void tst_qqmlmetatype::prettyTypeName()
@@ -269,7 +271,7 @@ void tst_qqmlmetatype::defaultObject()
TestType t;
ParserStatusTestType p;
- QVERIFY(QQmlMetaType::defaultProperty((QObject *)0).name() == 0);
+ QVERIFY(QQmlMetaType::defaultProperty((QObject *)nullptr).name() == nullptr);
QVERIFY(!QQmlMetaType::defaultProperty(&o).name());
QVERIFY(!QQmlMetaType::defaultProperty(&p).name());
QCOMPARE(QString(QQmlMetaType::defaultProperty(&t).name()), QString("foo"));
@@ -277,23 +279,23 @@ void tst_qqmlmetatype::defaultObject()
void tst_qqmlmetatype::registrationType()
{
- QQmlType *type = QQmlMetaType::qmlType(QString("TestType"), QString("Test"), 1, 0);
- QVERIFY(type);
- QVERIFY(!type->isInterface());
- QVERIFY(!type->isSingleton());
- QVERIFY(!type->isComposite());
+ QQmlType type = QQmlMetaType::qmlType(QString("TestType"), QString("Test"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
type = QQmlMetaType::qmlType(QString("TestTypeSingleton"), QString("Test"), 1, 0);
- QVERIFY(type);
- QVERIFY(!type->isInterface());
- QVERIFY(type->isSingleton());
- QVERIFY(!type->isComposite());
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
type = QQmlMetaType::qmlType(QString("TestTypeComposite"), QString("Test"), 1, 0);
- QVERIFY(type);
- QVERIFY(!type->isInterface());
- QVERIFY(!type->isSingleton());
- QVERIFY(type->isComposite());
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(type.isComposite());
}
void tst_qqmlmetatype::compositeType()
@@ -305,12 +307,12 @@ void tst_qqmlmetatype::compositeType()
QObject* obj = c.create();
QVERIFY(obj);
- QQmlType *type = QQmlMetaType::qmlType(QString("ImplicitType"), QString(""), 1, 0);
- QVERIFY(type);
- QVERIFY(type->module().isEmpty());
- QCOMPARE(type->elementName(), QLatin1String("ImplicitType"));
- QCOMPARE(type->qmlTypeName(), QLatin1String("ImplicitType"));
- QCOMPARE(type->sourceUrl(), testFileUrl("ImplicitType.qml"));
+ QQmlType type = QQmlMetaType::qmlType(QString("ImplicitType"), QString(""), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(type.module().isEmpty());
+ QCOMPARE(type.elementName(), QLatin1String("ImplicitType"));
+ QCOMPARE(type.qmlTypeName(), QLatin1String("ImplicitType"));
+ QCOMPARE(type.sourceUrl(), testFileUrl("ImplicitType.qml"));
}
void tst_qqmlmetatype::externalEnums()
@@ -330,6 +332,302 @@ void tst_qqmlmetatype::externalEnums()
}
+class Controller1 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString string MEMBER m_string)
+ Q_PROPERTY(Controller1Enum enumVal MEMBER m_enumVal)
+public:
+ enum Controller1Enum {
+ ENUM_VALUE_1 = 1,
+ ENUM_VALUE_2 = 2
+ };
+ Q_ENUMS(Controller1Enum)
+
+ Controller1(QObject *parent = nullptr) : QObject(parent), m_string("Controller #1"),
+ m_enumVal(ENUM_VALUE_1)
+ {}
+private:
+ QString m_string;
+ Controller1Enum m_enumVal;
+};
+
+class Controller2 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString string MEMBER m_string)
+ Q_PROPERTY(Controller2Enum enumVal MEMBER m_enumVal)
+public:
+ enum Controller2Enum {
+ ENUM_VALUE_1 = 111,
+ ENUM_VALUE_2 = 222
+ };
+ Q_ENUMS(Controller2Enum)
+
+ Controller2(QObject *parent = nullptr) : QObject(parent), m_string("Controller #2"),
+ m_enumVal(ENUM_VALUE_1)
+ {}
+private:
+ QString m_string;
+ Controller2Enum m_enumVal;
+};
+
+void tst_qqmlmetatype::unregisterCustomType()
+{
+ int controllerId = 0;
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller1>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller1 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #1"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 1);
+ }
+ QQmlMetaType::unregisterType(controllerId);
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller2>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller2 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #2"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 111);
+ }
+ QQmlMetaType::unregisterType(controllerId);
+ {
+ QQmlEngine engine;
+ QQmlType type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(!type.isValid());
+ controllerId = qmlRegisterType<Controller1>("mytypes", 1, 0, "Controller");
+ type = QQmlMetaType::qmlType(QString("Controller"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(!type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+ QObject *controller = obj->findChild<QObject *>("controller");
+ QVERIFY(qobject_cast<Controller1 *>(controller));
+ QVariant stringVal = controller->property("string");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("Controller #1"));
+ QVariant enumVal = controller->property("enumVal");
+ QCOMPARE(enumVal.type(), QVariant::Int);
+ QCOMPARE(enumVal.toInt(), 1);
+ }
+}
+
+class StaticProvider1 : public QObject
+{
+ Q_OBJECT
+public:
+ StaticProvider1(QObject *parent = nullptr) : QObject(parent) {}
+ Q_INVOKABLE QString singletonGetString() { return "StaticProvider #1"; }
+};
+
+static QObject* createStaticProvider1(QQmlEngine *, QJSEngine *)
+{
+ return new StaticProvider1;
+}
+
+class StaticProvider2 : public QObject
+{
+ Q_OBJECT
+public:
+ StaticProvider2(QObject *parent = nullptr) : QObject(parent) {}
+ Q_INVOKABLE QString singletonGetString() { return "StaticProvider #2"; }
+};
+
+static QObject* createStaticProvider2(QQmlEngine *, QJSEngine *)
+{
+ return new StaticProvider2;
+}
+
+void tst_qqmlmetatype::unregisterCustomSingletonType()
+{
+ int staticProviderId = 0;
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider1>("mytypes", 1, 0, "StaticProvider", createStaticProvider1);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #1"));
+ }
+ QQmlMetaType::unregisterType(staticProviderId);
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider2>("mytypes", 1, 0, "StaticProvider", createStaticProvider2);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #2"));
+ }
+ QQmlMetaType::unregisterType(staticProviderId);
+ {
+ QQmlEngine engine;
+ staticProviderId = qmlRegisterSingletonType<StaticProvider1>("mytypes", 1, 0, "StaticProvider", createStaticProvider1);
+ QQmlType type = QQmlMetaType::qmlType(QString("StaticProvider"), QString("mytypes"), 1, 0);
+ QVERIFY(type.isValid());
+ QVERIFY(!type.isInterface());
+ QVERIFY(type.isSingleton());
+ QVERIFY(!type.isComposite());
+ QQmlComponent c(&engine, testFileUrl("testUnregisterCustomSingletonType.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj.data());
+ QVariant stringVal = obj->property("text");
+ QCOMPARE(stringVal.type(), QVariant::String);
+ QCOMPARE(stringVal.toString(), QStringLiteral("StaticProvider #1"));
+ }
+}
+
+void tst_qqmlmetatype::normalizeUrls()
+{
+ const QUrl url("qrc:///tstqqmlmetatype/data/CompositeType.qml");
+ QVERIFY(!QQmlMetaType::qmlType(url).isValid());
+ const auto registrationId = qmlRegisterType(url, "Test", 1, 0, "ResourceCompositeType");
+ QVERIFY(QQmlMetaType::qmlType(url, /*includeNonFileImports=*/true).isValid());
+ QUrl normalizedURL("qrc:/tstqqmlmetatype/data/CompositeType.qml");
+ QVERIFY(QQmlMetaType::qmlType(normalizedURL, /*includeNonFileImports=*/true).isValid());
+ QQmlMetaType::unregisterType(registrationId);
+ QVERIFY(!QQmlMetaType::qmlType(url, /*includeNonFileImports=*/true).isValid());
+}
+
+void tst_qqmlmetatype::unregisterAttachedProperties()
+{
+ qmlClearTypeRegistrations();
+
+ const QUrl dummy("qrc:///doesnotexist.qml");
+ {
+ QQmlEngine e;
+ QQmlComponent c(&e);
+ c.setData("import QtQuick 2.2\n Item { }", dummy);
+
+ const QQmlType attachedType = QQmlMetaType::qmlType("QtQuick/KeyNavigation", 2, 2);
+ QCOMPARE(attachedType.attachedPropertiesId(QQmlEnginePrivate::get(&e)),
+ attachedType.index());
+
+ QVERIFY(c.create());
+ }
+
+ qmlClearTypeRegistrations();
+ {
+ QQmlEngine e;
+ QQmlComponent c(&e);
+
+ // The extra import shuffles the type IDs around, so that we
+ // get a different ID for the attached properties. If the attached
+ // properties aren't properly cleared, this will crash.
+ c.setData("import QtQml.StateMachine 1.0 \n"
+ "import QtQuick 2.2 \n"
+ "Item { KeyNavigation.up: null }", dummy);
+
+ const QQmlType attachedType = QQmlMetaType::qmlType("QtQuick/KeyNavigation", 2, 2);
+ QCOMPARE(attachedType.attachedPropertiesId(QQmlEnginePrivate::get(&e)),
+ attachedType.index());
+
+ QVERIFY(c.create());
+ }
+}
+
+class Grouped : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged REVISION 1)
+public:
+ int prop() const { return m_prop; }
+ void setProp(int prop)
+ {
+ if (prop != m_prop) {
+ m_prop = prop;
+ emit propChanged(prop);
+ }
+ }
+
+signals:
+ Q_REVISION(1) void propChanged(int prop);
+
+private:
+ int m_prop = 0;
+};
+
+class MyItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Grouped *grouped READ grouped CONSTANT)
+public:
+ MyItem() : m_grouped(new Grouped) {}
+ Grouped *grouped() const { return m_grouped.data(); }
+
+private:
+ QScopedPointer<Grouped> m_grouped;
+};
+
+void tst_qqmlmetatype::revisionedGroupedProperties()
+{
+ qmlClearTypeRegistrations();
+ qmlRegisterType<MyItem>("GroupedTest", 1, 0, "MyItem");
+ qmlRegisterType<MyItem, 1>("GroupedTest", 1, 1, "MyItem");
+ qmlRegisterUncreatableType<Grouped>("GroupedTest", 1, 0, "Grouped", "Grouped");
+ qmlRegisterUncreatableType<Grouped, 1>("GroupedTest", 1, 1, "Grouped", "Grouped");
+
+ {
+ QQmlEngine engine;
+ QQmlComponent valid(&engine, testFileUrl("revisionedGroupedPropertiesValid.qml"));
+ QVERIFY(valid.isReady());
+ QScopedPointer<QObject> obj(valid.create());
+ QVERIFY(!obj.isNull());
+ }
+
+ {
+ QQmlEngine engine;
+ QQmlComponent invalid(&engine, testFileUrl("revisionedGroupedPropertiesInvalid.qml"));
+ QVERIFY(invalid.isError());
+ }
+}
+
QTEST_MAIN(tst_qqmlmetatype)
#include "tst_qqmlmetatype.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
index fa9782f8c2..b44bc58373 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidFirstCommandModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
index fe01507412..ccd1066a36 100644
--- a/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro
deleted file mode 100644
index 150f2f08d3..0000000000
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-TEMPLATE = lib
-CONFIG += plugin
-SOURCES = plugin.cpp
-QT = core qml
-DESTDIR = ../imports/org/qtproject/InvalidStrictModule
-
-QT += core-private gui-private qml-private
-
-IMPORT_FILES = \
- qmldir
-
-include (../../../shared/imports.pri)
diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir
deleted file mode 100644
index 20716dc9f9..0000000000
--- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir
+++ /dev/null
@@ -1,2 +0,0 @@
-module org.qtproject.InvalidStrictModule
-plugin invalidStrictModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir
new file mode 100644
index 0000000000..104c4bf673
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir
@@ -0,0 +1,2 @@
+module moduleWithStaticPlugin
+plugin secondStaticPlugin
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir
new file mode 100644
index 0000000000..45a02b2ffe
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir
@@ -0,0 +1,2 @@
+module moduleWithWaitingPlugin
+plugin pluginThatWaits
diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
index 92d30351a7..610710fbf8 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp
@@ -36,7 +36,7 @@ class MyPluginType : public QObject
Q_PROPERTY(QString value READ value)
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
QString value() const { return "Hello"; }
};
@@ -47,7 +47,7 @@ class MyNestedPluginType : public QObject
Q_PROPERTY(QString value READ value)
public:
- MyNestedPluginType(QObject *parent=0) : QObject(parent) {}
+ MyNestedPluginType(QObject *parent=nullptr) : QObject(parent) {}
QString value() const { return "Goodbye"; }
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
index 5fc05b91bd..4c2109e02a 100644
--- a/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp
index 515d56a3c4..cb8c395fdf 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp
@@ -37,7 +37,7 @@ class MyChildPluginType : public QObject
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
public:
- MyChildPluginType(QObject *parent=0) : QObject(parent)
+ MyChildPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("child import2.1 worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
index 6cae5254bc..ced7e0895d 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/plugin.cpp
@@ -37,7 +37,7 @@ class MyPluginType : public QObject
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
public:
- MyPluginType(QObject *parent=0) : QObject(parent)
+ MyPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("import2.1 worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.2/plugin.cpp
index ecec870374..67cfc2a579 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.2/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.2/plugin.cpp
@@ -37,7 +37,7 @@ class MyPluginType : public QObject
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
public:
- MyPluginType(QObject *parent=0) : QObject(parent)
+ MyPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("import2.2 worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp
index 56545cfa3c..7b8f2a96be 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp
@@ -37,7 +37,7 @@ class MyChildPluginType : public QObject
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
public:
- MyChildPluginType(QObject *parent=0) : QObject(parent)
+ MyChildPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("child import2 worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
index 49a2a747a4..8a4598e3bf 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/plugin.cpp
@@ -37,7 +37,7 @@ class MyPluginType : public QObject
Q_PROPERTY(int valueOnlyIn2 READ value WRITE setValue)
public:
- MyPluginType(QObject *parent=0) : QObject(parent)
+ MyPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("import2 worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp
index 28490d3d98..6a2deca1df 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp
@@ -36,7 +36,7 @@ class MyChildPluginType : public QObject
Q_PROPERTY(int value READ value WRITE setValue)
public:
- MyChildPluginType(QObject *parent=0) : QObject(parent)
+ MyChildPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("child import worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
index db51185de6..5e39966a2a 100644
--- a/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/plugin/plugin.cpp
@@ -36,7 +36,7 @@ class MyPluginType : public QObject
Q_PROPERTY(int value READ value WRITE setValue)
public:
- MyPluginType(QObject *parent=0) : QObject(parent)
+ MyPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("import worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
index 7669d65568..5c3c1b81c6 100644
--- a/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/pluginWrongCase/plugin.cpp
@@ -36,7 +36,7 @@ class MyPluginType : public QObject
Q_PROPERTY(int value READ value WRITE setValue)
public:
- MyPluginType(QObject *parent=0) : QObject(parent)
+ MyPluginType(QObject *parent=nullptr) : QObject(parent)
{
qWarning("import worked");
}
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
index 92211ebf9d..0780ea8325 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
index 3df3e9cc81..bc896716e2 100644
--- a/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
index afdeea80f4..ae8c231aab 100644
--- a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
@@ -33,7 +33,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
index 0f548aa6f8..ae13a041cc 100644
--- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
@@ -11,7 +11,6 @@ SUBDIRS =\
nestedPlugin\
strictModule\
strictModule.2\
- invalidStrictModule\
nonstrictModule\
preemptiveModule\
preemptedStrictModule\
diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp
index 4f5176ae62..312ed325b1 100644
--- a/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/strictModule.2/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
index eaa9aeb1d0..a622078159 100644
--- a/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp
@@ -34,7 +34,7 @@ class MyPluginType : public QObject
{
Q_OBJECT
public:
- MyPluginType(QObject *parent=0) : QObject(parent) {}
+ MyPluginType(QObject *parent=nullptr) : QObject(parent) {}
};
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index 8600e1e8ab..97ca3fa1de 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -29,6 +29,10 @@
#include <qdir.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonarray.h>
#include <QDebug>
#if defined(Q_OS_MAC)
@@ -73,12 +77,80 @@ private slots:
void importsChildPlugin();
void importsChildPlugin2();
void importsChildPlugin21();
+ void parallelPluginImport();
private:
QString m_importsDirectory;
QString m_dataImportsDirectory;
};
+class PluginThatWaits : public QQmlExtensionPlugin
+{
+public:
+ static QByteArray metaData;
+
+ static QMutex initializeEngineEntered;
+ static QWaitCondition waitingForInitializeEngineEntry;
+ static QMutex leavingInitializeEngine;
+ static QWaitCondition waitingForInitializeEngineLeave;
+
+ void registerTypes(const char *uri) override
+ {
+ qmlRegisterModule(uri, 1, 0);
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ initializeEngineEntered.lock();
+ leavingInitializeEngine.lock();
+ waitingForInitializeEngineEntry.wakeOne();
+ initializeEngineEntered.unlock();
+ waitingForInitializeEngineLeave.wait(&leavingInitializeEngine);
+ leavingInitializeEngine.unlock();
+ }
+};
+QByteArray PluginThatWaits::metaData;
+QMutex PluginThatWaits::initializeEngineEntered;
+QWaitCondition PluginThatWaits::waitingForInitializeEngineEntry;
+QMutex PluginThatWaits::leavingInitializeEngine;
+QWaitCondition PluginThatWaits::waitingForInitializeEngineLeave;
+
+class SecondStaticPlugin : public QQmlExtensionPlugin
+{
+public:
+ static QByteArray metaData;
+
+ void registerTypes(const char *uri) override
+ {
+ qmlRegisterModule(uri, 1, 0);
+ }
+};
+QByteArray SecondStaticPlugin::metaData;
+
+template <typename PluginType>
+void registerStaticPlugin(const char *uri)
+{
+ QStaticPlugin plugin;
+ plugin.instance = []() {
+ static PluginType plugin;
+ return static_cast<QObject*>(&plugin);
+ };
+
+ QJsonObject md;
+ md.insert(QStringLiteral("IID"), QQmlExtensionInterface_iid);
+ QJsonArray uris;
+ uris.append(uri);
+ md.insert(QStringLiteral("uri"), uris);
+
+ PluginType::metaData.append(QLatin1String("QTMETADATA "));
+ PluginType::metaData.append(QJsonDocument(md).toBinaryData());
+
+ plugin.rawMetaData = []() {
+ return PluginType::metaData.constData();
+ };
+ qRegisterStaticPluginFunction(plugin);
+};
+
void tst_qqmlmoduleplugin::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -88,6 +160,9 @@ void tst_qqmlmoduleplugin::initTestCase()
m_dataImportsDirectory = directory() + QStringLiteral("/imports");
QVERIFY2(QFileInfo(m_dataImportsDirectory).isDir(),
qPrintable(QString::fromLatin1("Imports directory '%1' does not exist.").arg(m_dataImportsDirectory)));
+
+ registerStaticPlugin<PluginThatWaits>("moduleWithWaitingPlugin");
+ registerStaticPlugin<SecondStaticPlugin>("moduleWithStaticPlugin");
}
#define VERIFY_ERRORS(errorfile) \
@@ -143,7 +218,7 @@ void tst_qqmlmoduleplugin::importsPlugin()
qWarning() << err;
VERIFY_ERRORS(0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(),123);
delete object;
}
@@ -211,7 +286,7 @@ void tst_qqmlmoduleplugin::importPluginWithQmlFile()
qWarning() << err;
VERIFY_ERRORS(0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
}
@@ -227,7 +302,7 @@ void tst_qqmlmoduleplugin::remoteImportWithQuotedUrl()
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
QObject *object = component.create();
QCOMPARE(object->property("width").toInt(), 300);
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
delete object;
foreach (QQmlError err, component.errors())
@@ -249,7 +324,7 @@ void tst_qqmlmoduleplugin::remoteImportWithUnquotedUri()
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("width").toInt(), 300);
delete object;
@@ -258,6 +333,29 @@ void tst_qqmlmoduleplugin::remoteImportWithUnquotedUri()
VERIFY_ERRORS(0);
}
+static QByteArray msgComponentError(const QQmlComponent &c, const QQmlEngine *engine /* = 0 */)
+{
+ QString result;
+ const QList<QQmlError> errors = c.errors();
+ QTextStream str(&result);
+ str << "Component '" << c.url().toString() << "' has " << errors.size() << " errors: '";
+ for (int i = 0; i < errors.size(); ++i) {
+ if (i)
+ str << ", '";
+ str << errors.at(i).toString() << '\'';
+ }
+ if (!engine) {
+ if (QQmlContext *context = c.creationContext())
+ engine = context->engine();
+ }
+ if (engine) {
+ str << " Import paths: (" << engine->importPathList().join(QStringLiteral(", "))
+ << ") Plugin paths: (" << engine->pluginPathList().join(QStringLiteral(", "))
+ << ')';
+ }
+ return result.toLocal8Bit();
+}
+
// QTBUG-17324
void tst_qqmlmoduleplugin::importsMixedQmlCppPlugin()
@@ -271,7 +369,7 @@ void tst_qqmlmoduleplugin::importsMixedQmlCppPlugin()
QQmlComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.qml")));
QObject *o = component.create();
- QVERIFY2(o != 0, QQmlDataTest::msgComponentError(component, &engine));
+ QVERIFY2(o != nullptr, msgComponentError(component, &engine));
QCOMPARE(o->property("test").toBool(), true);
delete o;
}
@@ -280,7 +378,7 @@ void tst_qqmlmoduleplugin::importsMixedQmlCppPlugin()
QQmlComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.2.qml")));
QObject *o = component.create();
- QVERIFY2(o != 0, QQmlDataTest::msgComponentError(component, &engine));
+ QVERIFY2(o != nullptr, msgComponentError(component, &engine));
QCOMPARE(o->property("test").toBool(), true);
QCOMPARE(o->property("test2").toBool(), true);
delete o;
@@ -408,7 +506,7 @@ void tst_qqmlmoduleplugin::importLocalModule()
component.setData(qml.toUtf8(), testFileUrl("empty.qml"));
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("majorVersion").value<int>(), majorVersion);
QCOMPARE(object->property("minorVersion").value<int>(), minorVersion);
}
@@ -465,7 +563,7 @@ void tst_qqmlmoduleplugin::importStrictModule()
if (error.isEmpty()) {
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
} else {
QVERIFY(!component.isReady());
QCOMPARE(component.errors().count(), 1);
@@ -506,12 +604,6 @@ void tst_qqmlmoduleplugin::importStrictModule_data()
<< QString()
<< QString();
- QTest::newRow("wrong target")
- << "import org.qtproject.InvalidStrictModule 1.0\n"
- "MyPluginType {}"
- << QString()
- << ":1:1: plugin cannot be loaded for module \"org.qtproject.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'org.qtproject.SomeOtherModule'";
-
QTest::newRow("non-strict clash")
<< "import org.qtproject.NonstrictModule 1.0\n"
"MyPluginType {}"
@@ -555,7 +647,7 @@ void tst_qqmlmoduleplugin::importProtectedModule()
//If plugin is loaded due to import, should assert
QScopedPointer<QObject> object(component.create());
//qDebug() << component.errorString();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
}
void tst_qqmlmoduleplugin::importVersionedModule()
@@ -596,7 +688,7 @@ void tst_qqmlmoduleplugin::importsChildPlugin()
qWarning() << err;
VERIFY_ERRORS(0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(),123);
delete object;
}
@@ -613,7 +705,7 @@ void tst_qqmlmoduleplugin::importsChildPlugin2()
qWarning() << err;
VERIFY_ERRORS(0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(),123);
delete object;
}
@@ -630,11 +722,56 @@ void tst_qqmlmoduleplugin::importsChildPlugin21()
qWarning() << err;
VERIFY_ERRORS(0);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(),123);
delete object;
}
+void tst_qqmlmoduleplugin::parallelPluginImport()
+{
+ QMutexLocker locker(&PluginThatWaits::initializeEngineEntered);
+
+ QThread worker;
+ QObject::connect(&worker, &QThread::started, [&worker](){
+ // Engines in separate threads are tricky, but as long as we do not create a graphical
+ // object and move objects created by the engines across thread boundaries, this is safe.
+ // At the same time this allows us to place the engine's loader thread into the position
+ // where, without the fix for this bug, the global lock is acquired.
+ QQmlEngine engineInThread;
+
+ QQmlComponent component(&engineInThread);
+ component.setData("import moduleWithWaitingPlugin 1.0\nimport QtQml 2.0\nQtObject {}",
+ QUrl());
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ worker.quit();
+ });
+ worker.start();
+
+ PluginThatWaits::waitingForInitializeEngineEntry.wait(&PluginThatWaits::initializeEngineEntered);
+
+ {
+ // After acquiring this lock, the engine in the other thread as well as its type loader
+ // thread are blocked. However they should not hold the global plugin lock
+ // qmlEnginePluginsWithRegisteredTypes()->mutex in qqmllimports.cpp, allowing for the load
+ // of a component in a different engine with its own plugin to proceed.
+ QMutexLocker continuationLock(&PluginThatWaits::leavingInitializeEngine);
+
+ QQmlEngine secondEngine;
+ QQmlComponent secondComponent(&secondEngine);
+ secondComponent.setData("import moduleWithStaticPlugin 1.0\nimport QtQml 2.0\nQtObject {}",
+ QUrl());
+ QScopedPointer<QObject> o(secondComponent.create());
+ QVERIFY(!o.isNull());
+
+ PluginThatWaits::waitingForInitializeEngineLeave.wakeOne();
+ }
+
+ worker.wait();
+}
+
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
index 43bd112415..118ca26ee9 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
@@ -10,4 +10,12 @@ include (../../shared/util.pri)
TESTDATA = data/* imports/* $$OUT_PWD/imports/*
+waitingPlugin.files = moduleWithWaitingPlugin
+waitingPlugin.prefix = /qt-project.org/imports/
+RESOURCES += waitingPlugin
+
+staticPlugin.files = moduleWithStaticPlugin
+staticPlugin.prefix = /qt-project.org/imports/
+RESOURCES += staticPlugin
+
QT += core-private gui-private qml-private network testlib
diff --git a/tests/auto/qml/qqmlnotifier/data/objectRenamer.qml b/tests/auto/qml/qqmlnotifier/data/objectRenamer.qml
new file mode 100644
index 0000000000..65d2206880
--- /dev/null
+++ b/tests/auto/qml/qqmlnotifier/data/objectRenamer.qml
@@ -0,0 +1,9 @@
+import QtQml 2.2
+
+QtObject {
+ property Timer timer: Timer {
+ running: true
+ interval: 0
+ onTriggered: parent.objectName = "havoc"
+ }
+}
diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
index beb60925bb..6e831eacc1 100644
--- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
+++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
@@ -32,6 +32,9 @@
#include <QQmlContext>
#include <qqml.h>
#include <QMetaMethod>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
#include "../../shared/util.h"
@@ -46,21 +49,17 @@ class ExportedClass : public QObject
Q_PROPERTY(int v4BindingProp2 READ v4BindingProp2 NOTIFY v4BindingProp2Changed)
Q_PROPERTY(int scriptBindingProp READ scriptBindingProp NOTIFY scriptBindingPropChanged)
public:
- int qmlObjectPropConnections;
- int cppObjectPropConnections;
- int unboundPropConnections;
- int v8BindingPropConnections;
- int v4BindingPropConnections;
- int v4BindingProp2Connections;
- int scriptBindingPropConnections;
- int boundSignalConnections;
- int unusedSignalConnections;
-
- ExportedClass()
- : qmlObjectPropConnections(0), cppObjectPropConnections(0), unboundPropConnections(0),
- v8BindingPropConnections(0), v4BindingPropConnections(0), v4BindingProp2Connections(0),
- scriptBindingPropConnections(0), boundSignalConnections(0), unusedSignalConnections(0)
- {}
+ int qmlObjectPropConnections = 0;
+ int cppObjectPropConnections = 0;
+ int unboundPropConnections = 0;
+ int v8BindingPropConnections = 0;
+ int v4BindingPropConnections = 0;
+ int v4BindingProp2Connections = 0;
+ int scriptBindingPropConnections = 0;
+ int boundSignalConnections = 0;
+ int unusedSignalConnections = 0;
+
+ ExportedClass() {}
~ExportedClass()
{
@@ -98,7 +97,7 @@ public:
}
protected:
- void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
+ void connectNotify(const QMetaMethod &signal) override {
if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections++;
if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections++;
if (signal.name() == "unboundPropChanged") unboundPropConnections++;
@@ -112,7 +111,7 @@ protected:
//qDebug() << Q_FUNC_INFO << this << signal.name();
}
- void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
+ void disconnectNotify(const QMetaMethod &signal) override {
if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections--;
if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections--;
if (signal.name() == "unboundPropChanged") unboundPropConnections--;
@@ -141,12 +140,10 @@ class tst_qqmlnotifier : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qqmlnotifier()
- : root(0), exportedClass(0), exportedObject(0)
- {}
+ tst_qqmlnotifier() {}
private slots:
- void initTestCase() Q_DECL_OVERRIDE;
+ void initTestCase() override;
void cleanupTestCase();
void testConnectNotify();
@@ -162,13 +159,15 @@ private slots:
void disconnectOnDestroy();
void lotsOfBindings();
+ void deleteFromHandler();
+
private:
void createObjects();
QQmlEngine engine;
- QObject *root;
- ExportedClass *exportedClass;
- ExportedClass *exportedObject;
+ QObject *root = nullptr;
+ ExportedClass *exportedClass = nullptr;
+ ExportedClass *exportedObject = nullptr;
};
void tst_qqmlnotifier::initTestCase()
@@ -180,28 +179,28 @@ void tst_qqmlnotifier::initTestCase()
void tst_qqmlnotifier::createObjects()
{
delete root;
- root = 0;
- exportedClass = exportedObject = 0;
+ root = nullptr;
+ exportedClass = exportedObject = nullptr;
QQmlComponent component(&engine, testFileUrl("connectnotify.qml"));
exportedObject = new ExportedClass();
exportedObject->setObjectName("exportedObject");
engine.rootContext()->setContextProperty("_exportedObject", exportedObject);
root = component.create();
- QVERIFY(root != 0);
+ QVERIFY(root != nullptr);
exportedClass = qobject_cast<ExportedClass *>(
root->findChild<ExportedClass*>("exportedClass"));
- QVERIFY(exportedClass != 0);
+ QVERIFY(exportedClass != nullptr);
exportedClass->verifyReceiverCount();
}
void tst_qqmlnotifier::cleanupTestCase()
{
delete root;
- root = 0;
+ root = nullptr;
delete exportedObject;
- exportedObject = 0;
+ exportedObject = nullptr;
}
void tst_qqmlnotifier::testConnectNotify()
@@ -303,7 +302,7 @@ void tst_qqmlnotifier::disconnectOnDestroy()
// Deleting a QML object should remove all connections. For exportedClass, this is tested in
// the destructor, and for exportedObject, it is tested below.
delete root;
- root = 0;
+ root = nullptr;
QCOMPARE(exportedObject->cppObjectPropConnections, 0);
exportedObject->verifyReceiverCount();
}
@@ -341,6 +340,33 @@ void tst_qqmlnotifier::lotsOfBindings()
delete e;
}
+void tst_qqmlnotifier::deleteFromHandler()
+{
+#if !QT_CONFIG(process)
+ QSKIP("Need QProcess support to test qFatal.");
+#else
+ if (qEnvironmentVariableIsSet("TST_QQMLNOTIFIER_DO_CRASH")) {
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("objectRenamer.qml"));
+ QPointer<QObject> mess = component.create();
+ QObject::connect(mess, &QObject::objectNameChanged, [&]() { delete mess; });
+ QTRY_VERIFY(mess.isNull()); // BANG!
+ } else {
+ QProcess process;
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("TST_QQMLNOTIFIER_DO_CRASH", "bang");
+ process.setProcessEnvironment(env);
+ process.setProgram(QCoreApplication::applicationFilePath());
+ process.setArguments({"deleteFromHandler"});
+ process.start();
+ QTRY_COMPARE(process.exitStatus(), QProcess::CrashExit);
+ const QByteArray output = process.readAllStandardOutput();
+ QVERIFY(output.contains("QFATAL"));
+ QVERIFY(output.contains("destroyed while one of its QML signal handlers is in progress"));
+ }
+#endif
+}
+
QTEST_MAIN(tst_qqmlnotifier)
#include "tst_qqmlnotifier.moc"
diff --git a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
index 430a9c2a22..fb63d811a8 100644
--- a/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
+++ b/tests/auto/qml/qqmlobjectmodel/tst_qqmlobjectmodel.cpp
@@ -26,6 +26,7 @@
**
****************************************************************************/
#include <QtQml/private/qqmlobjectmodel_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
#include <QtTest/qsignalspy.h>
#include <QtTest/qtest.h>
@@ -46,16 +47,41 @@ static bool compareItems(QQmlObjectModel *model, const QObjectList &items)
return true;
}
+static bool verifyChangeSet(const QQmlChangeSet &changeSet, int expectedInserts, int expectedRemoves, bool isMove, int moveId = -1)
+{
+ int actualRemoves = 0;
+ for (const QQmlChangeSet::Change &r : changeSet.removes()) {
+ if (r.isMove() != isMove && (!isMove || moveId == r.moveId))
+ return false;
+ actualRemoves += r.count;
+ }
+
+ int actualInserts = 0;
+ for (const QQmlChangeSet::Change &i : changeSet.inserts()) {
+ if (i.isMove() != isMove && (!isMove || moveId == i.moveId))
+ return false;
+ actualInserts += i.count;
+ }
+
+ return actualRemoves == expectedRemoves && actualInserts == expectedInserts;
+}
+
+Q_DECLARE_METATYPE(QQmlChangeSet)
+
void tst_QQmlObjectModel::changes()
{
QQmlObjectModel model;
+ qRegisterMetaType<QQmlChangeSet>();
+
QSignalSpy countSpy(&model, SIGNAL(countChanged()));
QSignalSpy childrenSpy(&model, SIGNAL(childrenChanged()));
+ QSignalSpy modelUpdateSpy(&model, SIGNAL(modelUpdated(QQmlChangeSet,bool)));
int count = 0;
int countSignals = 0;
int childrenSignals = 0;
+ int modelUpdateSignals = 0;
QObjectList items;
QObject item0, item1, item2, item3;
@@ -66,6 +92,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 0, false));
// insert(0, item1) -> [item1, item0]
model.insert(0, &item1); items.insert(0, &item1);
@@ -73,6 +101,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 0, false));
// append(item2) -> [item1, item0, item2]
model.append(&item2); items.append(&item2);
@@ -80,6 +110,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 0, false));
// insert(2, item3) -> [item1, item0, item3, item2]
model.insert(2, &item3); items.insert(2, &item3);
@@ -87,6 +119,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 0, false));
// move(0, 1) -> [item0, item1, item3, item2]
model.move(0, 1); items.move(0, 1);
@@ -94,6 +128,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 1, true, 1));
// move(3, 2) -> [item0, item1, item2, item3]
model.move(3, 2); items.move(3, 2);
@@ -101,6 +137,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 1, 1, true, 2));
// remove(0) -> [item1, item2, item3]
model.remove(0); items.removeAt(0);
@@ -108,6 +146,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 0, 1, false));
// remove(2) -> [item1, item2]
model.remove(2); items.removeAt(2);
@@ -115,6 +155,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 0, 1, false));
// clear() -> []
model.clear(); items.clear();
@@ -122,6 +164,8 @@ void tst_QQmlObjectModel::changes()
QVERIFY(compareItems(&model, items));
QCOMPARE(countSpy.count(), ++countSignals);
QCOMPARE(childrenSpy.count(), ++childrenSignals);
+ QCOMPARE(modelUpdateSpy.count(), ++modelUpdateSignals);
+ QVERIFY(verifyChangeSet(modelUpdateSpy.last().first().value<QQmlChangeSet>(), 0, 2, false));
}
QTEST_MAIN(tst_QQmlObjectModel)
diff --git a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
index c3ace5e0f3..44ce1d6987 100644
--- a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
+++ b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
@@ -44,7 +44,7 @@ class CustomObject: public QObject
{
Q_OBJECT
public:
- CustomObject(QObject *parent = 0)
+ CustomObject(QObject *parent = nullptr)
: QObject(parent) {}
};
@@ -53,7 +53,7 @@ void tst_qqmlopenmetaobject::createProperties()
QQmlEngine engine;
CustomObject object;
const QQmlRefPointer<QQmlOpenMetaObjectType> mot = new QQmlOpenMetaObjectType(object.metaObject(), &engine);
- QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot);
+ QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot.data());
mo->setCached(true);
mot->createProperty("customProperty");
QVERIFY(true);
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index ba2b836a6d..c2c73935c0 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -50,6 +50,10 @@ private slots:
void qmlParser();
#endif
void invalidEscapeSequence();
+ void stringLiteral();
+ void noSubstitutionTemplateLiteral();
+ void templateLiteral();
+ void leadingSemicolonInClass();
private:
QStringList excludedDirs;
@@ -78,6 +82,13 @@ public:
const quint32 parentBegin = parent->firstSourceLocation().begin();
const quint32 parentEnd = parent->lastSourceLocation().end();
+ if (node->firstSourceLocation().begin() < parentBegin)
+ qDebug() << "first source loc failed: node:" << node->kind << "at" << node->firstSourceLocation().startLine << "/" << node->firstSourceLocation().startColumn
+ << "parent" << parent->kind << "at" << parent->firstSourceLocation().startLine << "/" << parent->firstSourceLocation().startColumn;
+ if (node->lastSourceLocation().end() > parentEnd)
+ qDebug() << "first source loc failed: node:" << node->kind << "at" << node->lastSourceLocation().startLine << "/" << node->lastSourceLocation().startColumn
+ << "parent" << parent->kind << "at" << parent->lastSourceLocation().startLine << "/" << parent->lastSourceLocation().startColumn;
+
QVERIFY(node->firstSourceLocation().begin() >= parentBegin);
QVERIFY(node->lastSourceLocation().end() <= parentEnd);
}
@@ -183,13 +194,12 @@ void tst_qqmlparser::qmlParser()
Lexer lexer(&engine);
lexer.setCode(code, 1, qmlMode);
Parser parser(&engine);
- if (qmlMode)
- parser.parse();
- else
- parser.parseProgram();
+ bool ok = qmlMode ? parser.parse() : parser.parseProgram();
- check::Check chk;
- chk(parser.rootNode());
+ if (ok) {
+ check::Check chk;
+ chk(parser.rootNode());
+ }
}
#endif
@@ -204,6 +214,76 @@ void tst_qqmlparser::invalidEscapeSequence()
parser.parse();
}
+void tst_qqmlparser::stringLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("'hello string'");
+ lexer.setCode(code , 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+ auto *literal = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expression);
+ QVERIFY(literal);
+ QCOMPARE(literal->value, "hello string");
+ QCOMPARE(literal->firstSourceLocation().begin(), 0);
+ QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::noSubstitutionTemplateLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("`hello template`");
+ lexer.setCode(code, 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+
+ auto *literal = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+ QVERIFY(literal);
+
+ QCOMPARE(literal->value, "hello template");
+ QCOMPARE(literal->firstSourceLocation().begin(), 0);
+ QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::templateLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("`one plus one equals ${1+1}!`");
+ lexer.setCode(code, 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+
+ auto *templateLiteral = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+ QVERIFY(templateLiteral);
+
+ QCOMPARE(templateLiteral->firstSourceLocation().begin(), 0);
+ auto *e = templateLiteral->expression;
+ QVERIFY(e);
+}
+
+void tst_qqmlparser::leadingSemicolonInClass()
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String("class X{;n(){}}"), 1);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parseProgram());
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml b/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml
new file mode 100644
index 0000000000..43ccf24965
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-empty-input.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var promise: Promise.all([]);
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value.length !== 0) {
+ return;
+ }
+
+ wasTestSuccessful = true
+
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml b/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml
new file mode 100644
index 0000000000..ec59c47130
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-invoke-then-method.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int callCount: 0
+ property bool wasTestSuccessful: false
+
+ property var promise1: new Promise(function() {})
+ property var promise2: new Promise(function() {})
+ property var promise3: new Promise(function() {})
+
+ Component.onCompleted: {
+ promise1.then = null
+ console.log(promise1.then)
+
+ // TODO: This assinment works in JS scope but does not work
+ // in QML scope
+ promise1.then = promise2.then = promise3.then = function(a, b) {
+ console.log("then was called")
+ callCount++;
+ }
+
+ Promise.all([promise1, promise2, promise3])
+
+ console.log("callCount " + callCount)
+ wasTestSuccessful = (callCount === 3)
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml b/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml
new file mode 100644
index 0000000000..a9bdbf2fb7
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-noniterable-input.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var nonIterable: 3
+ property var promise: Promise.all(nonIterable);
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(err) {
+ if (!(err instanceof TypeError)) {
+ throw new Error("Should reject with TypeError")
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml
new file mode 100644
index 0000000000..0d3d31d494
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-last.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ // TODO!
+
+ property int resolveValue: 5
+ property int rejectValue: 10
+ property int resultValue: rejectValue
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+ property var promise4: Promise.reject(rejectValue)
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3, promise4]).then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value !== rejectValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml
new file mode 100644
index 0000000000..67ca95971c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-reject-reject-is-mid.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ // TODO!
+
+ property int resolveValue: 5
+ property int rejectValue: 10
+ property int resultValue: rejectValue
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: Promise.reject(rejectValue)
+ property var promise4: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3, promise4]).then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value !== rejectValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml b/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml
new file mode 100644
index 0000000000..1996b7f9c8
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-all-resolve.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 5
+ property var resultValue: [resolveValue, resolveValue, resolveValue]
+ property bool wasTestSuccessful: false
+
+
+ property var delayedEvent: Timer {
+ interval: 0
+ property var handler: null
+ onTriggered: {
+ if (handler) {
+ handler();
+ }
+ }
+ }
+
+ function postEvent(event, value) {
+ delayedEvent.handler = function() { event(value) }
+ delayedEvent.restart();
+ }
+
+ property var promise1: Promise.resolve(resolveValue);
+ property int promise2: resolveValue
+ property var promise3: new Promise(function (resolve, reject) {
+ postEvent(resolve, resolveValue)
+ })
+
+ Component.onCompleted: {
+ Promise.all([promise1, promise2, promise3]).then(function(value) {
+ if (value.length !== resultValue.length) {
+ return;
+ }
+
+ for (var i in value) {
+ if (value[i] !== resultValue[i]) {
+ return;
+ }
+ }
+
+ wasTestSuccessful = true
+
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml
new file mode 100644
index 0000000000..4c54ad3fc7
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-async-reject-with-value.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int rejectValue: 5
+ property bool wasTestSuccessful: false
+
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ reject(rejectValue)
+ }
+ delayedExecutor.restart();
+ })
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml
new file mode 100644
index 0000000000..a491394a30
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-async-resolve-with-value.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 5
+ property bool wasTestSuccessful: false
+
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ resolve(resolveValue)
+ }
+ delayedExecutor.restart();
+ })
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml
new file mode 100644
index 0000000000..e2a264dd3c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-function-extensible.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var executorFunction: null
+
+ function notPromise(executor) {
+ executorFunction = executor;
+ executor(function() {}, function() {});
+ }
+
+ Component.onCompleted: {
+ Promise.resolve.call(notPromise);
+ wasTestSuccessful = executorFunction !== null &&
+ Object.isExtensible(executorFunction);
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml
new file mode 100644
index 0000000000..4e609ae4a4
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-reject.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property string resolution: "reject promise";
+
+ property bool wasExecutorCalled: false
+ property bool wasPromiseRejected: false
+ property bool wasPromiseTypeReturnedByThen: false;
+ property bool wasResolutionForwardedCorrectly: false;
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ wasExecutorCalled = true;
+ reject(resolution);
+ });
+
+ var res = promise.then(function(result) {
+ wasPromiseRejected = false;
+ }, function(err) {
+ wasPromiseRejected = true;
+ wasResolutionForwardedCorrectly = (err === resolution);
+ });
+
+ wasPromiseTypeReturnedByThen = (typeof res === 'Promise');
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml
new file mode 100644
index 0000000000..659636d6a8
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-resolve.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property string resolution: "fullfill promise";
+
+ property bool wasExecutorCalled: false
+ property bool wasPromiseResolved: false
+ property bool wasPromiseTypeReturnedByThen: false
+ property bool wasResolutionForwardedCorrectly: false
+ property bool wasNewPromiseObjectCreatedByThen: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ wasExecutorCalled = true;
+ resolve(resolution);
+ });
+
+ var res = promise.then(function(result) {
+ wasPromiseResolved = true;
+ wasResolutionForwardedCorrectly = (result === resolution);
+ }, function(err) {
+ wasPromiseResolved = false;
+ });
+
+ wasPromiseTypeReturnedByThen = (typeof res === 'Promise');
+ console.debug("typeof res: " + (typeof res)) // TODO: remove
+ wasNewPromiseObjectCreatedByThen = (res !== promise);
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml b/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml
new file mode 100644
index 0000000000..9e912635d6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-executor-throw-exception.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: false
+
+ property var errorObject: { text: "Exception should not escape executor" }
+
+ property var promise: new Promise(function() {
+ throw errorObject
+ })
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(error) {
+ if (error === errorObject) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-get-length.qml b/tests/auto/qml/qqmlpromise/data/promise-get-length.qml
new file mode 100644
index 0000000000..d42bc61179
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-get-length.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: (Promise.length === 1)
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml b/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml
new file mode 100644
index 0000000000..188b1c2f15
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-empty-input.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property bool wasTestSuccessful: true
+
+ Component.onCompleted: {
+ Promise.race([]).then(function(value) {
+ wasTestSuccessful = false
+ throw new Error("Should never be called")
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml
new file mode 100644
index 0000000000..1d6e47b87e
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st-in-executor-function.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+
+ property var promise: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ property var resolvedPromiseArray: [promise, Promise.resolve(resolveValue + 5)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml
new file mode 100644
index 0000000000..bd7b3a4026
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-1st.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+ property var resolvedPromiseArray: [Promise.resolve(resolveValue), Promise.resolve(resolveValue + 5)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml
new file mode 100644
index 0000000000..e4c1b98acc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-race-resolve-2nd.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.4
+
+QtObject {
+ property int resolveValue: 33
+
+ property var delayedExecutor: Timer {
+ interval: 0
+ property var executor: null
+ onTriggered: {
+ if (executor) {
+ executor();
+ }
+ }
+ }
+
+ property var promise: new Promise(function (resolve, reject) {
+ delayedExecutor.executor = function() {
+ resolve(resolveValue + 5)
+ }
+ delayedExecutor.restart();
+ })
+
+ property var resolvedPromiseArray: [promise, Promise.resolve(resolveValue)]
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ Promise.race(resolvedPromiseArray).then(function(value) {
+ if (value !== resolveValue) {
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml b/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml
new file mode 100644
index 0000000000..a83d2670ba
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-reject-catch.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+ property var promise: Promise.reject(rejectValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }).then(function() {
+ throw new Error("Should never be called")
+ }).catch(function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml
new file mode 100644
index 0000000000..6b81e83643
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-reject-with-value.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+ property var promise: Promise.reject(rejectValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(value) {
+ if (value === rejectValue) {
+ wasTestSuccessful = true
+ }
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml
new file mode 100644
index 0000000000..40d35e5a3b
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-function-length.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var resolveFunction
+ property var promise: new Promise(function(resolve, reject) {
+ resolveFunction = resolve
+ })
+
+ property bool wasTestSuccessful: (typeof resolveFunction === "function" &&
+ typeof resolveFunction.length !== "undefined" &&
+ resolveFunction.length === 1)
+
+ Component.onCompleted: {
+ // TODO: Function length field should be NotWritabel & NotEnumerable & Configurable
+ console.log(Object.getOwnPropertyDescriptor(resolveFunction, "length").configurable)
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml
new file mode 100644
index 0000000000..fbdcc0f8e9
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-is-a-function.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property bool wasTestSuccessful: (typeof Promise.resolve === "function")
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml
new file mode 100644
index 0000000000..04d2209907
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-array.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var resolveValue: [1, 2, 3]
+ property var promise: Promise.resolve(resolveValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml
new file mode 100644
index 0000000000..61c7bf17a6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-empty.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property var promise: Promise.resolve()
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (typeof value === "undefined") {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml
new file mode 100644
index 0000000000..65b39508ad
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-promise.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+ property var originalPromise: Promise.resolve(resolveValue)
+
+ property var castPromise: Promise.resolve(originalPromise)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ if (castPromise !== originalPromise) {
+ console.log("resolve did not return original promise")
+ return;
+ }
+
+ castPromise.then(function(value) {
+ if (value !== resolveValue) {
+ console.log("resolved values are not the same")
+ return;
+ }
+
+ wasTestSuccessful = true
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml
new file mode 100644
index 0000000000..a1294cf9a6
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/promise-resolve-with-value.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+ property var promise: Promise.resolve(resolveValue)
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ promise.then(function(value) {
+ if (value === resolveValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml b/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml
new file mode 100644
index 0000000000..ee7e3ed7be
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-fulfilled-non-callable.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+
+ property bool promise1WasResolved: false
+ property bool promise2WasResolved: false
+ property bool promise3WasResolved: false
+ property bool promise4WasResolved: true
+
+ property bool wasTestSuccessful: promise1WasResolved && promise2WasResolved &&
+ promise3WasResolved && promise4WasResolved
+
+ // TODO: Should this work as well?
+ // property Promise promise
+ property var promise1: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise2: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise3: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+ property var promise4: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ Component.onCompleted: {
+ promise1.then().then(function (result) {
+ promise1WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise2.then(3, 5).then(function (result) {
+ promise2WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise3.then(null, function() {
+ throw new Error("Should never be called")
+ }).then(function (result) {
+ promise3WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ /*
+ promise4.then(undefined, undefined).then(function (result) {
+ promise4WasResolved = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ */
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml b/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml
new file mode 100644
index 0000000000..645ae9b07c
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-reject-chaining.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 1
+ property int expectedValue: rejectValue + 2;
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ reject(rejectValue);
+ });
+
+ promise.then(function() {
+ throw new Error("Should never be called")
+ }, function(val) {
+ return val + 2;
+ }).then(function(val) {
+ if (val === expectedValue) {
+ wasTestSuccessful = true
+ }
+ }, function() {
+ throw new Error("Should never be called")
+ });
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml b/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml
new file mode 100644
index 0000000000..df708c6218
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-reject-non-callable.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int rejectValue: 5
+
+ property bool promise1WasRejected: false
+ property bool promise2WasRejected: false
+
+ property bool wasTestSuccessful: promise1WasRejected && promise2WasRejected
+
+ // TODO: Should this work as well?
+ // property Promise promise
+ property var promise1: new Promise(function (resolve, reject) {
+ reject(rejectValue)
+ })
+ property var promise2: new Promise(function (resolve, reject) {
+ reject(rejectValue)
+ })
+
+ Component.onCompleted: {
+ promise1.then().then(function() {
+ promise1WasRejected = false
+ throw new Error("Should never be called")
+ }, function (result) {
+ promise1WasRejected = (result === rejectValue);
+ })
+ promise2.then(3, 5).then(function() {
+ promise2WasRejected = false
+ throw new Error("Should never be called")
+ }, function (result) {
+ promise2WasRejected = (result === rejectValue);
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml b/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml
new file mode 100644
index 0000000000..d65e9c86ac
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-resolve-chaining.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 1
+ property int expectedValue: resolveValue + 2;
+ property bool wasTestSuccessful: false
+
+ Component.onCompleted: {
+ var promise = new Promise(function(resolve, reject) {
+ resolve(resolveValue);
+ });
+
+ promise.then(function(val) {
+ return val + 2;
+ }).then(function(val) {
+ if (val === expectedValue) {
+ wasTestSuccessful = true;
+ }
+ });
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml b/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml
new file mode 100644
index 0000000000..48000d5ddc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/data/then-resolve-multiple-then.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+
+QtObject {
+ property int resolveValue: 5
+
+ property bool was1stCallSucessfull: false
+ property bool was2ndCallSucessfull: false
+
+ property bool wasTestSuccessful: was1stCallSucessfull && was2ndCallSucessfull
+
+ property var promise: new Promise(function (resolve, reject) {
+ resolve(resolveValue)
+ })
+
+ Component.onCompleted: {
+ promise.then(function (result) {
+ was1stCallSucessfull = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ promise.then(function (result) {
+ was2ndCallSucessfull = (result === resolveValue);
+ }, function() {
+ throw new Error("Should never be called")
+ })
+ }
+}
diff --git a/tests/auto/qml/qqmlpromise/qqmlpromise.pro b/tests/auto/qml/qqmlpromise/qqmlpromise.pro
new file mode 100644
index 0000000000..7cdb02cd61
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/qqmlpromise.pro
@@ -0,0 +1,46 @@
+CONFIG += testcase
+TARGET = tst_qqmlpromise
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qqmlpromise.cpp
+
+OTHER_FILES +=
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core-private gui-private qml-private testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+DISTFILES += \
+ data/then-fulfilled-non-callable.qml \
+ data/then-reject-non-callable.qml \
+ data/then-resolve-multiple-then.qml \
+ data/then-resolve-chaining.qml \
+ data/then-reject-chaining.qml \
+ data/promise-resolve-with-value.qml \
+ data/promise-resolve-with-promise.qml \
+ data/promise-reject-with-value.qml \
+ data/promise-executor-resolve.qml \
+ data/promise-get-length.qml \
+ data/promise-executor-reject.qml \
+ data/promise-reject-catch.qml \
+ data/promise-async-resolve-with-value.qml \
+ data/promise-async-reject-with-value.qml \
+ data/promise-all-resolve.qml \
+ data/promise-all-empty-input.qml \
+ data/promise-resolve-with-array.qml \
+ data/promise-all-reject-reject-is-last.qml \
+ data/promise-all-reject-reject-is-mid.qml \
+ data/promise-race-resolve-1st.qml \
+ data/promise-race-empty-input.qml \
+ data/promise-race-resolve-2nd.qml \
+ data/promise-race-resolve-1st-in-executor-function.qml \
+ data/promise-resolve-is-a-function.qml \
+ data/promise-resolve-function-length.qml \
+ data/promise-all-invoke-then-method.qml \
+ data/promise-resolve-with-empty.qml \
+ data/promise-executor-throw-exception.qml \
+ data/promise-executor-function-extensible.qml \
+ data/promise-all-noniterable-input.qml
diff --git a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
new file mode 100644
index 0000000000..0f4bb5cdcc
--- /dev/null
+++ b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QString>
+#include <QtTest>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QDebug>
+#include <QScopedPointer>
+#include "../../shared/util.h"
+
+class tst_qqmlpromise : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_qqmlpromise() {}
+
+private slots:
+ void promise_all_empty_input();
+ void promise_all_noniterable_input();
+// void promise_all_invoke_then_method();
+ void promise_all_resolve();
+ void promise_all_reject_reject_is_last();
+ void promise_all_reject_reject_is_mid();
+ void promise_get_length();
+ void promise_executor_function_extensible();
+ void promise_executor_reject();
+ void promise_executor_resolve();
+ void promise_executor_throw_exception();
+ void promise_async_resolve_with_value();
+ void promise_async_reject_with_value();
+ void promise_resolve_with_value();
+ void promise_resolve_function_length();
+ void promise_resolve_is_a_function();
+ void promise_resolve_with_array();
+ void promise_resolve_with_empty();
+ void promise_resolve_with_promise();
+ void promise_race_empty_input();
+ void promise_race_resolve_1st_in_executor_function();
+ void promise_race_resolve_1st();
+ void promise_race_resolve_2nd();
+ void promise_reject_with_value();
+ void promise_reject_catch();
+ void then_resolve_chaining();
+ void then_reject_chaining();
+ void then_fulfilled_non_callable();
+ void then_reject_non_callable();
+ void then_resolve_multiple_then();
+
+private:
+ void execute_test(QString testName);
+};
+
+void tst_qqmlpromise::promise_all_empty_input()
+{
+ execute_test("promise-all-empty-input.qml");
+}
+
+void tst_qqmlpromise::promise_all_noniterable_input()
+{
+ execute_test("promise-all-noniterable-input.qml");
+}
+
+// TODO: Fix the test
+//void tst_qqmlpromise::promise_all_invoke_then_method()
+//{
+// execute_test("promise-all-invoke-then-method.qml");
+//}
+
+void tst_qqmlpromise::promise_all_resolve()
+{
+ execute_test("promise-all-resolve.qml");
+}
+
+void tst_qqmlpromise::promise_all_reject_reject_is_last()
+{
+ execute_test("promise-all-reject-reject-is-last.qml");
+}
+
+void tst_qqmlpromise::promise_all_reject_reject_is_mid()
+{
+ execute_test("promise-all-reject-reject-is-mid.qml");
+}
+
+void tst_qqmlpromise::promise_get_length()
+{
+ execute_test("promise-get-length.qml");
+}
+
+void tst_qqmlpromise::promise_executor_resolve()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("promise-executor-resolve.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasExecutorCalled").toBool(), true);
+ QTRY_COMPARE(object->property("wasPromiseResolved").toBool(), true);
+ // TODO: now "object" type is returned. fix
+ // QCOMPARE(object->property("wasPromiseTypeReturnedByThen").toBool(), true);
+ QTRY_COMPARE(object->property("wasResolutionForwardedCorrectly").toBool(), true);
+ QTRY_COMPARE(object->property("wasNewPromiseObjectCreatedByThen").toBool(), true);
+}
+
+void tst_qqmlpromise::promise_executor_throw_exception()
+{
+ execute_test("promise-executor-throw-exception.qml");
+}
+
+void tst_qqmlpromise::promise_async_resolve_with_value()
+{
+ execute_test("promise-async-resolve-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_async_reject_with_value()
+{
+ execute_test("promise-async-reject-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_value()
+{
+ execute_test("promise-resolve-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_function_length()
+{
+ execute_test("promise-resolve-function-length.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_is_a_function()
+{
+ execute_test("promise-resolve-is-a-function.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_array()
+{
+ execute_test("promise-resolve-with-array.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_empty()
+{
+ execute_test("promise-resolve-with-empty.qml");
+}
+
+void tst_qqmlpromise::promise_resolve_with_promise()
+{
+ execute_test("promise-resolve-with-promise.qml");
+}
+
+void tst_qqmlpromise::promise_race_empty_input()
+{
+ execute_test("promise-race-empty-input.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_1st_in_executor_function()
+{
+ execute_test("promise-race-resolve-1st-in-executor-function.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_1st()
+{
+ execute_test("promise-race-resolve-1st.qml");
+}
+
+void tst_qqmlpromise::promise_race_resolve_2nd()
+{
+ execute_test("promise-race-resolve-2nd.qml");
+}
+
+void tst_qqmlpromise::promise_reject_with_value()
+{
+ execute_test("promise-reject-with-value.qml");
+}
+
+void tst_qqmlpromise::promise_reject_catch()
+{
+ execute_test("promise-reject-catch.qml");
+}
+
+void tst_qqmlpromise::promise_executor_function_extensible()
+{
+ execute_test("promise-executor-function-extensible.qml");
+}
+
+void tst_qqmlpromise::promise_executor_reject()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("promise-executor-reject.qml"));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasExecutorCalled").toBool(), true);
+ QTRY_COMPARE(object->property("wasPromiseRejected").toBool(), true);
+ // TODO: now "object" type is returned. fix
+ // QCOMPARE(object->property("wasPromiseTypeReturnedByThen").toBool(), true);
+ QTRY_COMPARE(object->property("wasResolutionForwardedCorrectly").toBool(), true);
+}
+
+void tst_qqmlpromise::then_resolve_chaining()
+{
+ execute_test("then-resolve-chaining.qml");
+}
+
+void tst_qqmlpromise::then_reject_chaining()
+{
+ execute_test("then-reject-chaining.qml");
+}
+
+void tst_qqmlpromise::then_fulfilled_non_callable()
+{
+ execute_test("then-fulfilled-non-callable.qml");
+}
+
+void tst_qqmlpromise::then_reject_non_callable()
+{
+ execute_test("then-reject-non-callable.qml");
+}
+
+void tst_qqmlpromise::then_resolve_multiple_then()
+{
+ execute_test("then-resolve-multiple-then.qml");
+}
+
+void tst_qqmlpromise::execute_test(QString testName)
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl(testName));
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
+ component.completeCreate();
+
+ QTRY_COMPARE(object->property("wasTestSuccessful").toBool(), true);
+}
+
+
+QTEST_MAIN(tst_qqmlpromise)
+
+#include "tst_qqmlpromise.moc"
diff --git a/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml b/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml
new file mode 100644
index 0000000000..8cbd928f36
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ property alias testType: testType
+
+ Rectangle {
+ id: testType
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 84a1bd9cc5..27e06c6f67 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -44,7 +44,7 @@ class MyQmlObject : public QObject
Q_OBJECT
Q_PROPERTY(QPoint pointProperty MEMBER m_point)
public:
- MyQmlObject(QObject *parent = 0) : QObject(parent) {}
+ MyQmlObject(QObject *parent = nullptr) : QObject(parent) {}
private:
QPoint m_point;
@@ -56,7 +56,7 @@ class MyQObject : public QObject
{
Q_OBJECT
public:
- MyQObject(QObject *parent = 0) : QObject(parent), m_i(0) {}
+ MyQObject(QObject *parent = nullptr) : QObject(parent), m_i(0) {}
int inc() { return ++m_i; }
@@ -143,6 +143,7 @@ private slots:
void registeredCompositeTypeProperty();
void deeplyNestedObject();
void readOnlyDynamicProperties();
+ void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem();
void floatToStringPrecision_data();
void floatToStringPrecision();
@@ -158,21 +159,21 @@ void tst_qqmlproperty::qmlmetaproperty()
QObject *obj = new QObject;
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QCOMPARE(prop.name(), QString());
QCOMPARE(prop.read(), QVariant());
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -183,10 +184,10 @@ void tst_qqmlproperty::qmlmetaproperty()
QCOMPARE(prop.isResettable(), false);
QCOMPARE(prop.isSignalProperty(), false);
QCOMPARE(prop.isValid(), false);
- QCOMPARE(prop.object(), (QObject *)0);
+ QCOMPARE(prop.object(), (QObject *)nullptr);
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
QVERIFY(!prop.property().name());
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
@@ -333,7 +334,7 @@ class PropertyObject : public QObject
Q_CLASSINFO("DefaultProperty", "defaultProperty")
public:
- PropertyObject() : m_resetProperty(9), m_qObject(0), m_stringProperty("foo") {}
+ PropertyObject() : m_resetProperty(9), m_qObject(nullptr), m_stringProperty("foo") {}
int defaultProperty() { return 10; }
QRect rectProperty() { return QRect(10, 10, 1, 209); }
@@ -400,11 +401,11 @@ void tst_qqmlproperty::qmlmetaproperty_object()
{
QQmlProperty prop(&object);
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -413,10 +414,10 @@ void tst_qqmlproperty::qmlmetaproperty_object()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -427,10 +428,10 @@ void tst_qqmlproperty::qmlmetaproperty_object()
QCOMPARE(prop.isResettable(), false);
QCOMPARE(prop.isSignalProperty(), false);
QCOMPARE(prop.isValid(), false);
- QCOMPARE(prop.object(), (QObject *)0);
+ QCOMPARE(prop.object(), (QObject *)nullptr);
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
QVERIFY(!prop.property().name());
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
@@ -448,12 +449,12 @@ void tst_qqmlproperty::qmlmetaproperty_object()
{
QQmlProperty prop(&dobject);
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -462,10 +463,10 @@ void tst_qqmlproperty::qmlmetaproperty_object()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), true);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -505,11 +506,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&object, QString("defaultProperty"));
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -518,10 +519,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -532,10 +533,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.isResettable(), false);
QCOMPARE(prop.isSignalProperty(), false);
QCOMPARE(prop.isValid(), false);
- QCOMPARE(prop.object(), (QObject *)0);
+ QCOMPARE(prop.object(), (QObject *)nullptr);
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
QVERIFY(!prop.property().name());
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
@@ -553,12 +554,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("defaultProperty"));
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -567,10 +568,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), true);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -604,12 +605,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("onClicked"));
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -618,10 +619,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.write(QVariant("Hello")), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()"));
@@ -635,8 +636,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
- QCOMPARE(prop.property().name(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
+ QCOMPARE(prop.property().name(), (const char *)nullptr);
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
QVERIFY(binding->ref == 1);
@@ -654,12 +655,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
{
QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"));
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -668,10 +669,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.write(QVariant("Hello")), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
@@ -685,8 +686,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
- QCOMPARE(prop.property().name(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
+ QCOMPARE(prop.property().name(), (const char *)nullptr);
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
QVERIFY(binding->ref == 1);
@@ -710,11 +711,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
{
QQmlProperty prop(&object, engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -723,10 +724,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -737,10 +738,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
QCOMPARE(prop.isResettable(), false);
QCOMPARE(prop.isSignalProperty(), false);
QCOMPARE(prop.isValid(), false);
- QCOMPARE(prop.object(), (QObject *)0);
+ QCOMPARE(prop.object(), (QObject *)nullptr);
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
QVERIFY(!prop.property().name());
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
@@ -758,12 +759,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
{
QQmlProperty prop(&dobject, engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -772,10 +773,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), true);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -815,11 +816,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -828,10 +829,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -842,10 +843,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.isResettable(), false);
QCOMPARE(prop.isSignalProperty(), false);
QCOMPARE(prop.isValid(), false);
- QCOMPARE(prop.object(), (QObject *)0);
+ QCOMPARE(prop.object(), (QObject *)nullptr);
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
QVERIFY(!prop.property().name());
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
@@ -863,12 +864,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -877,10 +878,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.write(QVariant()), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), true);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QVERIFY(!prop.method().isValid());
@@ -914,12 +915,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -928,10 +929,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.write(QVariant("Hello")), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()"));
@@ -945,8 +946,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
- QCOMPARE(prop.property().name(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
+ QCOMPARE(prop.property().name(), (const char *)nullptr);
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
QVERIFY(binding->ref == 1);
@@ -964,12 +965,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
{
QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext());
- QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, QQmlContextData::get(engine.rootContext())));
+ QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), nullptr, QQmlContextData::get(engine.rootContext())));
static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
QVERIFY(binding);
- QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1);
+ QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1);
QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr);
- QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
+ QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted());
QObject *obj = new QObject;
@@ -978,10 +979,10 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.write(QVariant("Hello")), false);
QCOMPARE(prop.hasNotifySignal(), false);
QCOMPARE(prop.needsNotifySignal(), false);
- QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
QCOMPARE(prop.connectNotifySignal(obj, 0), false);
- QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
+ QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
QCOMPARE(prop.connectNotifySignal(obj, -1), false);
QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
@@ -995,8 +996,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
QCOMPARE(prop.propertyType(), 0);
- QCOMPARE(prop.propertyTypeName(), (const char *)0);
- QCOMPARE(prop.property().name(), (const char *)0);
+ QCOMPARE(prop.propertyTypeName(), (const char *)nullptr);
+ QCOMPARE(prop.property().name(), (const char *)nullptr);
QVERIFY(!QQmlPropertyPrivate::binding(prop));
QQmlPropertyPrivate::setBinding(prop, binding.data());
QVERIFY(binding->ref == 1);
@@ -1062,7 +1063,7 @@ void tst_qqmlproperty::name()
}
{
- QQmlProperty p(0, "foo");
+ QQmlProperty p(nullptr, "foo");
QCOMPARE(p.name(), QString());
}
@@ -1150,8 +1151,8 @@ void tst_qqmlproperty::read()
QQmlProperty p(&o, "onClicked");
QCOMPARE(p.read(), QVariant());
- QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1));
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
QCOMPARE(p.read(), QVariant());
}
@@ -1162,8 +1163,8 @@ void tst_qqmlproperty::read()
QQmlProperty p(&o, "onPropertyWithNotifyChanged");
QCOMPARE(p.read(), QVariant());
- QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1));
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
QCOMPARE(p.read(), QVariant());
}
@@ -1213,7 +1214,7 @@ void tst_qqmlproperty::read()
{
QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "test", &engine);
@@ -1228,7 +1229,7 @@ void tst_qqmlproperty::read()
{ // static
QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant v = QQmlProperty::read(object, "test", &engine);
QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
@@ -1241,7 +1242,7 @@ void tst_qqmlproperty::read()
QQmlComponent component(&engine);
component.setData("import Test 1.0\nMyContainer { }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
QCOMPARE(p.read(), QVariant(13));
@@ -1251,7 +1252,7 @@ void tst_qqmlproperty::read()
QQmlComponent component(&engine);
component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
QCOMPARE(p.read(), QVariant(10));
@@ -1261,7 +1262,7 @@ void tst_qqmlproperty::read()
QQmlComponent component(&engine);
component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
QCOMPARE(p.read(), QVariant(10));
@@ -1271,7 +1272,7 @@ void tst_qqmlproperty::read()
QQmlComponent component(&engine);
component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(QQmlProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10));
delete object;
@@ -1341,12 +1342,12 @@ void tst_qqmlproperty::write()
QQmlProperty p(&o, "onClicked");
QCOMPARE(p.write(QVariant("console.log(1921)")), false);
- QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1));
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
QCOMPARE(p.write(QVariant("console.log(1921)")), false);
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
}
// Automatic signal property
@@ -1355,12 +1356,12 @@ void tst_qqmlproperty::write()
QQmlProperty p(&o, "onPropertyWithNotifyChanged");
QCOMPARE(p.write(QVariant("console.log(1921)")), false);
- QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1));
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(engine.rootContext()), nullptr, QLatin1String("null"), QString(), -1, -1));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
QCOMPARE(p.write(QVariant("console.log(1921)")), false);
- QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
+ QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p));
}
// Value-type property
@@ -1436,7 +1437,7 @@ void tst_qqmlproperty::write()
QQmlComponent component(&engine);
component.setData("import Test 1.0\nPropertyObject { stringProperty: constQChar }", QUrl());
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
if (obj) {
QQmlProperty stringProperty(obj, "stringProperty");
QCOMPARE(stringProperty.read(), QVariant(QString(obj->constQChar())));
@@ -1476,7 +1477,7 @@ void tst_qqmlproperty::write()
QQmlComponent component(&engine);
component.setData("import Test 1.0\nMyContainer { }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
p.write(QVariant(99));
@@ -1487,7 +1488,7 @@ void tst_qqmlproperty::write()
QQmlComponent component(&engine);
component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QQmlProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
p.write(QVariant(99));
@@ -1498,7 +1499,7 @@ void tst_qqmlproperty::write()
{
PropertyObject o;
QQmlProperty p(&o, QString("qObject"));
- QCOMPARE(o.qObject(), (QObject*)0);
+ QCOMPARE(o.qObject(), (QObject*)nullptr);
QObject *newObject = new MyQObject(this);
QCOMPARE(p.write(QVariant::fromValue(newObject)), true);
QCOMPARE(o.qObject(), newObject);
@@ -1515,7 +1516,7 @@ void tst_qqmlproperty::write()
QQmlEngine engine;
PropertyObject o;
QQmlProperty p(&o, QString("qObject"), &engine);
- QCOMPARE(o.qObject(), (QObject*)0);
+ QCOMPARE(o.qObject(), (QObject*)nullptr);
QObject *newObject = new MyQObject(this);
QCOMPARE(p.write(QVariant::fromValue(newObject)), true);
QCOMPARE(o.qObject(), newObject);
@@ -1617,7 +1618,7 @@ void tst_qqmlproperty::writeObjectToList()
QQmlComponent containerComponent(&engine);
containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
- QVERIFY(container != 0);
+ QVERIFY(container != nullptr);
QQmlListReference list(container, "children");
QCOMPARE(list.count(), 1);
@@ -1633,7 +1634,7 @@ void tst_qqmlproperty::writeListToList()
QQmlComponent containerComponent(&engine);
containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
- QVERIFY(container != 0);
+ QVERIFY(container != nullptr);
QQmlListReference list(container, "children");
QCOMPARE(list.count(), 1);
@@ -1817,7 +1818,7 @@ void tst_qqmlproperty::crashOnValueProperty()
component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }", QUrl());
PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QQmlProperty p(obj, "wrectProperty.x", qmlContext(obj));
QCOMPARE(p.name(), QString("wrectProperty.x"));
@@ -1826,7 +1827,7 @@ void tst_qqmlproperty::crashOnValueProperty()
//don't crash once the engine is deleted
delete engine;
- engine = 0;
+ engine = nullptr;
QCOMPARE(p.propertyTypeName(), "int");
QCOMPARE(p.read(), QVariant(10));
@@ -1852,7 +1853,7 @@ void tst_qqmlproperty::aliasPropertyBindings()
QQmlComponent component(&engine, testFileUrl(file));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// the object where realProperty lives
QObject *realPropertyObject = object;
@@ -1871,8 +1872,8 @@ void tst_qqmlproperty::aliasPropertyBindings()
QQmlProperty aliasProperty(object, QLatin1String("aliasProperty"));
// Check there is a binding on these two properties
- QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
- QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
+ QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr);
+ QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr);
// Check that its the same binding on these two properties
QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
@@ -1881,8 +1882,8 @@ void tst_qqmlproperty::aliasPropertyBindings()
// Change the binding
object->setProperty("state", QString("switch"));
- QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
- QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
+ QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr);
+ QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr);
QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
QQmlPropertyPrivate::binding(aliasProperty));
@@ -1903,8 +1904,8 @@ void tst_qqmlproperty::aliasPropertyBindings()
// Revert
object->setProperty("state", QString(""));
- QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
- QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
+ QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr);
+ QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr);
QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
QQmlPropertyPrivate::binding(aliasProperty));
@@ -1946,7 +1947,7 @@ void tst_qqmlproperty::copy()
QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal);
QCOMPARE(p2.propertyType(), (int)QVariant::Int);
- delete property; property = 0;
+ delete property; property = nullptr;
QCOMPARE(p1.name(), QString("defaultProperty"));
QCOMPARE(p1.read(), QVariant(10));
@@ -1967,9 +1968,9 @@ void tst_qqmlproperty::noContext()
QQmlComponent compB(&engine, testFileUrl("NoContextTypeB.qml"));
QObject *a = compA.create();
- QVERIFY(a != 0);
+ QVERIFY(a != nullptr);
QObject *b = compB.create();
- QVERIFY(b != 0);
+ QVERIFY(b != nullptr);
QVERIFY(QQmlProperty::write(b, "myTypeA", QVariant::fromValue(a), &engine));
@@ -2006,15 +2007,15 @@ void tst_qqmlproperty::warnOnInvalidBinding()
QString expectedWarning;
// V4 error message for property-to-property binding
- expectedWarning = testUrl.toString() + QString::fromLatin1(":6:36: Unable to assign QQuickText to QQuickRectangle");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":6:5: Unable to assign QQuickText to QQuickRectangle");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
// V8 error message for function-to-property binding
- expectedWarning = testUrl.toString() + QString::fromLatin1(":7:36: Unable to assign QQuickText to QQuickRectangle");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":7:5: Unable to assign QQuickText to QQuickRectangle");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
// V8 error message for invalid binding to anchor
- expectedWarning = testUrl.toString() + QString::fromLatin1(":14:33: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":14:9: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
QQmlComponent component(&engine, testUrl);
@@ -2037,7 +2038,7 @@ void tst_qqmlproperty::readOnlyDynamicProperties()
{
QQmlComponent comp(&engine, testFileUrl("readonlyPrimitiveVsVar.qml"));
QObject *obj = comp.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QVERIFY(!obj->metaObject()->property(obj->metaObject()->indexOfProperty("r_var")).isWritable());
QVERIFY(!obj->metaObject()->property(obj->metaObject()->indexOfProperty("r_int")).isWritable());
@@ -2047,6 +2048,17 @@ void tst_qqmlproperty::readOnlyDynamicProperties()
delete obj;
}
+void tst_qqmlproperty::aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem()
+{
+ const QUrl url = testFileUrl("aliasToIdWithMatchingQmlFileName.qml");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, url);
+ QScopedPointer<QObject> root(component.create());
+
+ QQmlProperty property(root.data(), "testType.objectName", QQmlEngine::contextForObject(root.data()));
+ QVERIFY(property.isValid());
+}
+
void tst_qqmlproperty::floatToStringPrecision_data()
{
QTest::addColumn<QString>("propertyName");
@@ -2054,19 +2066,19 @@ void tst_qqmlproperty::floatToStringPrecision_data()
QTest::addColumn<QString>("qtString");
QTest::addColumn<QString>("jsString");
- QTest::newRow("3.4") << "a" << 3.4 << "3.4" << "3.4";
- QTest::newRow("0.035003945") << "b" << 0.035003945 << "0.035003945" << "0.035003945";
- QTest::newRow("0.0000012345") << "c" << 0.0000012345 << "1.2345e-6" << "0.0000012345";
- QTest::newRow("0.00000012345") << "d" << 0.00000012345 << "1.2345e-7" << "1.2345e-7";
- QTest::newRow("1e20") << "e" << 1e20 << "1e+20" << "100000000000000000000";
- QTest::newRow("1e21") << "f" << 1e21 << "1e+21" << "1e+21";
+ QTest::newRow("3.4") << "a" << 3.4 << "3.4" << "3.4";
+ QTest::newRow("0.035003945") << "b" << 0.035003945 << "0.035003945" << "0.035003945";
+ QTest::newRow("0.0000012345") << "c" << 0.0000012345 << "1.2345e-06" << "0.0000012345";
+ QTest::newRow("0.00000012345") << "d" << 0.00000012345 << "1.2345e-07" << "1.2345e-7";
+ QTest::newRow("1e20") << "e" << 1e20 << "1e+20" << "100000000000000000000";
+ QTest::newRow("1e21") << "f" << 1e21 << "1e+21" << "1e+21";
}
void tst_qqmlproperty::floatToStringPrecision()
{
QQmlComponent comp(&engine, testFileUrl("floatToStringPrecision.qml"));
- QObject *obj = comp.create();
- QVERIFY(obj != 0);
+ QScopedPointer<QObject> obj(comp.create());
+ QVERIFY(obj != nullptr);
QFETCH(QString, propertyName);
QFETCH(double, number);
@@ -2084,8 +2096,6 @@ void tst_qqmlproperty::floatToStringPrecision()
QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1();
QCOMPARE(obj->property(name2).toDouble(), number);
QCOMPARE(obj->property(name2).toString(), jsString);
-
- delete obj;
}
void tst_qqmlproperty::initTestCase()
diff --git a/tests/auto/qml/qqmlpropertycache/data/foreignEnums.qml b/tests/auto/qml/qqmlpropertycache/data/foreignEnums.qml
new file mode 100644
index 0000000000..b7492e507e
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertycache/data/foreignEnums.qml
@@ -0,0 +1,17 @@
+import QtQml 2.2
+import example 1.0
+
+QtObject {
+ Component.onCompleted: {
+ var opt1 = MyEnum.Option1A | MyEnum.Option1D // 0x09
+ mydata.opt1 = opt1;
+ mydata.setOpt1(opt1);
+ mydata.setOption1(opt1);
+
+ var opt2 = mydata.opt2;
+ opt2 = (opt2 === MyEnum.Short8 ? MyEnum.Short16 : MyEnum.Short0);
+ mydata.opt2 = opt2;
+ mydata.setOpt2(opt2);
+ mydata.setOption2(opt2);
+ }
+}
diff --git a/tests/auto/qml/qqmlpropertycache/data/passQGadget.qml b/tests/auto/qml/qqmlpropertycache/data/passQGadget.qml
new file mode 100644
index 0000000000..86fdd920ed
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertycache/data/passQGadget.qml
@@ -0,0 +1,12 @@
+import QtQml 2.2
+
+QtObject {
+ property var result;
+
+ property Connections connections: Connections {
+ target: emitter
+ onEmitGadget: function(gadget) {
+ result = gadget.someProperty;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlpropertycache/qqmlpropertycache.pro b/tests/auto/qml/qqmlpropertycache/qqmlpropertycache.pro
index 9a04c899fe..26d41bbdbf 100644
--- a/tests/auto/qml/qqmlpropertycache/qqmlpropertycache.pro
+++ b/tests/auto/qml/qqmlpropertycache/qqmlpropertycache.pro
@@ -4,4 +4,8 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmlpropertycache.cpp
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
QT += core-private gui-private qml-private testlib
diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
index 824fe445c0..02b5302a45 100644
--- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
+++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
@@ -29,12 +29,14 @@
#include <qtest.h>
#include <private/qqmlpropertycache_p.h>
#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"
-class tst_qqmlpropertycache : public QObject
+class tst_qqmlpropertycache : public QQmlDataTest
{
Q_OBJECT
public:
@@ -43,10 +45,13 @@ public:
private slots:
void properties();
void propertiesDerived();
+ void revisionedProperties();
void methods();
void methodsDerived();
void signalHandlers();
void signalHandlersDerived();
+ void passForeignEnums();
+ void passQGadget();
void metaObjectSize_data();
void metaObjectSize();
void metaObjectChecksum();
@@ -61,7 +66,7 @@ class BaseObject : public QObject
Q_PROPERTY(int propertyA READ propertyA NOTIFY propertyAChanged)
Q_PROPERTY(QString propertyB READ propertyB NOTIFY propertyBChanged)
public:
- BaseObject(QObject *parent = 0) : QObject(parent) {}
+ BaseObject(QObject *parent = nullptr) : QObject(parent) {}
int propertyA() const { return 0; }
QString propertyB() const { return QString(); }
@@ -80,11 +85,13 @@ class DerivedObject : public BaseObject
Q_OBJECT
Q_PROPERTY(int propertyC READ propertyC NOTIFY propertyCChanged)
Q_PROPERTY(QString propertyD READ propertyD NOTIFY propertyDChanged)
+ Q_PROPERTY(int propertyE READ propertyE NOTIFY propertyEChanged REVISION 1)
public:
- DerivedObject(QObject *parent = 0) : BaseObject(parent) {}
+ DerivedObject(QObject *parent = nullptr) : BaseObject(parent) {}
int propertyC() const { return 0; }
QString propertyD() const { return QString(); }
+ int propertyE() const { return 0; }
public Q_SLOTS:
void slotB() {}
@@ -92,22 +99,22 @@ public Q_SLOTS:
Q_SIGNALS:
void propertyCChanged();
void propertyDChanged();
+ Q_REVISION(1) void propertyEChanged();
void signalB();
};
-QQmlPropertyData *cacheProperty(QQmlPropertyCache *cache, const char *name)
+QQmlPropertyData *cacheProperty(const QQmlRefPointer<QQmlPropertyCache> &cache, const char *name)
{
- return cache->property(QLatin1String(name), 0, 0);
+ return cache->property(QLatin1String(name), nullptr, nullptr);
}
void tst_qqmlpropertycache::properties()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
+ QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
QQmlPropertyData *data;
QVERIFY((data = cacheProperty(cache, "propertyA")));
@@ -126,11 +133,10 @@ void tst_qqmlpropertycache::properties()
void tst_qqmlpropertycache::propertiesDerived()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(v4, &BaseObject::staticMetaObject));
+ QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
@@ -147,14 +153,30 @@ void tst_qqmlpropertycache::propertiesDerived()
QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD"));
}
+void tst_qqmlpropertycache::revisionedProperties()
+{
+ // Check that if you create a QQmlPropertyCache from a QMetaObject together
+ // with an explicit revision, the cache will then, and only then, report a
+ // property with a matching revision as available.
+ DerivedObject object;
+ const QMetaObject *metaObject = object.metaObject();
+
+ QQmlRefPointer<QQmlPropertyCache> cacheWithoutVersion(new QQmlPropertyCache(metaObject));
+ QQmlRefPointer<QQmlPropertyCache> cacheWithVersion(new QQmlPropertyCache(metaObject, 1));
+ QQmlPropertyData *data;
+
+ QVERIFY((data = cacheProperty(cacheWithoutVersion, "propertyE")));
+ QCOMPARE(cacheWithoutVersion->isAllowedInRevision(data), false);
+ QCOMPARE(cacheWithVersion->isAllowedInRevision(data), true);
+}
+
void tst_qqmlpropertycache::methods()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
+ QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
QQmlPropertyData *data;
QVERIFY((data = cacheProperty(cache, "slotA")));
@@ -185,11 +207,10 @@ void tst_qqmlpropertycache::methods()
void tst_qqmlpropertycache::methodsDerived()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(v4, &BaseObject::staticMetaObject));
+ QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
@@ -221,11 +242,10 @@ void tst_qqmlpropertycache::methodsDerived()
void tst_qqmlpropertycache::signalHandlers()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject));
+ QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
QQmlPropertyData *data;
QVERIFY((data = cacheProperty(cache, "onSignalA")));
@@ -250,11 +270,10 @@ void tst_qqmlpropertycache::signalHandlers()
void tst_qqmlpropertycache::signalHandlersDerived()
{
QQmlEngine engine;
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
DerivedObject object;
const QMetaObject *metaObject = object.metaObject();
- QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(v4, &BaseObject::staticMetaObject));
+ QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
QQmlPropertyData *data;
@@ -277,6 +296,132 @@ void tst_qqmlpropertycache::signalHandlersDerived()
QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
}
+class MyEnum : public QObject
+ {
+ Q_OBJECT
+ public:
+ enum Option1Flag {
+ Option10 = 0,
+ Option1A = 1,
+ Option1B = 2,
+ Option1C = 4,
+ Option1D = 8,
+ Option1E = 16,
+ Option1F = 32,
+ Option1AD = Option1A | Option1D,
+ };
+ Q_DECLARE_FLAGS(Option1, Option1Flag)
+ Q_FLAG(Option1)
+
+ enum ShortEnum: quint16 {
+ Short0 = 0,
+ Short8 = 0xff,
+ Short16 = 0xffff
+ };
+ Q_ENUM(ShortEnum);
+};
+
+class MyData : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(MyEnum::Option1 opt1 READ opt1 WRITE setOpt1 NOTIFY opt1Changed)
+ Q_PROPERTY(MyEnum::ShortEnum opt2 READ opt2 WRITE setOpt2 NOTIFY opt2Changed)
+public:
+ MyEnum::Option1 opt1() const { return m_opt1; }
+ MyEnum::ShortEnum opt2() const { return m_opt2; }
+
+signals:
+ void opt1Changed(MyEnum::Option1 opt1);
+ void opt2Changed(MyEnum::ShortEnum opt2);
+
+public slots:
+ void setOpt1(MyEnum::Option1 opt1)
+ {
+ QCOMPARE(opt1, MyEnum::Option1AD);
+ if (opt1 != m_opt1) {
+ m_opt1 = opt1;
+ emit opt1Changed(opt1);
+ }
+ }
+
+ void setOpt2(MyEnum::ShortEnum opt2)
+ {
+ QCOMPARE(opt2, MyEnum::Short16);
+ if (opt2 != m_opt2) {
+ m_opt2 = opt2;
+ emit opt2Changed(opt2);
+ }
+ }
+
+ void setOption1(MyEnum::Option1 opt1) { setOpt1(opt1); }
+ void setOption2(MyEnum::ShortEnum opt2) { setOpt2(opt2); }
+
+private:
+ MyEnum::Option1 m_opt1 = MyEnum::Option10;
+ MyEnum::ShortEnum m_opt2 = MyEnum::Short8;
+};
+
+void tst_qqmlpropertycache::passForeignEnums()
+{
+ qmlRegisterType<MyEnum>("example", 1, 0, "MyEnum");
+ qmlRegisterType<MyData>("example", 1, 0, "MyData");
+
+ MyEnum myenum;
+ MyData data;
+
+ engine.rootContext()->setContextProperty("myenum", &myenum);
+ engine.rootContext()->setContextProperty("mydata", &data);
+
+ QQmlComponent component(&engine, testFile("foreignEnums.qml"));
+ QVERIFY(component.isReady());
+
+ QScopedPointer<QObject> obj(component.create(engine.rootContext()));
+ QVERIFY(!obj.isNull());
+ QCOMPARE(data.opt1(), MyEnum::Option1AD);
+ QCOMPARE(data.opt2(), MyEnum::Short16);
+}
+
+Q_DECLARE_METATYPE(MyEnum::Option1)
+Q_DECLARE_METATYPE(MyEnum::ShortEnum)
+
+QT_BEGIN_NAMESPACE
+class SimpleGadget
+{
+ Q_GADGET
+ Q_PROPERTY(bool someProperty READ someProperty)
+public:
+ bool someProperty() const { return true; }
+};
+
+// Avoids NeedsCreation and NeedsDestruction flags
+Q_DECLARE_TYPEINFO(SimpleGadget, Q_PRIMITIVE_TYPE);
+QT_END_NAMESPACE
+
+class GadgetEmitter : public QObject
+{
+ Q_OBJECT
+signals:
+ void emitGadget(SimpleGadget);
+};
+
+void tst_qqmlpropertycache::passQGadget()
+{
+ qRegisterMetaType<SimpleGadget>();
+
+ GadgetEmitter emitter;
+ engine.rootContext()->setContextProperty("emitter", &emitter);
+ QQmlComponent component(&engine, testFile("passQGadget.qml"));
+ QVERIFY(component.isReady());
+
+ QScopedPointer<QObject> obj(component.create(engine.rootContext()));
+ QVariant before = obj->property("result");
+ QVERIFY(before.isNull());
+ emit emitter.emitGadget(SimpleGadget());
+ QVariant after = obj->property("result");
+ QCOMPARE(QMetaType::Type(after.type()), QMetaType::Bool);
+ QVERIFY(after.toBool());
+}
+
class TestClass : public QObject
{
Q_OBJECT
diff --git a/tests/auto/qml/qqmlpropertymap/data/PropertyMapSubType.qml b/tests/auto/qml/qqmlpropertymap/data/PropertyMapSubType.qml
new file mode 100644
index 0000000000..90ff179408
--- /dev/null
+++ b/tests/auto/qml/qqmlpropertymap/data/PropertyMapSubType.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+import Test 1.0
+
+SimplePropertyMap {
+ Component.onCompleted: {
+ console.log("expected output")
+ newProperty = 42
+ }
+}
diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
index b8ea98df2b..237b65679e 100644
--- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
+++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
@@ -35,7 +35,7 @@
#include <QSignalSpy>
#include <QDebug>
-class tst_QQmlPropertyMap : public QObject
+class tst_QQmlPropertyMap : public QQmlDataTest
{
Q_OBJECT
public:
@@ -61,6 +61,7 @@ private slots:
void disallowExtending();
void QTBUG_35906();
void QTBUG_48136();
+ void lookupsInSubTypes();
};
class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus
@@ -71,8 +72,7 @@ class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus
Q_PROPERTY(int someFixedProperty READ someFixedProperty WRITE setSomeFixedProperty NOTIFY someFixedPropertyChanged)
public:
LazyPropertyMap()
- : QQmlPropertyMap(this, /*parent*/0)
- , value(0)
+ : QQmlPropertyMap(this, /*parent*/nullptr)
{}
virtual void classBegin() {}
@@ -87,12 +87,21 @@ signals:
void someFixedPropertyChanged();
private:
- int value;
+ int value = 0;
+};
+
+class SimplePropertyMap: public QQmlPropertyMap
+{
+ Q_OBJECT
+public:
+ SimplePropertyMap() : QQmlPropertyMap(this, nullptr) {}
};
void tst_QQmlPropertyMap::initTestCase()
{
+ QQmlDataTest::initTestCase();
qmlRegisterType<LazyPropertyMap>("QTBUG_35233", 1, 0, "LazyPropertyMap");
+ qmlRegisterType<SimplePropertyMap>("Test", 1, 0, "SimplePropertyMap");
}
void tst_QQmlPropertyMap::insert()
@@ -313,7 +322,7 @@ class MyEnhancedPropertyMap : public QQmlPropertyMap
{
Q_OBJECT
public:
- MyEnhancedPropertyMap() : QQmlPropertyMap(this, 0), m_testSlotCalled(false) {}
+ MyEnhancedPropertyMap() : QQmlPropertyMap(this, nullptr) {}
bool testSlotCalled() const { return m_testSlotCalled; }
signals:
@@ -323,7 +332,7 @@ public slots:
void testSlot() { m_testSlotCalled = true; }
private:
- bool m_testSlotCalled;
+ bool m_testSlotCalled = false;
};
void tst_QQmlPropertyMap::metaObjectAccessibility()
@@ -497,6 +506,16 @@ void tst_QQmlPropertyMap::QTBUG_48136()
QCOMPARE(valueChangedSpy.count(), 1);
}
+void tst_QQmlPropertyMap::lookupsInSubTypes()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("PropertyMapSubType.qml"));
+ QTest::ignoreMessage(QtDebugMsg, "expected output");
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QCOMPARE(object->property("newProperty").toInt(), 42);
+}
+
QTEST_MAIN(tst_QQmlPropertyMap)
#include "tst_qqmlpropertymap.moc"
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index 0576650d01..2d8115e867 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -168,7 +168,7 @@ void tst_qqmlqt::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toInt(), (int)Qt::Key_Escape);
QCOMPARE(object->property("test2").toInt(), (int)Qt::DescendingOrder);
@@ -188,7 +188,7 @@ void tst_qqmlqt::rgba()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0, 0, 0.8));
@@ -211,7 +211,7 @@ void tst_qqmlqt::hsla()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromHslF(1, 0, 0, 0.8));
QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromHslF(1, 0.5, 0.3, 1));
@@ -233,7 +233,7 @@ void tst_qqmlqt::hsva()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromHsvF(1, 0, 0, 0.8));
QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromHsvF(1, 0.5, 0.3, 1));
@@ -261,7 +261,7 @@ void tst_qqmlqt::colorEqual()
QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":35: Error: Qt.colorEqual(): Invalid color name"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1a").toBool(), false);
QCOMPARE(object->property("test1b").toBool(), false);
@@ -338,7 +338,7 @@ void tst_qqmlqt::rect()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QRectF>(object->property("test1")), QRectF(10, 13, 100, 109));
QCOMPARE(qvariant_cast<QRectF>(object->property("test2")), QRectF(-10, 13, 100, 109.6));
@@ -359,7 +359,7 @@ void tst_qqmlqt::point()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QPointF>(object->property("test1")), QPointF(19, 34));
QCOMPARE(qvariant_cast<QPointF>(object->property("test2")), QPointF(-3, 109.2));
@@ -379,7 +379,7 @@ void tst_qqmlqt::size()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QSizeF>(object->property("test1")), QSizeF(19, 34));
QCOMPARE(qvariant_cast<QSizeF>(object->property("test2")), QSizeF(3, 109.2));
@@ -400,7 +400,7 @@ void tst_qqmlqt::vector2d()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QVector2D>(object->property("test1")), QVector2D(1, 0.9f));
QCOMPARE(qvariant_cast<QVector2D>(object->property("test2")), QVector2D(102, -982.1f));
@@ -420,7 +420,7 @@ void tst_qqmlqt::vector3d()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QVector3D>(object->property("test1")), QVector3D(1, 0, 0.9f));
QCOMPARE(qvariant_cast<QVector3D>(object->property("test2")), QVector3D(102, -10, -982.1f));
@@ -440,7 +440,7 @@ void tst_qqmlqt::vector4d()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QVector4D>(object->property("test1")), QVector4D(1, 0, 0.9f, 0.6f));
QCOMPARE(qvariant_cast<QVector4D>(object->property("test2")), QVector4D(102, -10, -982.1f, 10));
@@ -460,7 +460,7 @@ void tst_qqmlqt::quaternion()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QQuaternion>(object->property("test1")), QQuaternion(2, 17, 0.9f, 0.6f));
QCOMPARE(qvariant_cast<QQuaternion>(object->property("test2")), QQuaternion(102, -10, -982.1f, 10));
@@ -482,7 +482,7 @@ void tst_qqmlqt::matrix4x4()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test1")), QMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16));
QCOMPARE(qvariant_cast<QMatrix4x4>(object->property("test2")), QMatrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4));
@@ -503,10 +503,16 @@ void tst_qqmlqt::font()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(qvariant_cast<QFont>(object->property("test1")), QFont("Arial", 22));
- QCOMPARE(qvariant_cast<QFont>(object->property("test2")), QFont("Arial", 20, QFont::DemiBold, true));
+ QVERIFY(object != nullptr);
+
+ QFont f;
+ f.setFamily("Arial");
+ f.setPointSize(22);
+ QCOMPARE(qvariant_cast<QFont>(object->property("test1")), f);
+ f.setPointSize(20);
+ f.setWeight(QFont::DemiBold);
+ f.setItalic(true);
+ QCOMPARE(qvariant_cast<QFont>(object->property("test2")), f);
QCOMPARE(qvariant_cast<QFont>(object->property("test3")), QFont());
QCOMPARE(qvariant_cast<QFont>(object->property("test4")), QFont());
@@ -523,7 +529,7 @@ void tst_qqmlqt::lighter()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0.8, 0.3).lighter());
QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor());
@@ -545,7 +551,7 @@ void tst_qqmlqt::darker()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(1, 0.8, 0.3).darker());
QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor());
@@ -568,7 +574,7 @@ void tst_qqmlqt::tint()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QColor>(object->property("test1")), QColor::fromRgbF(0, 0, 1));
QCOMPARE(qvariant_cast<QColor>(object->property("test2")), QColor::fromRgbF(1, 0, 0));
@@ -601,7 +607,7 @@ void tst_qqmlqt::openUrlExternally()
QQmlComponent component(&engine, testFileUrl("openUrlExternally.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(handler.called,1);
QCOMPARE(handler.last, QUrl("test:url"));
@@ -623,7 +629,7 @@ void tst_qqmlqt::openUrlExternally_pragmaLibrary()
QQmlComponent component(&engine, testFileUrl("openUrlExternally_lib.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(handler.called,1);
QCOMPARE(handler.last, QUrl("test:url"));
@@ -644,7 +650,7 @@ void tst_qqmlqt::md5()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test2").toString(), QLatin1String(QCryptographicHash::hash("Hello World", QCryptographicHash::Md5).toHex()));
@@ -662,7 +668,7 @@ void tst_qqmlqt::createComponent()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("absoluteUrl").toString(), QString("http://www.example.com/test.qml"));
QCOMPARE(object->property("relativeUrl").toString(), testFileUrl("createComponentData.qml").toString());
@@ -676,7 +682,7 @@ void tst_qqmlqt::createComponent()
{
QQmlComponent component(&engine, testFileUrl("createComponent.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QTRY_VERIFY(object->property("success").toBool());
delete object;
}
@@ -687,7 +693,7 @@ void tst_qqmlqt::createComponent_pragmaLibrary()
// Currently, just loading createComponent_lib.qml causes crash on some platforms
QQmlComponent component(&engine, testFileUrl("createComponent_lib.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("status").toInt(), int(QQmlComponent::Ready));
QCOMPARE(object->property("readValue").toInt(), int(1913));
delete object;
@@ -711,13 +717,13 @@ void tst_qqmlqt::createQmlObject()
QTest::ignoreMessage(QtDebugMsg, qPrintable(warning6));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("emptyArg").toBool(), true);
QCOMPARE(object->property("success").toBool(), true);
QQuickItem *item = qobject_cast<QQuickItem *>(object);
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QCOMPARE(item->childItems().count(), 1);
delete object;
@@ -790,7 +796,7 @@ void tst_qqmlqt::dateTimeFormatting()
QObject *object = component.create();
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(inputProperties.count() > 0);
QVariant result;
@@ -863,7 +869,7 @@ void tst_qqmlqt::dateTimeFormattingVariants()
QObject *object = component.create();
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVariant result;
QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
@@ -888,7 +894,8 @@ void tst_qqmlqt::dateTimeFormattingVariants_data()
QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
QDate date(2011,5,31);
- temporary = QDateTime(date);
+ // V4 reads the date in UTC but DateObject::toQDateTime() gives it back in local time:
+ temporary = QDateTime(date, QTime(0, 0, 0), Qt::UTC).toLocalTime();
QTest::newRow("formatDate, qdate") << "formatDate" << QVariant::fromValue(date) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
QTest::newRow("formatDateTime, qdate") << "formatDateTime" << QVariant::fromValue(date) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
QTest::newRow("formatTime, qdate") << "formatTime" << QVariant::fromValue(date) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
@@ -922,7 +929,7 @@ void tst_qqmlqt::isQtObject()
{
QQmlComponent component(&engine, testFileUrl("isQtObject.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), false);
@@ -941,7 +948,7 @@ void tst_qqmlqt::btoa()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test2").toString(), QString("SGVsbG8gd29ybGQh"));
@@ -956,7 +963,7 @@ void tst_qqmlqt::atob()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test2").toString(), QString("Hello world!"));
@@ -971,7 +978,7 @@ void tst_qqmlqt::fontFamilies()
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QFontDatabase database;
QCOMPARE(object->property("test2"), QVariant::fromValue(database.families()));
@@ -985,7 +992,7 @@ void tst_qqmlqt::quit()
QSignalSpy spy(&engine, SIGNAL(quit()));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(spy.count(), 1);
delete object;
@@ -997,7 +1004,7 @@ void tst_qqmlqt::exit()
QSignalSpy spy(&engine, &QQmlEngine::exit);
QObject *object = component.create();
- QVERIFY(object != Q_NULLPTR);
+ QVERIFY(object != nullptr);
QCOMPARE(spy.count(), 1);
QList<QVariant> arguments = spy.takeFirst();
QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt());
@@ -1010,7 +1017,7 @@ void tst_qqmlqt::resolvedUrl()
QQmlComponent component(&engine, testFileUrl("resolvedUrl.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("result").toString(), component.url().toString());
QCOMPARE(object->property("isString").toBool(), true);
@@ -1100,14 +1107,14 @@ void tst_qqmlqt::later()
QQmlComponent component(&engine, testFileUrl("later.qml"));
QObject *root = component.create();
- QVERIFY(root != 0);
+ QVERIFY(root != nullptr);
if (!function.isEmpty())
QMetaObject::invokeMethod(root, qPrintable(function));
for (int i = 0; i < propNames.size(); ++i) {
if (propNames.at(i) == QLatin1String("processEvents")) {
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
} else if (propNames.at(i) == QLatin1String("collectGarbage")) {
engine.collectGarbage();
@@ -1130,7 +1137,7 @@ void tst_qqmlqt::qtObjectContents()
QQmlComponent component(&engine, testFileUrl("qtObjectContents.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("values").canConvert<QJSValue>());
QVariantMap values = object->property("values").value<QJSValue>().toVariant().toMap();
@@ -1254,7 +1261,7 @@ void tst_qqmlqt::timeRoundtrip()
eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp);
QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml"));
QObject *obj = component.create();
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
// QML reads m_getTime and saves the result as m_putTime; this should come out the same, without
// any perturbation (e.g. by DST effects) from converting from QTime to V4's Date and back
diff --git a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
index e08389045c..b0be799bd5 100644
--- a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
+++ b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp
@@ -53,6 +53,7 @@ private slots:
void categories();
void siblings();
void initial();
+ void noApplicationIdentifiersSet();
};
// ### Replace keyValueMap("foo", "bar") with QVariantMap({{"foo", "bar"}})
@@ -87,11 +88,8 @@ class CppObject : public QObject
Q_PROPERTY(QFont fontProperty MEMBER m_fontProperty NOTIFY fontPropertyChanged)
public:
- CppObject(QObject *parent = 0) : QObject(parent),
- m_intProperty(123),
- m_boolProperty(true),
- m_realProperty(1.23),
- m_doubleProperty(3.45),
+ CppObject(QObject *parent = nullptr) : QObject(parent),
+
m_stringProperty("foo"),
m_urlProperty("http://www.qt-project.org"),
m_objectProperty(keyValueMap("foo", "bar")),
@@ -127,10 +125,10 @@ signals:
void fontPropertyChanged(const QFont &arg);
private:
- int m_intProperty;
- bool m_boolProperty;
- qreal m_realProperty;
- double m_doubleProperty;
+ int m_intProperty = 123;
+ bool m_boolProperty = true;
+ qreal m_realProperty = 1.23;
+ double m_doubleProperty = 3.45;
QString m_stringProperty;
QUrl m_urlProperty;
QVariant m_varProperty;
@@ -150,10 +148,6 @@ void tst_QQmlSettings::initTestCase()
{
QQmlDataTest::initTestCase();
- QCoreApplication::setApplicationName("tst_QQmlSettings");
- QCoreApplication::setOrganizationName("QtProject");
- QCoreApplication::setOrganizationDomain("qt-project.org");
-
qmlRegisterType<CppObject>("Qt.test", 1, 0, "CppObject");
}
@@ -161,6 +155,10 @@ void tst_QQmlSettings::init()
{
QSettings settings;
settings.clear();
+
+ QCoreApplication::setApplicationName("tst_QQmlSettings");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setOrganizationDomain("qt-project.org");
}
void tst_QQmlSettings::cleanup()
@@ -484,6 +482,31 @@ void tst_QQmlSettings::initial()
QCOMPARE(settings->property("value").toString(), QStringLiteral("initial"));
}
+void tst_QQmlSettings::noApplicationIdentifiersSet()
+{
+#ifdef Q_OS_MACOS
+ QSKIP("macOS doesn't complain about empty application identifiers");
+#endif
+
+ QCoreApplication::setApplicationName(QString());
+ QCoreApplication::setOrganizationName(QString());
+ QCoreApplication::setOrganizationDomain(QString());
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: Failed to initialize QSettings instance. Status code is: 1"));
+ // Can't set an empty applicationName because QCoreApplication won't allow it, which is why it's not listed here.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Settings: The following application identifiers have not been set: QVector\\(\"organizationName\", \"organizationDomain\"\\)"));
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("basic.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root.data());
+ // The value of the QML property will be true because it defaults to it...
+ QVERIFY(root->property("success").toBool());
+ QSettings settings;
+ // ... but the settings' value should be false because it was never loaded.
+ QVERIFY(!settings.value("success").toBool());
+}
+
QTEST_MAIN(tst_QQmlSettings)
#include "tst_qqmlsettings.moc"
diff --git a/tests/auto/qml/qqmlsqldatabase/data/changeVersion.qml b/tests/auto/qml/qqmlsqldatabase/data/changeVersion.qml
new file mode 100644
index 0000000000..7d2683d869
--- /dev/null
+++ b/tests/auto/qml/qqmlsqldatabase/data/changeVersion.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQml 2.2
+import QtQuick.LocalStorage 2.0
+
+QtObject {
+ property var db;
+ property string version;
+
+ function create() {
+ db = LocalStorage.openDatabaseSync("testdb", "2", "stuff for testing", 100000);
+ version = db.version;
+ }
+
+ function upgrade() {
+ db = db.changeVersion(db.version, "22", function(y) {});
+ version = db.version;
+ }
+}
diff --git a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
index 3b982d1ab7..28f9c9a0c2 100644
--- a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
+++ b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp
@@ -63,6 +63,7 @@ private slots:
void testQml_cleanopen_data();
void testQml_cleanopen();
void totalDatabases();
+ void upgradeDatabase();
void cleanupTestCase();
@@ -164,7 +165,7 @@ void tst_qqmlsqldatabase::testQml()
component.setData(qml.toUtf8(), testFileUrl("empty.qml")); // just a file for relative local imports
QVERIFY(!component.isError());
QQuickText *text = qobject_cast<QQuickText*>(component.create());
- QVERIFY(text != 0);
+ QVERIFY(text != nullptr);
QCOMPARE(text->text(),QString("passed"));
}
@@ -200,6 +201,22 @@ void tst_qqmlsqldatabase::totalDatabases()
QCOMPARE(QDir(dbDir()+"/Databases").entryInfoList(QDir::Files|QDir::NoDotAndDotDot).count(), total_databases_created_by_tests*2);
}
+void tst_qqmlsqldatabase::upgradeDatabase()
+{
+ QQmlComponent component(engine, testFile("changeVersion.qml"));
+ QVERIFY(component.isReady());
+
+ QObject *object = component.create();
+ QVERIFY(object);
+ QVERIFY(object->property("version").toString().isEmpty());
+
+ QVERIFY(QMetaObject::invokeMethod(object, "create"));
+ QCOMPARE(object->property("version").toString(), QLatin1String("2"));
+
+ QVERIFY(QMetaObject::invokeMethod(object, "upgrade"));
+ QCOMPARE(object->property("version").toString(), QLatin1String("22"));
+}
+
QTEST_MAIN(tst_qqmlsqldatabase)
#include "tst_qqmlsqldatabase.moc"
diff --git a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
index 5231af88be..68ed22c01c 100644
--- a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
+++ b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp
@@ -55,10 +55,7 @@ public:
};
public:
- CppObject()
- : QObject()
- , m_objectState(State0)
- {}
+ CppObject() {}
ObjectState objectState() const { return m_objectState; }
void setObjectState(ObjectState objectState) { m_objectState = objectState; emit objectStateChanged();}
@@ -68,7 +65,7 @@ signals:
void mySignal(int signalState);
private:
- ObjectState m_objectState;
+ ObjectState m_objectState = State0;
};
tst_qqmlstatemachine::tst_qqmlstatemachine()
@@ -86,7 +83,7 @@ void tst_qqmlstatemachine::tst_cppObjectSignal()
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("_cppObject", &cppObject);
QScopedPointer<QObject> rootObject(component.create());
- QVERIFY(rootObject != 0);
+ QVERIFY(rootObject != nullptr);
// wait for state machine to start
QTRY_VERIFY(rootObject->property("running").toBool());
diff --git a/tests/auto/qml/qqmltablemodel/data/TestModel.qml b/tests/auto/qml/qqmltablemodel/data/TestModel.qml
new file mode 100644
index 0000000000..7aeb5d03f4
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/TestModel.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
+
+import "TestUtils.js" as TestUtils
+
+TableModel {
+ id: testModel
+ objectName: "testModel"
+ roleDataProvider: TestUtils.testModelRoleDataProvider
+ 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/builtInRoles.qml b/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml
new file mode 100644
index 0000000000..d9882e4dea
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/builtInRoles.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
+
+import "TestUtils.js" as TestUtils
+
+TableModel {
+ id: testModel
+ objectName: "testModel"
+ roleDataProvider: TestUtils.testModelRoleDataProvider
+ rows: [
+ [
+ { name: "John", someOtherRole1: "foo" }, // column 0
+ { age: 22, someOtherRole2: "foo" } // column 1
+ ],
+ [
+ { name: "Oliver", someOtherRole1: "foo" }, // column 0
+ { age: 33, someOtherRole2: "foo" } // column 1
+ ]
+ ]
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/common.qml b/tests/auto/qml/qqmltablemodel/data/common.qml
new file mode 100644
index 0000000000..aec796bd4f
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/common.qml
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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 appendRow(personName, personAge) {
+ testModel.appendRow([
+ { name: personName },
+ { age: personAge }
+ ])
+ }
+
+ function appendRowInvalid1() {
+ testModel.appendRow([
+ { name: "Foo" },
+ { age: 99 },
+ { nonExistentRole: 123 }
+ ])
+ }
+
+ function appendRowInvalid2() {
+ testModel.appendRow(123)
+ }
+
+ function appendRowInvalid3() {
+ testModel.appendRow([
+ { name: "Foo" },
+ { age: [] }
+ ])
+ }
+
+ function insertRow(personName, personAge, rowIndex) {
+ testModel.insertRow(rowIndex, [
+ { name: personName },
+ { age: personAge }]
+ )
+ }
+
+ function insertRowInvalid1() {
+ testModel.insertRow(0, [
+ { name: "Foo" },
+ { age: 99 },
+ { nonExistentRole: 123 }
+ ])
+ }
+
+ function insertRowInvalid2() {
+ testModel.insertRow(0, 123)
+ }
+
+ function insertRowInvalid3() {
+ testModel.insertRow(0, [
+ { name: "Foo" },
+ { age: [] }
+ ])
+ }
+
+ function setRow(rowIndex, personName, personAge) {
+ testModel.setRow(rowIndex, [
+ { name: personName },
+ { age: personAge }]
+ )
+ }
+
+ function setRowInvalid1() {
+ testModel.setRow(0, [
+ { name: "Foo" },
+ { age: 99 },
+ { nonExistentRole: 123 }
+ ])
+ }
+
+ function setRowInvalid2() {
+ testModel.setRow(0, 123)
+ }
+
+ function setRowInvalid3() {
+ testModel.setRow(0, [
+ { name: "Foo" },
+ { age: [] }
+ ])
+ }
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ model: TestModel {
+ id: testModel
+ }
+ delegate: Text {
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml
new file mode 100644
index 0000000000..d61c50ba2c
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/dataAndSetData.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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: TableModel {
+ id: testModel
+ objectName: "testModel"
+ rows: [
+ [
+ { name: "John", someOtherRole1: "foo" }, // column 0
+ { age: 22, someOtherRole2: "foo" } // column 1
+ ],
+ [
+ { name: "Oliver", someOtherRole1: "foo" }, // column 0
+ { age: 33, someOtherRole2: "foo" } // column 1
+ ]
+ ]
+
+ // 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), "name") === dude)
+ row = r;
+ var index = testModel.index(row, 1)
+ testModel.setData(index, "age", testModel.data(index, "age") + 1)
+ }
+ }
+ delegate: Text {
+ id: textItem
+ text: model.display
+ TapHandler {
+ onTapped: testModel.happyBirthday(testModel.data(testModel.index(row, 0), "name"))
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/empty.qml b/tests/auto/qml/qqmltablemodel/data/empty.qml
new file mode 100644
index 0000000000..6e66b99145
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/empty.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.12
+import Qt.labs.qmlmodels 1.0
+
+import "TestUtils.js" as TestUtils
+
+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 }
+ ]
+ ]
+ }
+
+ TableModel {
+ id: testModel
+ objectName: "testModel"
+ roleDataProvider: TestUtils.testModelRoleDataProvider
+ }
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ model: testModel
+ delegate: Text {
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml b/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml
new file mode 100644
index 0000000000..510a62e74b
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** 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
+ rows: [
+ [
+ { name: "John", display: "foo" },
+ { age: 22, display: "bar" }
+ ]
+ ]
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml b/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml
new file mode 100644
index 0000000000..2706ea54fd
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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
+
+ TableModel {
+ id: testModel
+ objectName: "testModel"
+ rows: [
+ [ { name: "Rex" }, { age: 3 } ],
+ [ { name: "Buster" }, { age: 5 } ]
+ ]
+ roleDataProvider: function(index, role, cellData) {
+ if (role === "display") {
+ // Age will now be in dog years
+ if (cellData.hasOwnProperty("age"))
+ return (cellData.age * 7);
+ else if (index.column === 0)
+ return (cellData.name);
+ }
+ return cellData;
+ }
+ }
+ TableView {
+ anchors.fill: parent
+ model: testModel
+ delegate: Text {
+ id: textItem
+ text: model.display
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml
new file mode 100644
index 0000000000..5f849c3350
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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: TableModel {
+ id: testModel
+ objectName: "testModel"
+ rows: [
+ [
+ { name: "John" },
+ { age: 22 }
+ ],
+ [
+ { name: "Oliver" },
+ { age: 33 }
+ ]
+ ]
+ }
+
+ delegate: Text {
+ id: textItem
+ // TODO: this is currently random when no roleDataProvider handles it
+ // we should allow roleDataProvider to be used to handle specific roles only
+ text: model.display
+
+ Connections {
+ target: root
+ enabled: column === 1
+ onShouldModify: model.age = 18
+ }
+
+ Connections {
+ target: root
+ enabled: column === 0
+ // Invalid: should be "name".
+ onShouldModifyInvalidRole: model.age = 100
+ }
+
+ Connections {
+ target: root
+ enabled: column === 1
+ // Invalid: should be string.
+ onShouldModifyInvalidType: model.age = "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..6aaf79f2d4
--- /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..11b11132aa
--- /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
diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
new file mode 100644
index 0000000000..059ce082d9
--- /dev/null
+++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp
@@ -0,0 +1,947 @@
+/****************************************************************************
+**
+** 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 <QtQml/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 clear();
+ void getRow();
+ void insertRow();
+ void moveRow();
+ void setRow();
+ void setDataThroughDelegate();
+ void setRowsImperatively();
+ void setRowsMultipleTimes();
+ void builtInRoles_data();
+ void builtInRoles();
+ void explicitDisplayRole();
+ void roleDataProvider();
+ void dataAndEditing();
+};
+
+static const int builtInRoleCount = 6;
+
+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 heightSignalEmissions = 0;
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QCOMPARE(roleNames.size(), 2 + builtInRoleCount);
+ QVERIFY(roleNames.values().contains("name"));
+ QVERIFY(roleNames.values().contains("age"));
+ QVERIFY(roleNames.values().contains("display"));
+ QVERIFY(roleNames.values().contains("decoration"));
+ QVERIFY(roleNames.values().contains("edit"));
+ QVERIFY(roleNames.values().contains("toolTip"));
+ QVERIFY(roleNames.values().contains("statusTip"));
+ QVERIFY(roleNames.values().contains("whatsThis"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).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(), heightSignalEmissions);
+
+ // 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(), heightSignalEmissions);
+
+ // 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(), heightSignalEmissions);
+
+ // 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(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+
+ // Call append() with a row that has a new (and hence unexpected) role.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*appendRow\\(\\): expected 2 columns, but got 3"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid1"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 1);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // Call append() with a row that is not an array.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*appendRow\\(\\): expected \"row\" argument to be an array, but got int instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid2"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 1);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // Call append() with a row with a role that is of the wrong type.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*appendRow\\(\\): expected property with type int at column index 1, but got QVariantList instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRowInvalid3"));
+ // Nothing should change.
+ QCOMPARE(model->rowCount(), 1);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // Call append() to insert one row.
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "appendRow", 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("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+
+ // Call remove() and specify rowIndex and rows, removing all remaining rows.
+ QVERIFY(QMetaObject::invokeMethod(model, "removeRow", Q_ARG(int, 0), Q_ARG(int, 2)));
+ QCOMPARE(model->rowCount(), 0);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")), QVariant());
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")), QVariant());
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+}
+
+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("name"));
+ QVERIFY(roleNames.values().contains("age"));
+ QCOMPARE(roleNames.size(), 2 + builtInRoleCount);
+
+ 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 QVariantList rowAsVariantList = returnValue.toList();
+ QCOMPARE(rowAsVariantList.at(0).toMap().value(QLatin1String("name")), QLatin1String("John"));
+ QCOMPARE(rowAsVariantList.at(1).toMap().value(QLatin1String("age")), 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 heightSignalEmissions = 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that has a new (and hence unexpected) role.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*insertRow\\(\\): expected 2 columns, but got 3"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid1"));
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that is not an array.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*insertRow\\(\\): expected \"row\" argument to be an array, but got int 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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(
+ ".*insertRow\\(\\): expected property with type int at column index 1, but got QVariantList instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "insertRowInvalid3"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ 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, 2)));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 3);
+ 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, 1)));
+ QCOMPARE(model->rowCount(), 4);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+ QTRY_COMPARE(tableView->rows(), 4);
+ 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 heightSignalEmissions = 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ heightSignalEmissions = 3;
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+
+ // 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("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(3, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(3, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(4, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Trev"));
+ QCOMPARE(model->data(model->index(4, 1, QModelIndex()), roleNames.key("age")).toInt(), 48);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+}
+
+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 heightSignalEmissions = 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(
+ ".*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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ QCOMPARE(tableView->rows(), 2);
+ QCOMPARE(tableView->columns(), 2);
+
+ // Try to insert a row that has a new (and hence unexpected) role.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setRow\\(\\): expected 2 columns, but got 3"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid1"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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 an array, but got int 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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 property with type int at column index 1, but got QVariantList instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowInvalid3"));
+ QCOMPARE(model->rowCount(), 2);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), heightSignalEmissions);
+ 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("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 40);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Daisy"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 30);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Wot"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 99);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), ++heightSignalEmissions);
+ 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(), 2 + builtInRoleCount);
+ QVERIFY(roleNames.values().contains("name"));
+ QVERIFY(roleNames.values().contains("age"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 18);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+
+ // Test setting a role that doesn't exist for a certain column.
+ const auto invalidRoleRegEx = QRegularExpression(".*setData\\(\\): no role named \"age\" at column index 0. " \
+ "The available roles for that column are:[\r\n] - \"name\" \\(QString\\)");
+ // There are two rows, so two delegates respond to the signal, which means we need to ignore two warnings.
+ QTest::ignoreMessage(QtWarningMsg, invalidRoleRegEx);
+ QTest::ignoreMessage(QtWarningMsg, invalidRoleRegEx);
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidRole"));
+ // Should be unchanged.
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).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 \"age\" to \"int\""));
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*setData\\(\\): failed converting value QVariant\\(QString, \"Whoops\"\\) " \
+ "set at row 1 column 1 with role \"age\" to \"int\""));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "modifyInvalidType"));
+ // Should be unchanged.
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 18);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 18);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 0);
+}
+
+// Start off with empty rows and append to test widthChanged().
+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->columnCount(), 0);
+ QCOMPARE(model->rowCount(), 0);
+
+ 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(), 0);
+
+ 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("name")).toString(), QLatin1String("John"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 33);
+ QCOMPARE(columnCountSpy.count(), 1);
+ 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("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 20);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Imum"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 41);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Power"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).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.
+ // TODO: add quotes to the warning message
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
+ ".*setRows\\(\\): expected property named name at column index 0, but got nope instead"));
+ QVERIFY(QMetaObject::invokeMethod(view.rootObject(), "setRowsInvalid"));
+ QCOMPARE(model->rowCount(), 3);
+ QCOMPARE(model->columnCount(), 2);
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Max"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 20);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Imum"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("age")).toInt(), 41);
+ QCOMPARE(model->data(model->index(2, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Power"));
+ QCOMPARE(model->data(model->index(2, 1, QModelIndex()), roleNames.key("age")).toInt(), 89);
+ QCOMPARE(columnCountSpy.count(), 0);
+ QCOMPARE(rowCountSpy.count(), 1);
+ QCOMPARE(tableView->rows(), 3);
+ QCOMPARE(tableView->columns(), 2);
+}
+
+void tst_QQmlTableModel::builtInRoles_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<QByteArray>("roleName");
+ QTest::addColumn<QVariant>("expectedValue");
+
+ const QByteArray displayRole = "display";
+
+ QTest::addRow("display(0,0)") << 0 << 0 << displayRole << QVariant(QLatin1String("John"));
+ QTest::addRow("display(0,1)") << 0 << 1 << displayRole << QVariant(QLatin1String("22"));
+ QTest::addRow("display(1,0)") << 1 << 0 << displayRole << QVariant(QLatin1String("Oliver"));
+ QTest::addRow("display(1,1)") << 1 << 1 << displayRole << QVariant(QLatin1String("33"));
+}
+
+void tst_QQmlTableModel::builtInRoles()
+{
+ QFETCH(int, row);
+ QFETCH(int, column);
+ QFETCH(QByteArray, roleName);
+ QFETCH(QVariant, expectedValue);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("builtInRoles.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(roleNames.size(), 4 + builtInRoleCount);
+ QVERIFY(roleNames.values().contains("display"));
+ QVERIFY(roleNames.values().contains("decoration"));
+ QVERIFY(roleNames.values().contains("edit"));
+ QVERIFY(roleNames.values().contains("toolTip"));
+ QVERIFY(roleNames.values().contains("statusTip"));
+ QVERIFY(roleNames.values().contains("whatsThis"));
+ QVERIFY(roleNames.values().contains("name"));
+ QVERIFY(roleNames.values().contains("age"));
+ QVERIFY(roleNames.values().contains("someOtherRole1"));
+ QVERIFY(roleNames.values().contains("someOtherRole2"));
+ QCOMPARE(model->data(model->index(row, column, QModelIndex()), roleNames.key(roleName)), expectedValue);
+}
+
+void tst_QQmlTableModel::explicitDisplayRole()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("explicitDisplayRole.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+
+ QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create()));
+ QVERIFY(model);
+ 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("foo"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("bar"));
+}
+
+void tst_QQmlTableModel::roleDataProvider()
+{
+ QQuickView view(testFileUrl("roleDataProvider.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>();
+ QVERIFY(model);
+
+ const QHash<int, QByteArray> roleNames = model->roleNames();
+ QVERIFY(roleNames.values().contains("display"));
+ QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Rex"));
+ QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 3 * 7);
+ QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Buster"));
+ QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 5 * 7);
+}
+
+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);
+}
+
+QTEST_MAIN(tst_QQmlTableModel)
+
+#include "tst_qqmltablemodel.moc"
diff --git a/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp b/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
index 44e7c706bf..4e42d02514 100644
--- a/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
+++ b/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
@@ -89,11 +89,9 @@ class TimerHelper : public QObject
{
Q_OBJECT
public:
- TimerHelper() : QObject(), count(0)
- {
- }
+ TimerHelper() { }
- int count;
+ int count = 0;
public slots:
void timeout() {
@@ -101,9 +99,7 @@ public slots:
}
};
-tst_qqmltimer::tst_qqmltimer()
-{
-}
+tst_qqmltimer::tst_qqmltimer() { }
void tst_qqmltimer::initTestCase()
{
@@ -116,7 +112,7 @@ void tst_qqmltimer::notRepeating()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 100; running: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
QVERIFY(timer->isRunning());
QVERIFY(!timer->isRepeating());
QCOMPARE(timer->interval(), 100);
@@ -138,7 +134,7 @@ void tst_qqmltimer::notRepeatingStart()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 100 }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
QVERIFY(!timer->isRunning());
TimerHelper helper;
@@ -163,7 +159,7 @@ void tst_qqmltimer::repeat()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 100; repeat: true; running: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -205,7 +201,7 @@ void tst_qqmltimer::triggeredOnStart()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 100; running: true; triggeredOnStart: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
QVERIFY(timer->triggeredOnStart());
TimerHelper helper;
@@ -239,7 +235,7 @@ void tst_qqmltimer::triggeredOnStartRepeat()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 100; running: true; triggeredOnStart: true; repeat: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -268,7 +264,7 @@ void tst_qqmltimer::noTriggerIfNotRunning()
"}"
), QUrl::fromLocalFile(""));
QObject *item = component.create();
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
consistentWait(200);
QCOMPARE(item->property("ok").toBool(), true);
@@ -281,7 +277,7 @@ void tst_qqmltimer::changeDuration()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 200; repeat: true; running: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -317,7 +313,7 @@ void tst_qqmltimer::restart()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQml 2.0\nTimer { interval: 500; repeat: true; running: true }"), QUrl::fromLocalFile(""));
QQmlTimer *timer = qobject_cast<QQmlTimer*>(component.create());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -350,7 +346,7 @@ void tst_qqmltimer::restartFromTriggered()
" }"), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(component.create());
QQmlTimer *timer = qobject_cast<QQmlTimer*>(object.data());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -378,7 +374,7 @@ void tst_qqmltimer::runningFromTriggered()
" }"), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(component.create());
QQmlTimer *timer = qobject_cast<QQmlTimer*>(object.data());
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
TimerHelper helper;
connect(timer, SIGNAL(triggered()), &helper, SLOT(timeout()));
@@ -401,9 +397,9 @@ void tst_qqmltimer::parentProperty()
QQmlComponent component(&engine);
component.setData(QByteArray("import QtQuick 2.0\nItem { Timer { objectName: \"timer\"; running: parent.visible } }"), QUrl::fromLocalFile(""));
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
- QVERIFY(item != 0);
+ QVERIFY(item != nullptr);
QQmlTimer *timer = item->findChild<QQmlTimer*>("timer");
- QVERIFY(timer != 0);
+ QVERIFY(timer != nullptr);
QVERIFY(timer->isRunning());
diff --git a/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml b/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml
new file mode 100644
index 0000000000..294fff3284
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ property string baseProperty: qsTr("translate me");
+}
diff --git a/tests/auto/qml/qqmltranslation/data/translationChange.qml b/tests/auto/qml/qqmltranslation/data/translationChange.qml
new file mode 100644
index 0000000000..ae3231935c
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/translationChange.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+
+TranslationChangeBase {
+ id: root
+
+ ListModel {
+ id: listModel
+ ListElement {
+ text: qsTr("translate me")
+ }
+ }
+
+ baseProperty: "do not translate"
+ property string text1: qsTr("translate me")
+ function weDoTranslations() {
+ return qsTr("translate me")
+ }
+ property string text2: weDoTranslations()
+ property string text3
+ property string fromListModel: listModel.get(0).text
+
+ states: [
+ State {
+ name: "default"
+ when: 1 == 1
+ PropertyChanges {
+ target: root
+ text3: qsTr("translate me")
+ }
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 1fc803a395..809a9bd9db 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -44,6 +44,7 @@ private slots:
void translation_data();
void translation();
void idTranslation();
+ void translationChange();
};
void tst_qqmltranslation::translation_data()
@@ -70,12 +71,12 @@ void tst_qqmltranslation::translation()
QQmlEngine engine;
QQmlComponent component(&engine, testFile);
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
if (verifyCompiledData) {
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
- QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
+ QQmlRefPointer<QQmlTypeData> typeData = engine->typeLoader.getType(context->baseUrl());
QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
QVERIFY(compilationUnit);
@@ -84,11 +85,10 @@ void tst_qqmltranslation::translation()
<< QStringLiteral("disambiguation")
<< QStringLiteral("singular") << QStringLiteral("plural");
- const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
- const QString propertyName = unit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
const bool expectCompiledTranslation = compiledTranslations.contains(propertyName);
@@ -130,20 +130,19 @@ void tst_qqmltranslation::idTranslation()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("idtranslation.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
{
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
- QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
+ QQmlRefPointer<QQmlTypeData> typeData = engine->typeLoader.getType(context->baseUrl());
QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
QVERIFY(compilationUnit);
- const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
- const QString propertyName = unit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex);
if (propertyName == "idTranslation") {
if (binding->type != QV4::CompiledData::Binding::Type_TranslationById)
qDebug() << "binding for property" << propertyName << "is not a compiled translation";
@@ -162,6 +161,55 @@ void tst_qqmltranslation::idTranslation()
delete object;
}
+class DummyTranslator : public QTranslator
+{
+ Q_OBJECT
+
+ QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override
+ {
+ Q_UNUSED(context);
+ Q_UNUSED(disambiguation);
+ Q_UNUSED(n);
+ if (!qstrcmp(sourceText, "translate me"))
+ return QString::fromUtf8("xxx");
+ return QString();
+ }
+
+ bool isEmpty() const override
+ {
+ return false;
+ }
+};
+
+void tst_qqmltranslation::translationChange()
+{
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("translationChange.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QCOMPARE(object->property("baseProperty").toString(), QString::fromUtf8("do not translate"));
+ QCOMPARE(object->property("text1").toString(), QString::fromUtf8("translate me"));
+ QCOMPARE(object->property("text2").toString(), QString::fromUtf8("translate me"));
+ QCOMPARE(object->property("text3").toString(), QString::fromUtf8("translate me"));
+ QCOMPARE(object->property("fromListModel").toString(), QString::fromUtf8("translate me"));
+
+ DummyTranslator translator;
+ QCoreApplication::installTranslator(&translator);
+
+ QEvent ev(QEvent::LanguageChange);
+ QCoreApplication::sendEvent(&engine, &ev);
+
+ QCOMPARE(object->property("baseProperty").toString(), QString::fromUtf8("do not translate"));
+ QCOMPARE(object->property("text1").toString(), QString::fromUtf8("xxx"));
+ QCOMPARE(object->property("text2").toString(), QString::fromUtf8("xxx"));
+ QCOMPARE(object->property("text3").toString(), QString::fromUtf8("xxx"));
+ QCOMPARE(object->property("fromListModel").toString(), QString::fromUtf8("xxx"));
+
+ QCoreApplication::removeTranslator(&translator);
+}
+
QTEST_MAIN(tst_qqmltranslation)
#include "tst_qqmltranslation.moc"
diff --git a/tests/auto/qml/qqmltypeloader/data/Base.qml b/tests/auto/qml/qqmltypeloader/data/Base.qml
new file mode 100644
index 0000000000..431c659424
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Base.qml
@@ -0,0 +1,3 @@
+import QtQml 2.0
+
+QtObject {}
diff --git a/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml b/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml
new file mode 100644
index 0000000000..b3610831df
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/ComponentWithIncubator.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ Repeater {
+ model: 3
+ Item {}
+ }
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml
new file mode 100644
index 0000000000..f4ad5e5f7a
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton1.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQuick 2.0
+
+Item {
+ property bool ok: true
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml
new file mode 100644
index 0000000000..55dd57517f
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/CppRegisteredSingleton2.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+import QtQuick 2.0
+import cppsingletonmodule 1.0
+
+Item {
+ property bool ok: CppRegisteredSingleton1.ok
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Fast/Fast.qml b/tests/auto/qml/qqmltypeloader/data/Fast/Fast.qml
new file mode 100644
index 0000000000..e879577e10
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Fast/Fast.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+
+QtObject {
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Fast/qmldir b/tests/auto/qml/qqmltypeloader/data/Fast/qmldir
new file mode 100644
index 0000000000..a6a4c9e6c7
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Fast/qmldir
@@ -0,0 +1 @@
+Fast 1.0 Fast.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/Intercept.qml b/tests/auto/qml/qqmltypeloader/data/Intercept.qml
new file mode 100644
index 0000000000..b557b4b941
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Intercept.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 Fast 1.0
+
+Item {
+ Rectangle {
+ color: "red"
+ width: 100
+ height: 100
+ }
+ Fast {
+
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Load.qml b/tests/auto/qml/qqmltypeloader/data/Load.qml
new file mode 100644
index 0000000000..0b893bb5cd
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Load.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Item {
+ property int xy: loader.xy
+ Loader {
+ id: loader
+ asynchronous: true
+ source: 'Base.qml'
+ property int xy: item.xy
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/Singleton.qml b/tests/auto/qml/qqmltypeloader/data/Singleton.qml
new file mode 100644
index 0000000000..3a1b1c1493
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/Singleton.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+import QtQml 2.0
+import modulewithsingleton 1.0
+
+QtObject {
+ property bool ok: true
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/ValueSource.qml b/tests/auto/qml/qqmltypeloader/data/ValueSource.qml
new file mode 100644
index 0000000000..19e6e730c8
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/ValueSource.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+import QtQuick 2.6
+
+Item {
+ id: valueSource
+ property int something: 10
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/implicitcomponent.qml b/tests/auto/qml/qqmltypeloader/data/implicitcomponent.qml
new file mode 100644
index 0000000000..9cebc88c8b
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/implicitcomponent.qml
@@ -0,0 +1,10 @@
+import QtQml 2.2
+
+QtObject {
+ property Component some: QtObject {
+ property int rrr: 2
+ property Component onemore: QtObject {
+ property int brrrr: -1
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml
new file mode 100644
index 0000000000..34eca59f86
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton1.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+import QtQuick 2.0
+import "."
+
+Item {
+ property bool ok: true
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml
new file mode 100644
index 0000000000..607d85d7fb
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/Singleton2.qml
@@ -0,0 +1,7 @@
+pragma Singleton
+import QtQuick 2.0
+import "."
+
+Item {
+ property bool ok: Singleton1.ok
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir
new file mode 100644
index 0000000000..71b889a12d
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/imports/multisingletonmodule/qmldir
@@ -0,0 +1,2 @@
+singleton Singleton1 1.0 Singleton1.qml
+singleton Singleton2 1.0 Singleton2.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml
new file mode 100644
index 0000000000..b80e2c5223
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/multisingletonuser.qml
@@ -0,0 +1,7 @@
+import QtQml 2.0
+import multisingletonmodule 1.0
+import cppsingletonmodule 1.0
+
+QtObject {
+ property bool ok: Singleton2.ok && CppRegisteredSingleton2.ok
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/redirected/Imported.qml b/tests/auto/qml/qqmltypeloader/data/redirected/Imported.qml
new file mode 100644
index 0000000000..62954fe1b2
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/redirected/Imported.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property int xy: 323232
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/redirected/Redirected.qml b/tests/auto/qml/qqmltypeloader/data/redirected/Redirected.qml
new file mode 100644
index 0000000000..40fec5ed31
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/redirected/Redirected.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+Imported {
+
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/redirected/qmldir b/tests/auto/qml/qqmltypeloader/data/redirected/qmldir
new file mode 100644
index 0000000000..8eb1fa5c18
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/redirected/qmldir
@@ -0,0 +1 @@
+Imported 1.0 Imported.qml
diff --git a/tests/auto/qml/qqmltypeloader/data/singletonuser.qml b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml
new file mode 100644
index 0000000000..79ca47e12f
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/singletonuser.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import modulewithsingleton 1.0
+
+QtObject {
+ property bool ok: Singleton.ok
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/test_intercept.qml b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
new file mode 100644
index 0000000000..0d64cb7e28
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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
+
+ListView {
+ width: 400
+ height: 500
+ model: 2
+
+ id: test
+ property int created: 0
+ property int loaded: 0
+
+ delegate: Loader {
+ width: ListView.view.width
+ height: 100
+ asynchronous: true
+ source: index == 0 ? "Intercept.qml" : "GenericView.qml"
+
+ onLoaded: {
+ test.loaded++
+ }
+ Component.onCompleted: {
+ test.created++
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml
new file mode 100644
index 0000000000..219c7d3bcb
--- /dev/null
+++ b/tests/auto/qml/qqmltypeloader/data/trim_cache3.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ width: 400
+ height: 400
+
+ property alias source: loader.source
+
+ Loader {
+ id: loader
+ source: "ComponentWithIncubator.qml"
+ }
+}
+
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 3d3a7ff725..0c4abf19f4 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -28,10 +28,15 @@
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
+#if QT_CONFIG(process)
+#include <QtCore/qprocess.h>
+#endif
#include <QtQml/private/qqmlengine_p.h>
#include <QtQml/private/qqmltypeloader_p.h>
+#include "../../shared/testhttpserver.h"
#include "../../shared/util.h"
class tst_QQMLTypeLoader : public QQmlDataTest
@@ -43,6 +48,14 @@ private slots:
void loadComponentSynchronously();
void trimCache();
void trimCache2();
+ void trimCache3();
+ void keepSingleton();
+ void keepRegistrations();
+ void intercept();
+ void redirect();
+ void qmlSingletonWithinModule();
+ void multiSingletonModule();
+ void implicitComponentModule();
};
void tst_QQMLTypeLoader::testLoadComplete()
@@ -56,7 +69,7 @@ void tst_QQMLTypeLoader::testLoadComplete()
QVERIFY(QTest::qWaitForWindowExposed(window));
QObject *rootObject = window->rootObject();
- QTRY_VERIFY(rootObject != 0);
+ QTRY_VERIFY(rootObject != nullptr);
QTRY_COMPARE(rootObject->property("created").toInt(), 2);
QTRY_COMPARE(rootObject->property("loaded").toInt(), 2);
delete window;
@@ -68,7 +81,7 @@ void tst_QQMLTypeLoader::loadComponentSynchronously()
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
QLatin1String(".*nonprotocol::1:1: QtObject is not a type.*")));
QQmlComponent component(&engine, testFileUrl("load_synchronous.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
}
@@ -80,7 +93,7 @@ void tst_QQMLTypeLoader::trimCache()
QUrl url = testFileUrl("trim_cache.qml");
url.setQuery(QString::number(i));
- QQmlTypeData *data = loader.getType(url);
+ QQmlTypeData *data = loader.getType(url).take();
// Run an event loop to receive the callback that release()es.
QTRY_COMPARE(data->count(), 2);
@@ -109,7 +122,7 @@ void tst_QQMLTypeLoader::trimCache()
void tst_QQMLTypeLoader::trimCache2()
{
- QQuickView *window = new QQuickView();
+ QScopedPointer<QQuickView> window(new QQuickView());
window->setSource(testFileUrl("trim_cache2.qml"));
QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader;
// in theory if gc has already run this could be false
@@ -120,6 +133,376 @@ void tst_QQMLTypeLoader::trimCache2()
QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), false);
}
+// test trimming the cache of an item that contains sub-items created via incubation
+void tst_QQMLTypeLoader::trimCache3()
+{
+ QScopedPointer<QQuickView> window(new QQuickView());
+ window->setSource(testFileUrl("trim_cache3.qml"));
+ QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader;
+ QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), true);
+
+ QQmlProperty::write(window->rootObject(), "source", QString());
+
+ // handle our deleteLater and cleanup
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ window->engine()->collectGarbage();
+
+ window->engine()->trimComponentCache();
+
+ QCOMPARE(loader.isTypeLoaded(testFileUrl("ComponentWithIncubator.qml")), false);
+}
+
+static void checkSingleton(const QString &dataDirectory)
+{
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory);
+ QQmlComponent component(&engine);
+ component.setData("import ClusterDemo 1.0\n"
+ "import QtQuick 2.6\n"
+ "import \"..\"\n"
+ "Item { property int t: ValueSource.something }",
+ QUrl::fromLocalFile(dataDirectory + "/abc/Xyz.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o.data());
+ QCOMPARE(o->property("t").toInt(), 10);
+}
+
+void tst_QQMLTypeLoader::keepSingleton()
+{
+ qmlRegisterSingletonType(testFileUrl("ValueSource.qml"), "ClusterDemo", 1, 0, "ValueSource");
+ checkSingleton(dataDirectory());
+ QQmlMetaType::freeUnusedTypesAndCaches();
+ checkSingleton(dataDirectory());
+}
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+public:
+ TestObject(QObject *parent = nullptr) : QObject(parent) {}
+};
+
+QML_DECLARE_TYPE(TestObject)
+
+static void verifyTypes(bool shouldHaveTestObject, bool shouldHaveFast)
+{
+ bool hasTestObject = false;
+ bool hasFast = false;
+ for (const QQmlType &type : QQmlMetaType::qmlAllTypes()) {
+ if (type.elementName() == QLatin1String("Fast"))
+ hasFast = true;
+ else if (type.elementName() == QLatin1String("TestObject"))
+ hasTestObject = true;
+ }
+ QCOMPARE(hasTestObject, shouldHaveTestObject);
+ QCOMPARE(hasFast, shouldHaveFast);
+}
+
+void tst_QQMLTypeLoader::keepRegistrations()
+{
+ verifyTypes(false, false);
+ qmlRegisterType<TestObject>("Test", 1, 0, "TestObject");
+ verifyTypes(true, false);
+
+ {
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+ QQmlComponent component(&engine);
+ component.setData("import Fast 1.0\nFast {}", QUrl());
+ QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8().constData());
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o.data());
+ verifyTypes(true, true);
+ }
+
+ verifyTypes(true, false); // Fast is gone again, even though an event was still scheduled.
+ QQmlMetaType::freeUnusedTypesAndCaches();
+ verifyTypes(true, false); // qmlRegisterType creates an undeletable type.
+}
+
+class NetworkReply : public QNetworkReply
+{
+public:
+ NetworkReply()
+ {
+ open(QIODevice::ReadOnly);
+ }
+
+ void setData(const QByteArray &data)
+ {
+ if (isFinished())
+ return;
+ m_buffer = data;
+ emit readyRead();
+ setFinished(true);
+ emit finished();
+ }
+
+ void fail()
+ {
+ if (isFinished())
+ return;
+ m_buffer.clear();
+ setError(ContentNotFoundError, "content not found");
+ emit error(ContentNotFoundError);
+ setFinished(true);
+ emit finished();
+ }
+
+ qint64 bytesAvailable() const override
+ {
+ return m_buffer.size();
+ }
+
+ qint64 readData(char *data, qint64 maxlen) override
+ {
+ if (m_buffer.length() < maxlen)
+ maxlen = m_buffer.length();
+ std::memcpy(data, m_buffer.data(), maxlen);
+ m_buffer.remove(0, maxlen);
+ return maxlen;
+ }
+
+ void abort() override
+ {
+ if (isFinished())
+ return;
+ m_buffer.clear();
+ setFinished(true);
+ emit finished();
+ }
+
+private:
+ QByteArray m_buffer;
+};
+
+class NetworkAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+public:
+
+ NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent)
+ {
+ }
+
+ QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
+ QIODevice *outgoingData) override
+ {
+ QUrl url = request.url();
+ QString scheme = url.scheme();
+ if (op != GetOperation || !scheme.endsWith("+debug"))
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+
+ scheme.chop(sizeof("+debug") - 1);
+ url.setScheme(scheme);
+
+ NetworkReply *reply = new NetworkReply;
+ QString filename = QQmlFile::urlToLocalFileOrQrc(url);
+ QTimer::singleShot(10, reply, [this, reply, filename]() {
+ if (filename.isEmpty()) {
+ reply->fail();
+ } else {
+ QFile file(filename);
+ if (file.open(QIODevice::ReadOnly)) {
+ emit loaded(filename);
+ reply->setData(transformQmldir(filename, file.readAll()));
+ } else
+ reply->fail();
+ }
+ });
+ return reply;
+ }
+
+ QByteArray transformQmldir(const QString &filename, const QByteArray &content)
+ {
+ if (!filename.endsWith("/qmldir"))
+ return content;
+
+ // Make qmldir plugin paths absolute, so that we don't try to load them over the network
+ QByteArray result;
+ QByteArray path = filename.toUtf8();
+ path.chop(sizeof("qmldir") - 1);
+ for (QByteArray line : content.split('\n')) {
+ if (line.isEmpty())
+ continue;
+ QList<QByteArray> segments = line.split(' ');
+ if (segments.startsWith("plugin")) {
+ if (segments.length() == 2) {
+ segments.append(path);
+ } else if (segments.length() == 3) {
+ if (!segments[2].startsWith('/'))
+ segments[2] = path + segments[2];
+ } else {
+ // Invalid plugin declaration. Ignore
+ }
+ result.append(segments.join(' '));
+ } else {
+ result.append(line);
+ }
+ result.append('\n');
+ }
+ return result;
+ }
+
+signals:
+ void loaded(const QString &filename);
+};
+
+class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
+{
+public:
+ QStringList loadedFiles;
+
+ QNetworkAccessManager *create(QObject *parent) override
+ {
+ NetworkAccessManager *manager = new NetworkAccessManager(parent);
+ QObject::connect(manager, &NetworkAccessManager::loaded, [this](const QString &filename) {
+ loadedFiles.append(filename);
+ });
+ return manager;
+ }
+};
+
+class UrlInterceptor : public QQmlAbstractUrlInterceptor
+{
+public:
+ QUrl intercept(const QUrl &path, DataType type) override
+ {
+ Q_UNUSED(type);
+ if (!QQmlFile::isLocalFile(path))
+ return path;
+
+ QUrl result = path;
+ QString scheme = result.scheme();
+ if (!scheme.endsWith("+debug"))
+ result.setScheme(scheme + "+debug");
+ return result;
+ }
+};
+
+void tst_QQMLTypeLoader::intercept()
+{
+ qmlClearTypeRegistrations();
+
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+ engine.addImportPath(QT_TESTCASE_BUILDDIR);
+
+ UrlInterceptor interceptor;
+ NetworkAccessManagerFactory factory;
+
+ engine.setUrlInterceptor(&interceptor);
+ engine.setNetworkAccessManagerFactory(&factory);
+
+ QQmlComponent component(&engine, testFileUrl("test_intercept.qml"));
+
+ QVERIFY(component.status() != QQmlComponent::Ready);
+ QTRY_VERIFY2(component.status() == QQmlComponent::Ready,
+ component.errorString().toUtf8().constData());
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o.data());
+
+ QTRY_COMPARE(o->property("created").toInt(), 2);
+ QTRY_COMPARE(o->property("loaded").toInt(), 2);
+
+ QVERIFY(factory.loadedFiles.length() >= 6);
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/test_intercept.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Intercept.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/qmldir"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/Fast.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/GenericView.qml"));
+ QVERIFY(factory.loadedFiles.contains(QLatin1String(QT_TESTCASE_BUILDDIR) + "/Slow/qmldir"));
+}
+
+void tst_QQMLTypeLoader::redirect()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ QVERIFY(server.serveDirectory(dataDirectory()));
+ server.addRedirect("Base.qml", server.urlString("/redirected/Redirected.qml"));
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(server.urlString("/Load.qml"), QQmlComponent::Asynchronous);
+ QTRY_VERIFY2(component.isReady(), qPrintable(component.errorString()));
+
+ QObject *object = component.create();
+ QTRY_COMPARE(object->property("xy").toInt(), 323232);
+}
+
+void tst_QQMLTypeLoader::qmlSingletonWithinModule()
+{
+ qmlClearTypeRegistrations();
+ QQmlEngine engine;
+ qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "modulewithsingleton", 1, 0, "Singleton");
+
+ QQmlComponent component(&engine, testFileUrl("singletonuser.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("ok").toBool());
+}
+
+static void checkCleanCacheLoad(const QString &testCase)
+{
+#if QT_CONFIG(process)
+ const char *skipKey = "QT_TST_QQMLTYPELOADER_SKIP_MISMATCH";
+ if (qEnvironmentVariableIsSet(skipKey))
+ return;
+ for (int i = 0; i < 5; ++i) {
+ QProcess child;
+ child.setProgram(QCoreApplication::applicationFilePath());
+ child.setArguments(QStringList(testCase));
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(QLatin1String("QT_LOGGING_RULES"), QLatin1String("qt.qml.diskcache.debug=true"));
+ env.insert(QLatin1String(skipKey), QLatin1String("1"));
+ child.setProcessEnvironment(env);
+ child.start();
+ QVERIFY(child.waitForFinished());
+ QCOMPARE(child.exitCode(), 0);
+ QVERIFY(!child.readAllStandardOutput().contains("Checksum mismatch for cached version"));
+ QVERIFY(!child.readAllStandardError().contains("Checksum mismatch for cached version"));
+ }
+#else
+ Q_UNUSED(testCase);
+#endif
+}
+
+void tst_QQMLTypeLoader::multiSingletonModule()
+{
+ qmlClearTypeRegistrations();
+ QQmlEngine engine;
+ engine.addImportPath(testFile("imports"));
+
+ qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton1.qml"), "cppsingletonmodule",
+ 1, 0, "CppRegisteredSingleton1");
+ qmlRegisterSingletonType(testFileUrl("CppRegisteredSingleton2.qml"), "cppsingletonmodule",
+ 1, 0, "CppRegisteredSingleton2");
+
+ QQmlComponent component(&engine, testFileUrl("multisingletonuser.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("ok").toBool());
+
+ checkCleanCacheLoad(QLatin1String("multiSingletonModule"));
+}
+
+void tst_QQMLTypeLoader::implicitComponentModule()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("implicitcomponent.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Ready);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ checkCleanCacheLoad(QLatin1String("implicitComponentModule"));
+}
+
QTEST_MAIN(tst_QQMLTypeLoader)
#include "tst_qqmltypeloader.moc"
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
index 3a20e94741..0352561e03 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.pro
@@ -3,7 +3,12 @@ TARGET = tst_qqmltypeloader
QT += qml testlib qml-private quick
macx:CONFIG -= app_bundle
-SOURCES += tst_qqmltypeloader.cpp
+SOURCES += \
+ tst_qqmltypeloader.cpp \
+ ../../shared/testhttpserver.cpp
+
+HEADERS += \
+ ../../shared/testhttpserver.h
include (../../shared/util.pri)
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
index 1902801c8f..22074602b7 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
+++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
@@ -78,7 +78,7 @@ void tst_qqmlvaluetypeproviders::qtqmlValueTypes()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("qtqmlTypeSuccess").toBool());
QVERIFY(object->property("qtquickTypeSuccess").toBool());
delete object;
@@ -91,7 +91,7 @@ void tst_qqmlvaluetypeproviders::qtquickValueTypes()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("qtqmlTypeSuccess").toBool());
QVERIFY(object->property("qtquickTypeSuccess").toBool());
delete object;
@@ -104,7 +104,7 @@ void tst_qqmlvaluetypeproviders::comparisonSemantics()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("comparisonSuccess").toBool());
delete object;
}
@@ -116,7 +116,7 @@ void tst_qqmlvaluetypeproviders::cppIntegration()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
// ensure accessing / comparing / assigning cpp-defined props
// and qml-defined props works in QML.
@@ -156,7 +156,7 @@ void tst_qqmlvaluetypeproviders::jsObjectConversion()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("qtquickTypeSuccess").toBool());
delete object;
}
@@ -168,7 +168,7 @@ void tst_qqmlvaluetypeproviders::invokableFunctions()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("complete").toBool());
QVERIFY(object->property("success").toBool());
delete object;
@@ -233,7 +233,7 @@ public:
if (type == qMetaTypeId<TestValue>())
return &TestValueType::staticMetaObject;
- return 0;
+ return nullptr;
}
};
@@ -284,7 +284,7 @@ void tst_qqmlvaluetypeproviders::userType()
QQmlComponent component(&e, testFileUrl("userType.qml"));
QScopedPointer<QObject> obj(component.create());
- QVERIFY(obj != 0);
+ QVERIFY(obj != nullptr);
QCOMPARE(obj->property("success").toBool(), true);
}
@@ -295,7 +295,7 @@ void tst_qqmlvaluetypeproviders::changedSignal()
QVERIFY(!component.isError());
QVERIFY(component.errors().isEmpty());
QScopedPointer<QObject> object(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("complete").toBool());
QVERIFY(object->property("success").toBool());
}
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index 163ce11cb8..8a01524b5b 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -89,6 +89,8 @@ private slots:
void customValueType();
void customValueTypeInQml();
void gadgetInheritance();
+ void gadgetTemplateInheritance();
+ void sequences();
void toStringConversion();
void enumerableProperties();
void enumProperties();
@@ -108,7 +110,7 @@ void tst_qqmlvaluetypes::point()
{
QQmlComponent component(&engine, testFileUrl("point_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("p_x").toInt(), 10);
QCOMPARE(object->property("p_y").toInt(), 4);
@@ -120,7 +122,7 @@ void tst_qqmlvaluetypes::point()
{
QQmlComponent component(&engine, testFileUrl("point_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->point(), QPoint(11, 12));
@@ -130,7 +132,7 @@ void tst_qqmlvaluetypes::point()
{
QQmlComponent component(&engine, testFileUrl("point_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QPoint(10, 4)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -153,7 +155,7 @@ void tst_qqmlvaluetypes::pointf()
{
QQmlComponent component(&engine, testFileUrl("pointf_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(float(object->property("p_x").toDouble()), float(11.3));
QCOMPARE(float(object->property("p_y").toDouble()), float(-10.9));
@@ -165,7 +167,7 @@ void tst_qqmlvaluetypes::pointf()
{
QQmlComponent component(&engine, testFileUrl("pointf_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->pointf(), QPointF(6.8, 9.3));
@@ -175,7 +177,7 @@ void tst_qqmlvaluetypes::pointf()
{
QQmlComponent component(&engine, testFileUrl("pointf_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QPointF(11.3, -10.9)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -198,7 +200,7 @@ void tst_qqmlvaluetypes::size()
{
QQmlComponent component(&engine, testFileUrl("size_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("s_width").toInt(), 1912);
QCOMPARE(object->property("s_height").toInt(), 1913);
@@ -210,7 +212,7 @@ void tst_qqmlvaluetypes::size()
{
QQmlComponent component(&engine, testFileUrl("size_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->size(), QSize(13, 88));
@@ -220,7 +222,7 @@ void tst_qqmlvaluetypes::size()
{
QQmlComponent component(&engine, testFileUrl("size_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QSize(1912, 1913)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -243,7 +245,7 @@ void tst_qqmlvaluetypes::sizef()
{
QQmlComponent component(&engine, testFileUrl("sizef_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(float(object->property("s_width").toDouble()), float(0.1));
QCOMPARE(float(object->property("s_height").toDouble()), float(100923.2));
@@ -255,7 +257,7 @@ void tst_qqmlvaluetypes::sizef()
{
QQmlComponent component(&engine, testFileUrl("sizef_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->sizef(), QSizeF(44.3, 92.8));
@@ -265,7 +267,7 @@ void tst_qqmlvaluetypes::sizef()
{
QQmlComponent component(&engine, testFileUrl("sizef_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QSizeF(0.1, 100923)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -288,7 +290,7 @@ void tst_qqmlvaluetypes::variant()
{
QQmlComponent component(&engine, testFileUrl("variant_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(float(object->property("s_width").toDouble()), float(0.1));
QCOMPARE(float(object->property("s_height").toDouble()), float(100923.2));
@@ -300,7 +302,7 @@ void tst_qqmlvaluetypes::variant()
{
QQmlComponent component(&engine, testFileUrl("variant_write.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("complete").toBool());
QVERIFY(object->property("success").toBool());
delete object;
@@ -309,7 +311,7 @@ void tst_qqmlvaluetypes::variant()
{
QQmlComponent component(&engine, testFileUrl("variant_write.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("complete").toBool());
QVERIFY(object->property("success").toBool());
delete object;
@@ -359,7 +361,7 @@ void tst_qqmlvaluetypes::sizereadonly()
{
QQmlComponent component(&engine, testFileUrl("sizereadonly_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("s_width").toInt(), 1912);
QCOMPARE(object->property("s_height").toInt(), 1913);
@@ -403,7 +405,7 @@ void tst_qqmlvaluetypes::rect()
{
QQmlComponent component(&engine, testFileUrl("rect_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("r_x").toInt(), 2);
QCOMPARE(object->property("r_y").toInt(), 3);
@@ -421,7 +423,7 @@ void tst_qqmlvaluetypes::rect()
{
QQmlComponent component(&engine, testFileUrl("rect_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect(), QRect(1234, 7, 56, 63));
@@ -431,7 +433,7 @@ void tst_qqmlvaluetypes::rect()
{
QQmlComponent component(&engine, testFileUrl("rect_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QRect(2, 3, 109, 102)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -454,7 +456,7 @@ void tst_qqmlvaluetypes::rectf()
{
QQmlComponent component(&engine, testFileUrl("rectf_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(float(object->property("r_x").toDouble()), float(103.8));
QCOMPARE(float(object->property("r_y").toDouble()), float(99.2));
@@ -472,7 +474,7 @@ void tst_qqmlvaluetypes::rectf()
{
QQmlComponent component(&engine, testFileUrl("rectf_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rectf(), QRectF(70.1, -113.2, 80924.8, 99.2));
@@ -482,7 +484,7 @@ void tst_qqmlvaluetypes::rectf()
{
QQmlComponent component(&engine, testFileUrl("rectf_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QRectF(103.8, 99.2, 88.1, 77.6)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -505,7 +507,7 @@ void tst_qqmlvaluetypes::vector2d()
{
QQmlComponent component(&engine, testFileUrl("vector2d_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_x").toDouble(), (float)32.88);
QCOMPARE((float)object->property("v_y").toDouble(), (float)1.3);
@@ -517,7 +519,7 @@ void tst_qqmlvaluetypes::vector2d()
{
QQmlComponent component(&engine, testFileUrl("vector2d_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->vector2(), QVector2D(-0.3f, -12.9f));
@@ -527,7 +529,7 @@ void tst_qqmlvaluetypes::vector2d()
{
QQmlComponent component(&engine, testFileUrl("vector2d_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QVector2D(32.88, 1.3)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -545,7 +547,7 @@ void tst_qqmlvaluetypes::vector2d()
{
QQmlComponent component(&engine, testFileUrl("vector2d_invokables.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
}
@@ -556,7 +558,7 @@ void tst_qqmlvaluetypes::vector3d()
{
QQmlComponent component(&engine, testFileUrl("vector3d_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_x").toDouble(), (float)23.88);
QCOMPARE((float)object->property("v_y").toDouble(), (float)3.1);
@@ -569,7 +571,7 @@ void tst_qqmlvaluetypes::vector3d()
{
QQmlComponent component(&engine, testFileUrl("vector3d_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->vector(), QVector3D(-0.3f, -12.9f, 907.4f));
@@ -579,7 +581,7 @@ void tst_qqmlvaluetypes::vector3d()
{
QQmlComponent component(&engine, testFileUrl("vector3d_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QVector3D(23.88, 3.1, 4.3)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -598,7 +600,7 @@ void tst_qqmlvaluetypes::vector3d()
{
QQmlComponent component(&engine, testFileUrl("vector3d_invokables.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
}
@@ -609,7 +611,7 @@ void tst_qqmlvaluetypes::vector4d()
{
QQmlComponent component(&engine, testFileUrl("vector4d_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_x").toDouble(), (float)54.2);
QCOMPARE((float)object->property("v_y").toDouble(), (float)23.88);
@@ -623,7 +625,7 @@ void tst_qqmlvaluetypes::vector4d()
{
QQmlComponent component(&engine, testFileUrl("vector4d_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->vector4(), QVector4D(-0.3f, -12.9f, 907.4f, 88.5f));
@@ -633,7 +635,7 @@ void tst_qqmlvaluetypes::vector4d()
{
QQmlComponent component(&engine, testFileUrl("vector4d_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QVector4D(54.2, 23.88, 3.1, 4.3)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -651,7 +653,7 @@ void tst_qqmlvaluetypes::vector4d()
{
QQmlComponent component(&engine, testFileUrl("vector4d_invokables.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
}
@@ -662,7 +664,7 @@ void tst_qqmlvaluetypes::quaternion()
{
QQmlComponent component(&engine, testFileUrl("quaternion_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_scalar").toDouble(), (float)4.3);
QCOMPARE((float)object->property("v_x").toDouble(), (float)54.2);
@@ -676,7 +678,7 @@ void tst_qqmlvaluetypes::quaternion()
{
QQmlComponent component(&engine, testFileUrl("quaternion_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->quaternion(), QQuaternion(88.5f, -0.3f, -12.9f, 907.4f));
@@ -686,7 +688,7 @@ void tst_qqmlvaluetypes::quaternion()
{
QQmlComponent component(&engine, testFileUrl("quaternion_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QQuaternion(4.3, 54.2, 23.88, 3.1)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -707,7 +709,7 @@ void tst_qqmlvaluetypes::matrix4x4()
{
QQmlComponent component(&engine, testFileUrl("matrix4x4_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_m11").toDouble(), (float)1);
QCOMPARE((float)object->property("v_m12").toDouble(), (float)2);
@@ -737,7 +739,7 @@ void tst_qqmlvaluetypes::matrix4x4()
{
QQmlComponent component(&engine, testFileUrl("matrix4x4_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->matrix(), QMatrix4x4(11, 12, 13, 14,
21, 22, 23, 24,
@@ -750,7 +752,7 @@ void tst_qqmlvaluetypes::matrix4x4()
{
QQmlComponent component(&engine, testFileUrl("matrix4x4_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QMatrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)");
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -768,7 +770,7 @@ void tst_qqmlvaluetypes::matrix4x4()
{
QQmlComponent component(&engine, testFileUrl("matrix4x4_invokables.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
delete object;
}
@@ -779,7 +781,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("f_family").toString(), object->font().family());
QCOMPARE(object->property("f_bold").toBool(), object->font().bold());
@@ -802,7 +804,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QFont font;
font.setFamily("Helvetica");
@@ -835,7 +837,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_write.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().pixelSize(), 10);
@@ -847,7 +849,7 @@ void tst_qqmlvaluetypes::font()
QQmlComponent component(&engine, testFileUrl("font_write.3.qml"));
QTest::ignoreMessage(QtWarningMsg, "Both point size and pixel size set. Using pixel size.");
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().pixelSize(), 10);
@@ -857,7 +859,7 @@ void tst_qqmlvaluetypes::font()
QQmlComponent component(&engine, testFileUrl("font_write.4.qml"));
QTest::ignoreMessage(QtWarningMsg, "Both point size and pixel size set. Using pixel size.");
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().pixelSize(), 10);
@@ -866,11 +868,11 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_write.5.qml"));
QObject *object = qobject_cast<QObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
MyTypeObject *object1 = object->findChild<MyTypeObject *>("object1");
- QVERIFY(object1 != 0);
+ QVERIFY(object1 != nullptr);
MyTypeObject *object2 = object->findChild<MyTypeObject *>("object2");
- QVERIFY(object2 != 0);
+ QVERIFY(object2 != nullptr);
QCOMPARE(object1->font().pixelSize(), 19);
QCOMPARE(object2->font().pointSize(), 14);
@@ -881,7 +883,7 @@ void tst_qqmlvaluetypes::font()
{
QQmlComponent component(&engine, testFileUrl("font_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString tostring = QLatin1String("QFont(") + object->font().toString() + QLatin1Char(')');
QCOMPARE(object->property("tostring").toString(), tostring);
@@ -902,7 +904,7 @@ void tst_qqmlvaluetypes::color()
{
QQmlComponent component(&engine, testFileUrl("color_read.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE((float)object->property("v_r").toDouble(), (float)0.2);
QCOMPARE((float)object->property("v_g").toDouble(), (float)0.88);
@@ -930,7 +932,7 @@ void tst_qqmlvaluetypes::color()
{
QQmlComponent component(&engine, testFileUrl("color_write.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QColor newColor;
newColor.setRedF(0.5);
@@ -945,7 +947,7 @@ void tst_qqmlvaluetypes::color()
{
QQmlComponent component(&engine, testFileUrl("color_write_HSV.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QColor newColor;
newColor.setHsvF(0.43, 0.77, 0.88, 0.7);
@@ -957,7 +959,7 @@ void tst_qqmlvaluetypes::color()
{
QQmlComponent component(&engine, testFileUrl("color_write_HSL.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QColor newColor;
newColor.setHslF(0.43, 0.74, 0.54, 0.7);
@@ -969,7 +971,7 @@ void tst_qqmlvaluetypes::color()
{
QQmlComponent component(&engine, testFileUrl("color_compare.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QString colorString("#5733e199");
QCOMPARE(object->property("colorToString").toString(), colorString);
QCOMPARE(object->property("colorEqualsIdenticalRgba").toBool(), true);
@@ -1004,7 +1006,7 @@ void tst_qqmlvaluetypes::bindingAssignment()
{
QQmlComponent component(&engine, testFileUrl("bindingAssignment.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 10);
QCOMPARE(object->rect().y(), 15);
@@ -1019,13 +1021,13 @@ void tst_qqmlvaluetypes::bindingAssignment()
// function assignment should fail without crashing
{
- QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6:13: Invalid use of Qt.binding() in a binding declaration.");
+ QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6:5: Invalid use of Qt.binding() in a binding declaration.");
QString warning2 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":10: Cannot assign JavaScript function to value-type property");
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QQmlComponent component(&engine, testFileUrl("bindingAssignment.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 5);
object->setProperty("value", QVariant(92));
QCOMPARE(object->rect().x(), 5);
@@ -1038,7 +1040,7 @@ void tst_qqmlvaluetypes::bindingRead()
{
QQmlComponent component(&engine, testFileUrl("bindingRead.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 2);
@@ -1054,7 +1056,7 @@ void tst_qqmlvaluetypes::staticAssignment()
{
QQmlComponent component(&engine, testFileUrl("staticAssignment.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 9);
@@ -1066,7 +1068,7 @@ void tst_qqmlvaluetypes::scriptAccess()
{
QQmlComponent component(&engine, testFileUrl("scriptAccess.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("valuePre").toInt(), 2);
QCOMPARE(object->rect().x(), 19);
@@ -1081,7 +1083,7 @@ void tst_qqmlvaluetypes::autoBindingRemoval()
{
QQmlComponent component(&engine, testFileUrl("autoBindingRemoval.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 10);
@@ -1103,7 +1105,7 @@ void tst_qqmlvaluetypes::autoBindingRemoval()
{
QQmlComponent component(&engine, testFileUrl("autoBindingRemoval.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 10);
@@ -1124,10 +1126,10 @@ void tst_qqmlvaluetypes::autoBindingRemoval()
{
QQmlComponent component(&engine, testFileUrl("autoBindingRemoval.3.qml"));
- QString warning = component.url().toString() + ":6:11: Unable to assign [undefined] to QRect";
+ QString warning = component.url().toString() + ":6:5: Unable to assign [undefined] to QRect";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
object->setProperty("value", QVariant(QRect(9, 22, 33, 44)));
@@ -1150,7 +1152,7 @@ void tst_qqmlvaluetypes::valueSources()
{
QQmlComponent component(&engine, testFileUrl("valueSources.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 3345);
@@ -1174,7 +1176,7 @@ void tst_qqmlvaluetypes::valueInterceptors()
QQmlComponent component(&engine, testFileUrl("valueInterceptors.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
checkNoErrors(component);
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect().x(), 13);
@@ -1208,10 +1210,10 @@ void tst_qqmlvaluetypes::deletedObject()
QQmlComponent component(&engine, testFileUrl("deletedObject.qml"));
QTest::ignoreMessage(QtDebugMsg, "Test: 2");
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QObject *dObject = qvariant_cast<QObject *>(object->property("object"));
- QVERIFY(dObject != 0);
+ QVERIFY(dObject != nullptr);
delete dObject;
QTest::ignoreMessage(QtDebugMsg, "Test: undefined");
@@ -1225,7 +1227,7 @@ void tst_qqmlvaluetypes::bindingVariantCopy()
{
QQmlComponent component(&engine, testFileUrl("bindingVariantCopy.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect(), QRect(19, 33, 5, 99));
@@ -1237,7 +1239,7 @@ void tst_qqmlvaluetypes::scriptVariantCopy()
{
QQmlComponent component(&engine, testFileUrl("scriptVariantCopy.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->rect(), QRect(2, 3, 109, 102));
@@ -1253,7 +1255,7 @@ void tst_qqmlvaluetypes::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.1.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().capitalization(), QFont::AllUppercase);
delete object;
}
@@ -1261,7 +1263,7 @@ void tst_qqmlvaluetypes::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().capitalization(), QFont::AllUppercase);
delete object;
}
@@ -1269,7 +1271,7 @@ void tst_qqmlvaluetypes::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.3.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().capitalization(), QFont::AllUppercase);
delete object;
}
@@ -1277,7 +1279,7 @@ void tst_qqmlvaluetypes::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.4.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().capitalization(), QFont::AllUppercase);
delete object;
}
@@ -1285,7 +1287,7 @@ void tst_qqmlvaluetypes::enums()
{
QQmlComponent component(&engine, testFileUrl("enums.5.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->font().capitalization(), QFont::AllUppercase);
delete object;
}
@@ -1298,7 +1300,7 @@ void tst_qqmlvaluetypes::conflictingBindings()
{
QQmlComponent component(&engine, testFileUrl("conflicting.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QFont>(object->property("font")).pixelSize(), 12);
@@ -1316,7 +1318,7 @@ void tst_qqmlvaluetypes::conflictingBindings()
{
QQmlComponent component(&engine, testFileUrl("conflicting.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QFont>(object->property("font")).pixelSize(), 6);
@@ -1334,7 +1336,7 @@ void tst_qqmlvaluetypes::conflictingBindings()
{
QQmlComponent component(&engine, testFileUrl("conflicting.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(qvariant_cast<QFont>(object->property("font")).pixelSize(), 12);
@@ -1354,7 +1356,7 @@ void tst_qqmlvaluetypes::returnValues()
{
QQmlComponent component(&engine, testFileUrl("returnValues.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -1367,7 +1369,7 @@ void tst_qqmlvaluetypes::varAssignment()
{
QQmlComponent component(&engine, testFileUrl("varAssignment.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("x").toInt(), 1);
QCOMPARE(object->property("y").toInt(), 2);
@@ -1382,7 +1384,7 @@ void tst_qqmlvaluetypes::bindingsSpliceCorrectly()
{
QQmlComponent component(&engine, testFileUrl("bindingsSpliceCorrectly.1.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1392,7 +1394,7 @@ void tst_qqmlvaluetypes::bindingsSpliceCorrectly()
{
QQmlComponent component(&engine, testFileUrl("bindingsSpliceCorrectly.2.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1403,7 +1405,7 @@ void tst_qqmlvaluetypes::bindingsSpliceCorrectly()
{
QQmlComponent component(&engine, testFileUrl("bindingsSpliceCorrectly.3.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1413,7 +1415,7 @@ void tst_qqmlvaluetypes::bindingsSpliceCorrectly()
{
QQmlComponent component(&engine, testFileUrl("bindingsSpliceCorrectly.4.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1423,7 +1425,7 @@ void tst_qqmlvaluetypes::bindingsSpliceCorrectly()
{
QQmlComponent component(&engine, testFileUrl("bindingsSpliceCorrectly.5.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1435,7 +1437,7 @@ void tst_qqmlvaluetypes::nonValueTypeComparison()
{
QQmlComponent component(&engine, testFileUrl("nonValueTypeComparison.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test1").toBool(), true);
QCOMPARE(object->property("test2").toBool(), true);
@@ -1447,7 +1449,7 @@ void tst_qqmlvaluetypes::initializeByWrite()
{
QQmlComponent component(&engine, testFileUrl("initializeByWrite.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(), true);
@@ -1486,7 +1488,7 @@ void tst_qqmlvaluetypes::groupedInterceptors()
QQmlComponent component(&engine, testFileUrl(qmlfile));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY2(object != nullptr, qPrintable(component.errorString()));
QColor initialColor = object->property("color").value<QColor>();
QVERIFY(fuzzyCompare(initialColor.redF(), expectedInitialColor.redF()));
@@ -1589,6 +1591,7 @@ struct BaseGadget
Q_PROPERTY(int baseProperty READ baseProperty WRITE setBaseProperty)
public:
BaseGadget() : m_baseProperty(0) {}
+ BaseGadget(int initValue) : m_baseProperty(initValue) {}
int baseProperty() const { return m_baseProperty; }
void setBaseProperty(int value) { m_baseProperty = value; }
@@ -1613,6 +1616,19 @@ public:
Q_INVOKABLE void functionInDerivedGadget(int value) { m_derivedProperty = value; }
};
+// QTBUG-66744: we want a Q_GADGET giving us generic type safety in C++ and property access in Qml
+template <typename T>
+struct DerivedTypedGadget : public BaseGadget
+{
+ // cannot use Q_GADGET here
+public:
+ DerivedTypedGadget() {}
+};
+
+class DerivedTypedGadgetDummyType {};
+
+Q_DECLARE_METATYPE(DerivedTypedGadget<DerivedTypedGadgetDummyType>)
+
class TypeWithCustomValueType : public QObject
{
Q_OBJECT
@@ -1657,6 +1673,62 @@ void tst_qqmlvaluetypes::gadgetInheritance()
QCOMPARE(value.property("baseProperty").toInt(), 42);
}
+void tst_qqmlvaluetypes::gadgetTemplateInheritance()
+{
+ QJSEngine engine;
+
+ QJSValue value = engine.toScriptValue(DerivedTypedGadget<DerivedTypedGadgetDummyType>());
+
+ QCOMPARE(value.property("baseProperty").toInt(), 0);
+ value.setProperty("baseProperty", 10);
+ QCOMPARE(value.property("baseProperty").toInt(), 10);
+
+ QJSValue method = value.property("functionInBaseGadget");
+ method.call(QJSValueList() << QJSValue(42));
+ QCOMPARE(value.property("baseProperty").toInt(), 42);
+}
+
+void tst_qqmlvaluetypes::sequences()
+{
+ QJSEngine engine;
+ {
+ QList<BaseGadget> gadgetList{1, 4, 7, 8, 15};
+ QJSValue value = engine.toScriptValue(gadgetList);
+ QCOMPARE(value.property("length").toInt(), gadgetList.length());
+ for (int i = 0; i < gadgetList.length(); ++i)
+ QCOMPARE(value.property(i).property("baseProperty").toInt(), gadgetList.at(i).baseProperty());
+ }
+ {
+ std::vector<BaseGadget> container{1, 4, 7, 8, 15};
+ QJSValue value = engine.toScriptValue(container);
+ QCOMPARE(value.property("length").toInt(), int(container.size()));
+ for (size_t i = 0; i < container.size(); ++i)
+ QCOMPARE(value.property(i).property("baseProperty").toInt(), container.at(i).baseProperty());
+ }
+ {
+ QVector<QChar> qcharVector{1, 4, 42, 8, 15};
+ QJSValue value = engine.toScriptValue(qcharVector);
+ QCOMPARE(value.property("length").toInt(), qcharVector.length());
+ for (int i = 0; i < qcharVector.length(); ++i)
+ QCOMPARE(value.property(i).toString(), qcharVector.at(i));
+ }
+ {
+ MyTypeObject a, b, c;
+ QSet<QObject*> objSet{&a, &b, &c};
+ QJSValue value = engine.toScriptValue(objSet);
+ QCOMPARE(value.property("length").toInt(), objSet.size());
+ for (int i = 0; i < objSet.size(); ++i)
+ QCOMPARE(value.property(i).property("point").property("x").toInt(), a.point().x());
+ }
+ {
+ MyTypeObject a, b, c;
+ QSet<MyTypeObject*> container{&a, &b, &c};
+ QJSValue value = engine.toScriptValue(container);
+ QCOMPARE(value.property("length").toInt(), container.size());
+ for (int i = 0; i < container.size(); ++i)
+ QCOMPARE(value.property(i).property("point").property("x").toInt(), a.point().x());
+ }
+}
struct StringLessGadget {
Q_GADGET
};
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js
new file mode 100644
index 0000000000..adb7269310
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js
@@ -0,0 +1,11 @@
+(function(url, resultCollector) {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+ x.setRequestHeader("Accept-Language","en-US");
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ resultCollector.responseText = x.responseText
+ }
+ }
+ x.send()
+})
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect
new file mode 100644
index 0000000000..6d34e1d2bb
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect
Binary files differ
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml
new file mode 100644
index 0000000000..ba9761201e
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+QtObject {
+ property string url
+
+ property bool dataOK: false
+
+ Component.onCompleted: {
+ var x = new XMLHttpRequest;
+ x.open("POST", url);
+ x.setRequestHeader("Accept-Language","en-US");
+
+ // Test to the end
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ dataOK = (x.responseText == "QML Rocks!\n");
+ }
+ }
+
+ var data = new Uint8Array([1, 2, 3, 0, 3, 2, 1])
+ x.send(data.buffer);
+ }
+}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/status.qml b/tests/auto/qml/qqmlxmlhttprequest/data/status.qml
index 22c45c099d..94908f63c0 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/data/status.qml
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/status.qml
@@ -11,6 +11,9 @@ QtObject {
property bool headersReceived: false
property bool loading: false
property bool done: false
+ property bool onloadCalled: false
+ property bool onerrorCalled: false
+ property bool onloadendCalled: false
property bool resetException: false
@@ -62,6 +65,16 @@ QtObject {
}
}
+ x.onload = function() {
+ // test also that it was called after onreadystatechanged(DONE)
+ onloadCalled = (done === true) && (onerrorCalled === false);
+ }
+ x.onloadend = function() {
+ onloadendCalled = (done === true) && (onloadCalled === true || onerrorCalled === true);
+ }
+ x.onerror = function() {
+ onerrorCalled = (done === true) && (onloadCalled === false);
+ }
x.send()
diff --git a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
index 44b2963918..572ab1d572 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
+++ b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro
@@ -2,7 +2,6 @@ CONFIG += testcase
TARGET = tst_qqmlxmlhttprequest
macx:CONFIG -= app_bundle
-INCLUDEPATH += ../../shared/
HEADERS += ../../shared/testhttpserver.h
SOURCES += tst_qqmlxmlhttprequest.cpp \
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 1ce07ecdab..6cf80ccfdb 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -108,6 +108,8 @@ private slots:
void text();
void cdata();
+ void noQmlContext();
+
// Crashes
// void outstanding_request_at_shutdown();
@@ -291,7 +293,7 @@ class TestThreadedHTTPServer : public QObject
Q_OBJECT
public:
TestThreadedHTTPServer(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl)
- : m_server(Q_NULLPTR) {
+ : m_server(nullptr) {
QMutexLocker locker(&m_lock);
moveToThread(&m_thread);
m_thread.start();
@@ -597,6 +599,7 @@ void tst_qqmlxmlhttprequest::send_withdata_data()
QTest::newRow("Incorrect content-type - out of order") << "send_data.4.expect" << "send_data.5.qml";
QTest::newRow("PUT") << "send_data.6.expect" << "send_data.6.qml";
QTest::newRow("Correct content-type - no charset") << "send_data.1.expect" << "send_data.7.qml";
+ QTest::newRow("ArrayBuffer") << "send_data.11.expect" << "send_data.11.qml";
}
void tst_qqmlxmlhttprequest::send_options()
@@ -914,6 +917,9 @@ void tst_qqmlxmlhttprequest::status()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
+ QCOMPARE(object->property("onloadCalled").toBool(), true);
+ QCOMPARE(object->property("onloadendCalled").toBool(), true);
+ QCOMPARE(object->property("onerrorCalled").toBool(), false);
}
void tst_qqmlxmlhttprequest::status_data()
@@ -1242,6 +1248,30 @@ void tst_qqmlxmlhttprequest::cdata()
QCOMPARE(object->property("status").toInt(), 200);
}
+void tst_qqmlxmlhttprequest::noQmlContext()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ QVERIFY(server.wait(testFileUrl("open_network.expect"),
+ testFileUrl("open_network.reply"),
+ testFileUrl("testdocument.html")));
+ QUrl url = server.urlString(QStringLiteral("/testdocument.html"));
+
+ QQmlEngine engine;
+
+ QFile f(testFile("noqmlcontext.js"));
+ QVERIFY(f.open(QIODevice::ReadOnly));
+ QString script = QString::fromUtf8(f.readAll());
+ QJSValue testFunction = engine.evaluate(script);
+ QVERIFY(testFunction.isCallable());
+
+ QJSValue resultCollector = engine.newObject();
+
+ testFunction.call(QJSValueList() << url.toString() << resultCollector);
+
+ QTRY_COMPARE(resultCollector.property("responseText").toString(), "QML Rocks!\n");
+ }
+
void tst_qqmlxmlhttprequest::stateChangeCallingContext()
{
#ifdef Q_OS_WIN
diff --git a/tests/auto/qml/qquickfolderlistmodel/data/sortdir/Uppercase.txt b/tests/auto/qml/qquickfolderlistmodel/data/sortdir/Uppercase.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qml/qquickfolderlistmodel/data/sortdir/Uppercase.txt
diff --git a/tests/auto/qml/qquickfolderlistmodel/data/sortdir/lowercase.txt b/tests/auto/qml/qquickfolderlistmodel/data/sortdir/lowercase.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qml/qquickfolderlistmodel/data/sortdir/lowercase.txt
diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
index f19e82032a..4b2ae45bae 100644
--- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
+++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp
@@ -42,12 +42,13 @@
// From qquickfolderlistmodel.h
const int FileNameRole = Qt::UserRole+1;
enum SortField { Unsorted, Name, Time, Size, Type };
+enum Status { Null, Ready, Loading };
class tst_qquickfolderlistmodel : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickfolderlistmodel() : removeStart(0), removeEnd(0) {}
+ tst_qquickfolderlistmodel() {}
public slots:
void removed(const QModelIndex &, int start, int end) {
@@ -58,6 +59,7 @@ public slots:
private slots:
void initTestCase();
void basicProperties();
+ void status();
void showFiles();
void resetFiltering();
void nameFilters();
@@ -71,13 +73,14 @@ private slots:
void showDotAndDotDot_data();
void sortReversed();
void introspectQrc();
-
+ void sortCaseSensitive_data();
+ void sortCaseSensitive();
private:
void checkNoErrors(const QQmlComponent& component);
QQmlEngine engine;
- int removeStart;
- int removeEnd;
+ int removeStart = 0;
+ int removeEnd = 0;
};
void tst_qquickfolderlistmodel::checkNoErrors(const QQmlComponent& component)
@@ -113,7 +116,7 @@ void tst_qquickfolderlistmodel::basicProperties()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
QCOMPARE(flm->property("nameFilters").toStringList(), QStringList() << "*.qml"); // from basic.qml
QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile(QDir::currentPath()));
@@ -124,7 +127,7 @@ void tst_qquickfolderlistmodel::basicProperties()
QSignalSpy folderChangedSpy(flm, SIGNAL(folderChanged()));
flm->setProperty("folder", dataDirectoryUrl());
QVERIFY(folderChangedSpy.wait());
- QCOMPARE(flm->property("count").toInt(), 8);
+ QCOMPARE(flm->property("count").toInt(), 9);
QCOMPARE(flm->property("folder").toUrl(), dataDirectoryUrl());
QCOMPARE(flm->property("parentFolder").toUrl(), QUrl::fromLocalFile(QDir(directory()).canonicalPath()));
QCOMPARE(flm->property("sortField").toInt(), int(Name));
@@ -141,21 +144,35 @@ void tst_qquickfolderlistmodel::basicProperties()
QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile(""));
}
+void tst_qquickfolderlistmodel::status()
+{
+ QQmlComponent component(&engine, testFileUrl("basic.qml"));
+ checkNoErrors(component);
+
+ QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
+ QVERIFY(flm != nullptr);
+ QTRY_COMPARE(flm->property("status").toInt(), int(Ready));
+ flm->setProperty("folder", QUrl::fromLocalFile(""));
+ QTRY_COMPARE(flm->property("status").toInt(), int(Null));
+ flm->setProperty("folder", QUrl::fromLocalFile(QDir::currentPath()));
+ QTRY_COMPARE(flm->property("status").toInt(), int(Ready));
+}
+
void tst_qquickfolderlistmodel::showFiles()
{
QQmlComponent component(&engine, testFileUrl("basic.qml"));
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
flm->setProperty("folder", dataDirectoryUrl());
- QTRY_COMPARE(flm->property("count").toInt(), 8); // wait for refresh
+ QTRY_COMPARE(flm->property("count").toInt(), 9); // wait for refresh
QCOMPARE(flm->property("showFiles").toBool(), true);
flm->setProperty("showFiles", false);
QCOMPARE(flm->property("showFiles").toBool(), false);
- QTRY_COMPARE(flm->property("count").toInt(), 2); // wait for refresh
+ QTRY_COMPARE(flm->property("count").toInt(), 3); // wait for refresh
}
void tst_qquickfolderlistmodel::resetFiltering()
@@ -165,7 +182,7 @@ void tst_qquickfolderlistmodel::resetFiltering()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
flm->setProperty("folder", testFileUrl("resetfiltering"));
// _q_directoryUpdated may be triggered if model was empty before, but there won't be a rowsRemoved signal
@@ -187,7 +204,7 @@ void tst_qquickfolderlistmodel::nameFilters()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
connect(flm, SIGNAL(rowsRemoved(QModelIndex,int,int)),
this, SLOT(removed(QModelIndex,int,int)));
@@ -219,10 +236,10 @@ void tst_qquickfolderlistmodel::refresh()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
flm->setProperty("folder", dataDirectoryUrl());
- QTRY_COMPARE(flm->property("count").toInt(),8); // wait for refresh
+ QTRY_COMPARE(flm->property("count").toInt(), 9); // wait for refresh
int count = flm->rowCount();
@@ -242,7 +259,7 @@ void tst_qquickfolderlistmodel::cdUp()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
const QUrl startFolder = flm->property("folder").toUrl();
QVERIFY(startFolder.isValid());
@@ -320,13 +337,13 @@ void tst_qquickfolderlistmodel::showDotAndDotDot()
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
flm->setProperty("folder", folder);
flm->setProperty("rootFolder", rootFolder);
flm->setProperty("showDotAndDotDot", showDotAndDotDot);
- int count = 9;
+ int count = 10;
if (showDot) count++;
if (showDotDot) count++;
QTRY_COMPARE(flm->property("count").toInt(), count); // wait for refresh
@@ -355,9 +372,9 @@ void tst_qquickfolderlistmodel::sortReversed()
QQmlComponent component(&engine, testFileUrl("sortReversed.qml"));
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
flm->setProperty("folder", dataDirectoryUrl());
- QTRY_COMPARE(flm->property("count").toInt(), 9); // wait for refresh
+ QTRY_COMPARE(flm->property("count").toInt(), 10); // wait for refresh
QCOMPARE(flm->data(flm->index(0),FileNameRole).toString(), QLatin1String("txtdir"));
}
@@ -366,11 +383,41 @@ void tst_qquickfolderlistmodel::introspectQrc()
QQmlComponent component(&engine, testFileUrl("qrc.qml"));
checkNoErrors(component);
QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
- QVERIFY(flm != 0);
+ QVERIFY(flm != nullptr);
QTRY_COMPARE(flm->property("count").toInt(), 1); // wait for refresh
QCOMPARE(flm->data(flm->index(0),FileNameRole).toString(), QLatin1String("hello.txt"));
}
+void tst_qquickfolderlistmodel::sortCaseSensitive_data()
+{
+ QTest::addColumn<bool>("sortCaseSensitive");
+ QTest::addColumn<QStringList>("expectedOrder");
+
+ const QString upperFile = QLatin1String("Uppercase.txt");
+ const QString lowerFile = QLatin1String("lowercase.txt");
+
+ QTest::newRow("caseSensitive") << true << (QStringList() << upperFile << lowerFile);
+ QTest::newRow("caseInsensitive") << false << (QStringList() << lowerFile << upperFile);
+}
+
+void tst_qquickfolderlistmodel::sortCaseSensitive()
+{
+ QFETCH(bool, sortCaseSensitive);
+ QFETCH(QStringList, expectedOrder);
+ QQmlComponent component(&engine);
+ component.setData("import Qt.labs.folderlistmodel 1.0\n"
+ "FolderListModel { }", QUrl());
+ checkNoErrors(component);
+
+ QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create());
+ QVERIFY(flm != 0);
+ flm->setProperty("folder", QUrl::fromLocalFile(dataDirectoryUrl().path() + QLatin1String("/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));
+}
+
QTEST_MAIN(tst_qquickfolderlistmodel)
#include "tst_qquickfolderlistmodel.moc"
diff --git a/tests/auto/qml/qquickworkerscript/data/messagehandler.mjs b/tests/auto/qml/qquickworkerscript/data/messagehandler.mjs
new file mode 100644
index 0000000000..749ff561da
--- /dev/null
+++ b/tests/auto/qml/qquickworkerscript/data/messagehandler.mjs
@@ -0,0 +1,4 @@
+
+export function messageHandler(msg) {
+ WorkerScript.sendMessage("Hello from the module")
+}
diff --git a/tests/auto/qml/qquickworkerscript/data/script_global.js b/tests/auto/qml/qquickworkerscript/data/script_global.js
deleted file mode 100644
index cce4f2ceca..0000000000
--- a/tests/auto/qml/qquickworkerscript/data/script_global.js
+++ /dev/null
@@ -1,5 +0,0 @@
-WorkerScript.onMessage = function(msg) {
- world = "World"
- WorkerScript.sendMessage(msg + " " + world)
-}
-
diff --git a/tests/auto/qml/qquickworkerscript/data/script_global2.js b/tests/auto/qml/qquickworkerscript/data/script_global2.js
deleted file mode 100644
index 0867f7ee76..0000000000
--- a/tests/auto/qml/qquickworkerscript/data/script_global2.js
+++ /dev/null
@@ -1,6 +0,0 @@
-world = "World"
-
-WorkerScript.onMessage = function(msg) {
- WorkerScript.sendMessage(msg + " " + world)
-}
-
diff --git a/tests/auto/qml/qquickworkerscript/data/script_module.mjs b/tests/auto/qml/qquickworkerscript/data/script_module.mjs
new file mode 100644
index 0000000000..eaa191c5a7
--- /dev/null
+++ b/tests/auto/qml/qquickworkerscript/data/script_module.mjs
@@ -0,0 +1,5 @@
+
+import { messageHandler as handler } from "./messagehandler.mjs";
+
+WorkerScript.onMessage = handler
+
diff --git a/tests/auto/qml/qquickworkerscript/data/worker_global.qml b/tests/auto/qml/qquickworkerscript/data/worker_global.qml
deleted file mode 100644
index 546afd2f39..0000000000
--- a/tests/auto/qml/qquickworkerscript/data/worker_global.qml
+++ /dev/null
@@ -1,5 +0,0 @@
-import QtQuick 2.0
-
-BaseWorker {
- source: "script_global.js"
-}
diff --git a/tests/auto/qml/qquickworkerscript/data/worker_global2.qml b/tests/auto/qml/qquickworkerscript/data/worker_global2.qml
deleted file mode 100644
index 42cad3852b..0000000000
--- a/tests/auto/qml/qquickworkerscript/data/worker_global2.qml
+++ /dev/null
@@ -1,5 +0,0 @@
-import QtQuick 2.0
-
-BaseWorker {
- source: "script_global2.js"
-}
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index 49135ca920..dfaeca67f1 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>
@@ -57,7 +58,6 @@ private slots:
void scriptError_onCall();
void script_function();
void script_var();
- void script_global();
void stressDispose();
private:
@@ -78,24 +78,30 @@ private:
void tst_QQuickWorkerScript::source()
{
QQmlComponent component(&m_engine, testFileUrl("worker.qml"));
- QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QScopedPointer<QQuickWorkerScript>worker(qobject_cast<QQuickWorkerScript*>(component.create()));
+ QVERIFY(worker != nullptr);
const QMetaObject *mo = worker->metaObject();
QVariant value(100);
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value)));
- waitForEchoMessage(worker);
- QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>(), value);
+ QVERIFY(QMetaObject::invokeMethod(worker.data(), "testSend", Q_ARG(QVariant, value)));
+ waitForEchoMessage(worker.data());
+ QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker.data()).value<QVariant>(), value);
QUrl source = testFileUrl("script_fixed_return.js");
worker->setSource(source);
QCOMPARE(worker->source(), source);
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value)));
- waitForEchoMessage(worker);
- QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>(), qVariantFromValue(QString("Hello_World")));
+ 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")));
+
+ 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")));
qApp->processEvents();
- delete worker;
}
void tst_QQuickWorkerScript::messaging()
@@ -104,7 +110,7 @@ void tst_QQuickWorkerScript::messaging()
QQmlComponent component(&m_engine, testFileUrl("worker.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value)));
waitForEchoMessage(worker);
@@ -113,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;
@@ -130,10 +147,10 @@ void tst_QQuickWorkerScript::messaging_data()
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("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive,
+ QRegExp::RegExp2));
+ QTest::newRow("regularexpression") << qVariantFromValue(QRegularExpression(
+ "^\\d\\d?$", QRegularExpression::CaseInsensitiveOption));
}
void tst_QQuickWorkerScript::messaging_sendQObjectList()
@@ -144,7 +161,7 @@ void tst_QQuickWorkerScript::messaging_sendQObjectList()
QQmlComponent component(&m_engine, testFileUrl("worker.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QVariantList objects;
for (int i=0; i<3; i++)
@@ -165,7 +182,7 @@ void tst_QQuickWorkerScript::messaging_sendJsObject()
{
QQmlComponent component(&m_engine, testFileUrl("worker.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
// Properties are in alphabetical order to enable string-based comparison after
// QVariant roundtrip, since the properties will be stored in a QVariantMap.
@@ -204,7 +221,7 @@ void tst_QQuickWorkerScript::script_with_pragma()
QQmlComponent component(&m_engine, testFileUrl("worker_pragma.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value)));
waitForEchoMessage(worker);
@@ -220,7 +237,7 @@ void tst_QQuickWorkerScript::script_included()
{
QQmlComponent component(&m_engine, testFileUrl("worker_include.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QString value("Hello");
@@ -247,7 +264,7 @@ void tst_QQuickWorkerScript::scriptError_onLoad()
QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler);
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QTRY_COMPARE(qquickworkerscript_lastWarning,
testFileUrl("script_error_onLoad.js").toString() + QLatin1String(":3:10: SyntaxError: Expected token `,'"));
@@ -261,7 +278,7 @@ void tst_QQuickWorkerScript::scriptError_onCall()
{
QQmlComponent component(&m_engine, testFileUrl("worker_error_onCall.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler);
QVariant value;
@@ -279,7 +296,7 @@ void tst_QQuickWorkerScript::script_function()
{
QQmlComponent component(&m_engine, testFileUrl("worker_function.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QString value("Hello");
@@ -297,7 +314,7 @@ void tst_QQuickWorkerScript::script_var()
{
QQmlComponent component(&m_engine, testFileUrl("worker_var.qml"));
QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
+ QVERIFY(worker != nullptr);
QString value("Hello");
@@ -311,47 +328,6 @@ void tst_QQuickWorkerScript::script_var()
delete worker;
}
-void tst_QQuickWorkerScript::script_global()
-{
- {
- QQmlComponent component(&m_engine, testFileUrl("worker_global.qml"));
- QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
-
- QString value("Hello");
-
- QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler);
-
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value)));
-
- QTRY_COMPARE(qquickworkerscript_lastWarning,
- testFileUrl("script_global.js").toString() + QLatin1String(":2: Invalid write to global property \"world\""));
-
- qInstallMessageHandler(previousMsgHandler);
-
- qApp->processEvents();
- delete worker;
- }
-
- qquickworkerscript_lastWarning = QString();
-
- {
- QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler);
-
- QQmlComponent component(&m_engine, testFileUrl("worker_global2.qml"));
- QQuickWorkerScript *worker = qobject_cast<QQuickWorkerScript*>(component.create());
- QVERIFY(worker != 0);
-
- QTRY_COMPARE(qquickworkerscript_lastWarning,
- testFileUrl("script_global2.js").toString() + QLatin1String(":1: Invalid write to global property \"world\""));
-
- qInstallMessageHandler(previousMsgHandler);
-
- qApp->processEvents();
- delete worker;
- }
-}
-
// Rapidly create and destroy worker scripts to test resources are being disposed
// in the correct isolate
void tst_QQuickWorkerScript::stressDispose()
diff --git a/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp b/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp
index eab3837245..90b6feee28 100644
--- a/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp
+++ b/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp
@@ -49,7 +49,7 @@ void tst_qtqmlmodules::baseTypes()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("base.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
@@ -60,7 +60,7 @@ void tst_qtqmlmodules::modelsTypes()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("models.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
@@ -71,7 +71,7 @@ void tst_qtqmlmodules::unavailableTypes()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("unavailable.qml"));
QObject *object = component.create();
- QVERIFY(object != 0);
+ QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
delete object;
diff --git a/tests/auto/qml/qv4assembler/data/crash.qml b/tests/auto/qml/qv4assembler/data/crash.qml
new file mode 100644
index 0000000000..dfdb9ceba5
--- /dev/null
+++ b/tests/auto/qml/qv4assembler/data/crash.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 QtQml 2.2
+import Crash 1.0
+
+QtObject {
+ property Crash crash: Crash {
+ id: crash
+ }
+
+ // Recursion makes the crash more reliable
+ // With a single frame the unwinder might guess
+ // the next frame by chance.
+ function recurse(x) {
+ if (x > 32)
+ crash.crash();
+ else
+ recurse(x + 1);
+ }
+
+ property Timer timer: Timer {
+ interval: 10
+ running: true
+ onTriggered: recurse(0)
+ }
+}
+
diff --git a/tests/auto/qml/qv4assembler/qv4assembler.pro b/tests/auto/qml/qv4assembler/qv4assembler.pro
new file mode 100644
index 0000000000..895e241cc9
--- /dev/null
+++ b/tests/auto/qml/qv4assembler/qv4assembler.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_qv4assembler
+
+include (../../shared/util.pri)
+
+macos:CONFIG -= app_bundle
+
+TESTDATA = data/*
+
+SOURCES += tst_qv4assembler.cpp
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
new file mode 100644
index 0000000000..4916cb4cc0
--- /dev/null
+++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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 <util.h>
+
+#include <QtTest/QtTest>
+#include <QtCore/qprocess.h>
+#include <QtCore/qtemporaryfile.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlapplicationengine.h>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+
+class tst_QV4Assembler : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() override;
+ void perfMapFile();
+ void functionTable();
+};
+
+void tst_QV4Assembler::initTestCase()
+{
+ qputenv("QV4_JIT_CALL_THRESHOLD", "0");
+ QQmlDataTest::initTestCase();
+}
+
+void tst_QV4Assembler::perfMapFile()
+{
+#if !defined(Q_OS_LINUX)
+ QSKIP("perf map files are only generated on linux");
+#else
+ const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
+ QProcess process;
+
+ QTemporaryFile infile;
+ QVERIFY(infile.open());
+ infile.write("'use strict'; function foo() { return 42 }; foo();");
+ infile.close();
+
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ environment.insert("QV4_PROFILE_WRITE_PERF_MAP", "1");
+ environment.insert("QV4_JIT_CALL_THRESHOLD", "0");
+
+ process.setProcessEnvironment(environment);
+ process.start(qmljs, QStringList({infile.fileName()}));
+ QVERIFY(process.waitForStarted());
+ const qint64 pid = process.processId();
+ QVERIFY(pid != 0);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+
+ QFile file(QString::fromLatin1("/tmp/perf-%1.map").arg(pid));
+ QVERIFY(file.exists());
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QList<QByteArray> functions;
+ while (!file.atEnd()) {
+ const QByteArray contents = file.readLine();
+ QVERIFY(contents.endsWith('\n'));
+ QList<QByteArray> fields = contents.split(' ');
+ QCOMPARE(fields.length(), 3);
+ bool ok = false;
+ const qulonglong address = fields[0].toULongLong(&ok, 16);
+ QVERIFY(ok);
+ QVERIFY(address > 0);
+ const ulong size = fields[1].toULong(&ok, 16);
+ QVERIFY(ok);
+ QVERIFY(size > 0);
+ functions.append(fields[2]);
+ }
+ QVERIFY(functions.contains("foo\n"));
+#endif
+}
+
+#ifdef Q_OS_WIN
+class Crash : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Crash(QObject *parent = nullptr) : QObject(parent) { }
+ Q_INVOKABLE static void crash();
+};
+
+static bool crashHandlerHit = false;
+
+static LONG WINAPI crashHandler(EXCEPTION_POINTERS*)
+{
+ crashHandlerHit = true;
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+void Crash::crash()
+{
+ SetUnhandledExceptionFilter(crashHandler);
+ RaiseException(EXCEPTION_ACCESS_VIOLATION, 0, 0, nullptr);
+}
+#endif
+
+void tst_QV4Assembler::functionTable()
+{
+#ifndef Q_OS_WIN
+ QSKIP("Function tables only exist on windows.");
+#else
+ QQmlApplicationEngine engine;
+ qmlRegisterType<Crash>("Crash", 1, 0, "Crash");
+ engine.load(testFileUrl("crash.qml"));
+ QTRY_VERIFY(crashHandlerHit);
+#endif
+}
+
+QTEST_MAIN(tst_QV4Assembler)
+
+#include "tst_qv4assembler.moc"
+
diff --git a/tests/auto/qml/qv4identifiertable/qv4identifiertable.pro b/tests/auto/qml/qv4identifiertable/qv4identifiertable.pro
new file mode 100644
index 0000000000..64dc822367
--- /dev/null
+++ b/tests/auto/qml/qv4identifiertable/qv4identifiertable.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase
+TARGET = tst_qv4identifiertable
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qv4identifiertable.cpp
+
+QT += qml qml-private testlib
+
diff --git a/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp
new file mode 100644
index 0000000000..095943cdc7
--- /dev/null
+++ b/tests/auto/qml/qv4identifiertable/tst_qv4identifiertable.cpp
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 basysKom GmbH.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QQmlEngine>
+#include <private/qv4identifiertable_p.h>
+
+class tst_qv4identifiertable : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void sweepFirstEntryInBucket();
+ void sweepCenterEntryInBucket();
+ void sweepLastEntryInBucket();
+ void sweepFirstEntryInSameBucketWithDifferingHash();
+ void dontSweepAcrossBucketBoundaries();
+ void sweepAcrossBucketBoundariesIfFirstBucketFull();
+ void sweepBucketGap();
+};
+
+void tst_qv4identifiertable::sweepFirstEntryInBucket()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/1);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+
+ // All strings go into the same bucket
+ entry1->stringHash = 0;
+ entry2->stringHash = 0;
+ entry3->stringHash = 0;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+ table.asPropertyKey(entry3);
+
+ QCOMPARE(table.size, 3);
+ QCOMPARE(table.alloc, 5);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry3);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+
+ // first entry not marked
+ entry2->setMarkBit();
+ entry3->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry2);
+ QCOMPARE(table.entriesByHash[1], entry3);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+}
+
+void tst_qv4identifiertable::sweepCenterEntryInBucket()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/1);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+
+ // All strings go into the same bucket
+ entry1->stringHash = 0;
+ entry2->stringHash = 0;
+ entry3->stringHash = 0;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+ table.asPropertyKey(entry3);
+
+ QCOMPARE(table.size, 3);
+ QCOMPARE(table.alloc, 5);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry3);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+
+ entry1->setMarkBit();
+ // second entry not marked
+ entry3->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry3);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+}
+
+void tst_qv4identifiertable::sweepLastEntryInBucket()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/1);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+
+ // All strings go into the same bucket
+ entry1->stringHash = 0;
+ entry2->stringHash = 0;
+ entry3->stringHash = 0;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+ table.asPropertyKey(entry3);
+
+ QCOMPARE(table.size, 3);
+ QCOMPARE(table.alloc, 5);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry3);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+
+ entry1->setMarkBit();
+ entry2->setMarkBit();
+ // third entry not marked
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+}
+
+void tst_qv4identifiertable::sweepFirstEntryInSameBucketWithDifferingHash()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/1);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+
+ // First and second entry have differing hash but end up in the
+ // same bucket after modulo alloc.
+ entry1->stringHash = 0;
+ entry2->stringHash = 5;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+
+ QCOMPARE(table.size, 2);
+ QCOMPARE(table.alloc, 5);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+
+ // first entry not marked
+ entry2->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry2);
+ QCOMPARE(table.entriesByHash[1], nullptr);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+}
+
+void tst_qv4identifiertable::dontSweepAcrossBucketBoundaries()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/1);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+
+ // Different buckets for both entries.
+ entry1->stringHash = 0;
+ entry2->stringHash = 1;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+
+ QCOMPARE(table.size, 2);
+ QCOMPARE(table.alloc, 5);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+
+ // first entry not marked
+ entry2->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], nullptr);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], nullptr);
+}
+
+void tst_qv4identifiertable::sweepAcrossBucketBoundariesIfFirstBucketFull()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/3);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+ auto entry4 = engine.newString(QStringLiteral("four"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+ entry4->createHashValue();
+
+ // First, third and fourth entry have the same bucket (after modulo) and
+ // would typically end up in order [entry1, entry3, entry4, entry2]. However
+ // since null termination isn't guaranteed, an insertion order of
+ // entry1, entry2, entry3 and entry4 results in a
+ // table [entry1, entry2, entry3, entry4].
+ entry1->stringHash = 0;
+ entry2->stringHash = 1;
+ entry3->stringHash = 11;
+ entry4->stringHash = 11;
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+ table.asPropertyKey(entry3);
+ table.asPropertyKey(entry4);
+
+ QCOMPARE(table.size, 4);
+ QCOMPARE(table.alloc, 11);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry3);
+ QCOMPARE(table.entriesByHash[3], entry4);
+ QCOMPARE(table.entriesByHash[4], nullptr);
+
+ // first entry not marked
+ entry2->setMarkBit();
+ entry3->setMarkBit();
+ entry4->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry3);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry4);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+}
+
+void tst_qv4identifiertable::sweepBucketGap()
+{
+ QV4::ExecutionEngine engine;
+ QV4::IdentifierTable table(&engine, /*numBits*/3);
+
+ auto entry1 = engine.newString(QStringLiteral("one"));
+ auto entry2 = engine.newString(QStringLiteral("two"));
+ auto entry3 = engine.newString(QStringLiteral("three"));
+ auto entry4 = engine.newString(QStringLiteral("four"));
+
+ entry1->createHashValue();
+ entry2->createHashValue();
+ entry3->createHashValue();
+ entry4->createHashValue();
+
+ // We have two buckets where the second entry in the first bucket
+ // flows into the second bucket. So insertion into the second bucket
+ // will shift by one and create
+ // [entry1][entry2 (would map to first but overflows into second), entry3, entry4]
+ // Garbage collecting the first entry should not only move the second entry
+ // into its own first bucket (where there is space now), it is also critical to
+ // not leave a gap but move the third and fourth entries to the beginning of
+ // their bucket:
+ // [entry2][entry3, entry4]
+ entry1->stringHash = 0; // % 11 -> 0
+ entry2->stringHash = 11; // % 11 -> 0, but ends up at idx 1 because 0 taken
+ entry3->stringHash = 12; // % 11 -> 1, but ends up at idx 2 because 1 taken
+ entry4->stringHash = 12; // % 11 -> 1, but ends up at idx 3 because 1+2 taken
+
+ // trigger insertion
+ table.asPropertyKey(entry1);
+ table.asPropertyKey(entry2);
+ table.asPropertyKey(entry3);
+ table.asPropertyKey(entry4);
+
+ QCOMPARE(table.size, 4);
+ QCOMPARE(table.alloc, 11);
+
+ QCOMPARE(table.entriesByHash[0], entry1);
+ QCOMPARE(table.entriesByHash[1], entry2);
+ QCOMPARE(table.entriesByHash[2], entry3);
+ QCOMPARE(table.entriesByHash[3], entry4);
+ QCOMPARE(table.entriesByHash[4], nullptr);
+
+ // first entry not marked
+ entry2->setMarkBit();
+ entry3->setMarkBit();
+ entry4->setMarkBit();
+
+ table.sweep();
+
+ QCOMPARE(table.entriesByHash[0], entry2);
+ QCOMPARE(table.entriesByHash[1], entry3);
+ QCOMPARE(table.entriesByHash[2], entry4);
+ QCOMPARE(table.entriesByHash[3], nullptr);
+}
+
+QTEST_MAIN(tst_qv4identifiertable)
+
+#include "tst_qv4identifiertable.moc"
diff --git a/tests/auto/qml/qv4mm/data/createdestroy.qml b/tests/auto/qml/qv4mm/data/createdestroy.qml
new file mode 100644
index 0000000000..5a4dd0f520
--- /dev/null
+++ b/tests/auto/qml/qv4mm/data/createdestroy.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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 QtQml 2.2
+
+QtObject {
+ property int creations: 0
+ property int destructions: 0
+ property int iterations: 0
+
+ property Component itemComponent: Component {
+ QtObject {
+ property var parent;
+ Component.onCompleted: ++parent.creations
+ Component.onDestruction: ++parent.destructions
+ }
+ }
+
+ property QtObject item: null;
+ property Timer timer: Timer {
+ running: true
+ repeat: true
+ interval: 1
+ onTriggered: {
+ if (parent.iterations === 100) {
+ item = null;
+ running = false;
+ } else {
+ ++parent.iterations;
+ item = itemComponent.createObject(null, { parent : parent });
+ }
+ gc();
+ }
+ }
+}
diff --git a/tests/auto/qml/qv4mm/qv4mm.pro b/tests/auto/qml/qv4mm/qv4mm.pro
index d9b749af4a..375c5cea75 100644
--- a/tests/auto/qml/qv4mm/qv4mm.pro
+++ b/tests/auto/qml/qv4mm/qv4mm.pro
@@ -1,6 +1,10 @@
CONFIG += testcase
TARGET = tst_qv4mm
-osx:CONFIG -= app_bundle
+include (../../shared/util.pri)
+
+macos:CONFIG -= app_bundle
+
+TESTDATA = data/*
SOURCES += tst_qv4mm.cpp
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index d4ba363d00..578a47d5fa 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -28,29 +28,84 @@
#include <qtest.h>
#include <QQmlEngine>
+#include <QLoggingCategory>
+#include <QQmlComponent>
+
#include <private/qv4mm_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include "../../shared/util.h"
+
+#include <memory>
-class tst_qv4mm : public QObject
+class tst_qv4mm : public QQmlDataTest
{
Q_OBJECT
private slots:
void gcStats();
- void tweaks();
+ void multiWrappedQObjects();
+ void accessParentOnDestruction();
};
void tst_qv4mm::gcStats()
{
- qputenv(QV4_MM_STATS, "1");
+ QLoggingCategory::setFilterRules("qt.qml.gc.*=true");
QQmlEngine engine;
engine.collectGarbage();
}
-void tst_qv4mm::tweaks()
+void tst_qv4mm::multiWrappedQObjects()
+{
+ QV4::ExecutionEngine engine1;
+ QV4::ExecutionEngine engine2;
+ {
+ QObject object;
+ for (int i = 0; i < 10; ++i)
+ QV4::QObjectWrapper::wrap(i % 2 ? &engine1 : &engine2, &object);
+
+ QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+ QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+ {
+ QV4::WeakValue value;
+ value.set(&engine1, QV4::QObjectWrapper::wrap(&engine1, &object));
+ }
+
+ QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1);
+ QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+
+ // Moves the additional WeakValue from m_multiplyWrappedQObjects to
+ // m_pendingFreedObjectWrapperValue. It's still alive after all.
+ engine1.memoryManager->runGC();
+ QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 2);
+
+ // engine2 doesn't own the object as engine1 was the first to wrap it above.
+ // Therefore, no effect here.
+ engine2.memoryManager->runGC();
+ QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+ }
+
+ // Clears m_pendingFreedObjectWrapperValue. Now it's really dead.
+ engine1.memoryManager->runGC();
+ QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+
+ engine2.memoryManager->runGC();
+ QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0);
+}
+
+void tst_qv4mm::accessParentOnDestruction()
{
- qputenv(QV4_MM_MAXBLOCK_SHIFT, "5");
- qputenv(QV4_MM_MAX_CHUNK_SIZE, "65536");
+ QLoggingCategory::setFilterRules("qt.qml.gc.*=false");
QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("createdestroy.qml"));
+ std::unique_ptr<QObject> obj(component.create());
+ QVERIFY(obj);
+ QPointer<QObject> timer = qvariant_cast<QObject *>(obj->property("timer"));
+ QVERIFY(timer);
+ QTRY_VERIFY(!timer->property("running").toBool());
+ QCOMPARE(obj->property("iterations").toInt(), 100);
+ QCOMPARE(obj->property("creations").toInt(), 100);
+ QCOMPARE(obj->property("destructions").toInt(), 100);
}
QTEST_MAIN(tst_qv4mm)
diff --git a/tests/auto/qml/qv4regexp/qv4regexp.pro b/tests/auto/qml/qv4regexp/qv4regexp.pro
new file mode 100644
index 0000000000..f4ab6941f5
--- /dev/null
+++ b/tests/auto/qml/qv4regexp/qv4regexp.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase
+TARGET = tst_qv4regexp
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qv4regexp.cpp
+
+QT += qml qml-private testlib
+
diff --git a/tests/auto/qml/qv4regexp/tst_qv4regexp.cpp b/tests/auto/qml/qv4regexp/tst_qv4regexp.cpp
new file mode 100644
index 0000000000..cbf9c3e47d
--- /dev/null
+++ b/tests/auto/qml/qv4regexp/tst_qv4regexp.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** 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 <qtest.h>
+#include <QtQml/qjsengine.h>
+
+class tst_qv4regexp : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void catchJitFail();
+};
+
+void tst_qv4regexp::catchJitFail()
+{
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(QLatin1String(
+ "var prevString = \" ok\";"
+ "var r = /^(\\s*)(([\\)\\]}]?\\s*)*([\\)\\]]\\s*))?;/.exec(prevString);"
+ "r === null;"), QLatin1String("regexptest.js"));
+ QVERIFY(result.isBool());
+ QVERIFY(result.toBool());
+}
+
+QTEST_MAIN(tst_qv4regexp)
+
+#include "tst_qv4regexp.moc"
diff --git a/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro b/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro
new file mode 100644
index 0000000000..c86365d5ea
--- /dev/null
+++ b/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+CONFIG += parallel_test
+TARGET = tst_qwidgetsinqml
+macos:CONFIG -= app_bundle
+QT += qml widgets testlib gui-private
+SOURCES += tst_qwidgetsinqml.cpp
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp b/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp
new file mode 100644
index 0000000000..c7bbb55474
--- /dev/null
+++ b/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module 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 <QQmlEngine>
+#include <QtQml>
+#include <QWidget>
+
+class tst_QWidgetsInQml : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QWidgetsInQml();
+
+private slots:
+ void instantiateWidget();
+ void instantiateWidgetWithoutParentWidget();
+ void widgetAsDefaultPropertyCollected();
+ void widgetAsDefaultPropertyKept();
+ void widgetAsDefaultPropertyKeptDuringCreation();
+};
+
+static void gc(QQmlEngine &engine)
+{
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+}
+
+// Like QtObject, but with default property
+class QObjectContainer : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("DefaultProperty", "data");
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false);
+public:
+ QObjectContainer()
+ : widgetParent(0)
+ , gcOnAppend(false)
+ {}
+
+ QQmlListProperty<QObject> data() {
+ return QQmlListProperty<QObject>(this, 0, children_append, children_count, children_at, children_clear);
+ }
+
+ static void children_append(QQmlListProperty<QObject> *prop, QObject *o)
+ {
+ QObjectContainer *that = static_cast<QObjectContainer*>(prop->object);
+ that->dataChildren.append(o);
+ QObject::connect(o, SIGNAL(destroyed(QObject*)), prop->object, SLOT(childDestroyed(QObject*)));
+ QWidget *widget = qobject_cast<QWidget*>(o);
+ if (widget && that->widgetParent)
+ widget->setParent(that->widgetParent);
+
+ if (that->gcOnAppend) {
+ QQmlEngine *engine = qmlEngine(that);
+ gc(*engine);
+ }
+ }
+
+ static int children_count(QQmlListProperty<QObject> *prop)
+ {
+ return static_cast<QObjectContainer*>(prop->object)->dataChildren.count();
+ }
+
+ static QObject *children_at(QQmlListProperty<QObject> *prop, int index)
+ {
+ return static_cast<QObjectContainer*>(prop->object)->dataChildren.at(index);
+ }
+
+ static void children_clear(QQmlListProperty<QObject> *prop)
+ {
+ QObjectContainer *that = static_cast<QObjectContainer*>(prop->object);
+ foreach (QObject *c, that->dataChildren)
+ QObject::disconnect(c, SIGNAL(destroyed(QObject*)), that, SLOT(childDestroyed(QObject*)));
+ that->dataChildren.clear();
+ }
+
+ QList<QObject*> dataChildren;
+ QWidget *widgetParent;
+ bool gcOnAppend;
+
+protected slots:
+ void childDestroyed(QObject *child) {
+ dataChildren.removeAll(child);
+ }
+};
+
+class QWidgetContainer : public QObjectContainer
+{
+ Q_OBJECT
+public:
+ QWidgetContainer()
+ {
+ widgetParent = new QWidget;
+ QQmlEngine::setObjectOwnership(widgetParent, QQmlEngine::CppOwnership);
+ }
+ virtual ~QWidgetContainer()
+ {
+ delete widgetParent;
+ widgetParent = 0;
+ }
+};
+
+class QObjectContainerWithGCOnAppend : public QObjectContainer
+{
+ Q_OBJECT
+public:
+ QObjectContainerWithGCOnAppend()
+ {
+ gcOnAppend = true;
+ }
+};
+
+tst_QWidgetsInQml::tst_QWidgetsInQml()
+{
+ qmlRegisterType<QWidget>("Qt.Widgets", 1, 0, "QWidget");
+ qmlRegisterType<QObjectContainer>("Qt.Widgets", 1, 0, "QObjectContainer");
+ qmlRegisterType<QWidgetContainer>("Qt.Widgets", 1, 0, "QWidgetContainer");
+ qmlRegisterType<QObjectContainerWithGCOnAppend>("Qt.Widgets", 1, 0, "QObjectContainerWithGCOnAppend");
+}
+
+void tst_QWidgetsInQml::instantiateWidget()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.Widgets 1.0;\nQWidget { property QWidget child: QWidget { objectName: 'child' } }", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QWidget *rootWidget = qobject_cast<QWidget*>(object.data());
+ QVERIFY(rootWidget != 0);
+ QCOMPARE(rootWidget->children().count(), 1);
+ QWidget *firstChildWidget = qobject_cast<QWidget*>(rootWidget->children().first());
+ QVERIFY(firstChildWidget != 0);
+
+ QWidget *widgetProperty = qvariant_cast<QWidget*>(object->property("child"));
+ QVERIFY(widgetProperty != 0);
+ QCOMPARE(firstChildWidget, widgetProperty);
+ QCOMPARE(firstChildWidget->objectName(), QString("child"));
+}
+
+void tst_QWidgetsInQml::instantiateWidgetWithoutParentWidget()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.Widgets 1.0;\n"
+ "import QtQml 2.0;\n"
+ "QtObject { property QtObject child: QWidget { objectName: 'child' } }", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QPointer<QWidget> widgetProperty = qvariant_cast<QWidget*>(object->property("child"));
+ QVERIFY(!widgetProperty.isNull());
+ QCOMPARE(widgetProperty->objectName(), QString("child"));
+
+ QVERIFY(!widgetProperty->parent());
+ gc(engine);
+ // Don't collect, the property reference should keep it alive
+ QVERIFY(!widgetProperty.isNull());
+}
+
+void tst_QWidgetsInQml::widgetAsDefaultPropertyCollected()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.Widgets 1.0;\n"
+ "import QtQml 2.0;\n"
+ "QObjectContainer {\n"
+ " QWidget {\n"
+ " id: parentLessChild;\n"
+ " objectName: 'child'\n"
+ " }\n"
+ " property var widgetHolder;\n"
+ " Component.onCompleted: {\n"
+ " widgetHolder = parentLessChild;\n"
+ " }\n"
+ "}", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObjectContainer *container = qobject_cast<QObjectContainer*>(object.data());
+ QCOMPARE(container->dataChildren.count(), 1);
+
+ QJSValue holder = qvariant_cast<QJSValue>(object->property("widgetHolder"));
+ QVERIFY(!holder.isNull());
+ gc(engine);
+ QCOMPARE(container->dataChildren.count(), 1);
+
+ holder = QJSValue();
+ object->setProperty("widgetHolder", QVariant::fromValue(holder));
+
+ gc(engine);
+ // The QWidget is without a parent and nobody is referencing it anymore (the children
+ // list in QObjectContainer is weak!), so it should get collected.
+ QCOMPARE(container->dataChildren.count(), 0);
+}
+
+void tst_QWidgetsInQml::widgetAsDefaultPropertyKept()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.Widgets 1.0;\n"
+ "import QtQml 2.0;\n"
+ "QWidgetContainer {\n"
+ " QWidget {\n"
+ " id: parentLessChild;\n"
+ " objectName: 'child'\n"
+ " }\n"
+ " property var widgetHolder;\n"
+ " Component.onCompleted: {\n"
+ " widgetHolder = parentLessChild;\n"
+ " }\n"
+ "}", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QWidgetContainer *container = qobject_cast<QWidgetContainer*>(object.data());
+ QCOMPARE(container->dataChildren.count(), 1);
+
+ QJSValue holder = qvariant_cast<QJSValue>(object->property("widgetHolder"));
+ QVERIFY(!holder.isNull());
+ gc(engine);
+ QCOMPARE(container->dataChildren.count(), 1);
+
+ holder = QJSValue();
+ object->setProperty("widgetHolder", QVariant::fromValue(holder));
+
+ gc(engine);
+ QCOMPARE(container->dataChildren.count(), 1);
+}
+
+void tst_QWidgetsInQml::widgetAsDefaultPropertyKeptDuringCreation()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import Qt.Widgets 1.0;\n"
+ "import QtQml 2.0;\n"
+ "QObjectContainerWithGCOnAppend {\n"
+ " QWidget {\n"
+ " id: parentLessChild;\n"
+ " objectName: 'child'\n"
+ " property var blah;\n" // Ensures that we have a JS wrapper
+ " }\n"
+ "}", QUrl());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObjectContainer *container = qobject_cast<QObjectContainer*>(object.data());
+ QCOMPARE(container->dataChildren.count(), 1);
+
+ gc(engine);
+ QCOMPARE(container->dataChildren.count(), 0);
+
+}
+
+QTEST_MAIN(tst_QWidgetsInQml)
+
+#include "tst_qwidgetsinqml.moc"
diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp
index 55a1f65608..2412ca7f92 100644
--- a/tests/auto/qml/v4misc/tst_v4misc.cpp
+++ b/tests/auto/qml/v4misc/tst_v4misc.cpp
@@ -26,207 +26,177 @@
**
****************************************************************************/
-#include <qhashfunctions.h>
#include <qtest.h>
-
-#define V4_AUTOTEST
-#include <private/qv4ssa_p.h>
+#include <private/qv4instr_moth_p.h>
+#include <private/qv4script_p.h>
class tst_v4misc: public QObject
{
Q_OBJECT
private slots:
- void initTestCase();
+ void tdzOptimizations_data();
+ void tdzOptimizations();
+
+ void parserMisc_data();
+ void parserMisc();
- void rangeSplitting_1();
- void rangeSplitting_2();
- void rangeSplitting_3();
+ void subClassing_data();
+ void subClassing();
- void moveMapping_1();
- void moveMapping_2();
+ void nestingDepth();
};
-using namespace QT_PREPEND_NAMESPACE(QV4::IR);
+void tst_v4misc::tdzOptimizations_data()
+{
+ QTest::addColumn<QString>("scriptToCompile");
+
+ QTest::newRow("access-after-let") << QString("let x; x = 10;");
+ QTest::newRow("access-after-const") << QString("const x = 10; print(x);");
+ QTest::newRow("access-after-let") << QString("for (let x of y) print(x);");
+}
-void tst_v4misc::initTestCase()
+void tst_v4misc::tdzOptimizations()
{
- qSetGlobalQHashSeed(0);
- QCOMPARE(qGlobalQHashSeed(), 0);
+ QFETCH(QString, scriptToCompile);
+
+ QV4::ExecutionEngine v4;
+ QV4::Script script(&v4, nullptr, /*parse as binding*/false, scriptToCompile);
+ script.parse();
+ QVERIFY(!v4.hasException);
+
+ const auto function = script.compilationUnit->unitData()->functionAt(0);
+ const auto *code = function->code();
+ const auto len = function->codeSize;
+ const char *end = code + len;
+
+ const auto decodeInstruction = [&code]() {
+ QV4::Moth::Instr::Type type = QV4::Moth::Instr::Type(static_cast<uchar>(*code));
+ dispatch:
+ switch (type) {
+ case QV4::Moth::Instr::Type::Nop:
+ ++code;
+ type = QV4::Moth::Instr::Type(static_cast<uchar>(*code));
+ goto dispatch;
+ case QV4::Moth::Instr::Type::Nop_Wide: /* wide prefix */
+ ++code;
+ type = QV4::Moth::Instr::Type(0x100 | static_cast<uchar>(*code));
+ goto dispatch;
+
+#define CASE_AND_GOTO_INSTRUCTION(name, nargs, ...) \
+ case QV4::Moth::Instr::Type::name: \
+ MOTH_ADJUST_CODE(qint8, nargs); \
+ break;
+
+#define CASE_AND_GOTO_WIDE_INSTRUCTION(name, nargs, ...) \
+ case QV4::Moth::Instr::Type::name##_Wide: \
+ MOTH_ADJUST_CODE(int, nargs); \
+ type = QV4::Moth::Instr::Type::name; \
+ break;
+
+#define MOTH_DECODE_WITHOUT_ARGS(instr) \
+ INSTR_##instr(CASE_AND_GOTO) \
+ INSTR_##instr(CASE_AND_GOTO_WIDE)
+
+ FOR_EACH_MOTH_INSTR(MOTH_DECODE_WITHOUT_ARGS)
+ }
+ return type;
+ };
+
+ while (code < end) {
+ QV4::Moth::Instr::Type type = decodeInstruction();
+ QVERIFY(type != QV4::Moth::Instr::Type::DeadTemporalZoneCheck);
+ }
+
}
-// split between two ranges
-void tst_v4misc::rangeSplitting_1()
+void tst_v4misc::parserMisc_data()
{
- LifeTimeInterval interval;
- interval.addRange(59, 59);
- interval.addRange(61, 62);
- interval.addRange(64, 64);
- interval.addRange(69, 71);
- interval.validate();
- QCOMPARE(interval.end(), 71);
-
- LifeTimeInterval newInterval = interval.split(66, 70);
- interval.validate();
- newInterval.validate();
- QVERIFY(newInterval.isSplitFromInterval());
-
- QCOMPARE(interval.ranges().size(), 3);
- QCOMPARE(interval.ranges()[0].start, 59);
- QCOMPARE(interval.ranges()[0].end, 59);
- QCOMPARE(interval.ranges()[1].start, 61);
- QCOMPARE(interval.ranges()[1].end, 62);
- QCOMPARE(interval.ranges()[2].start, 64);
- QCOMPARE(interval.ranges()[2].end, 64);
- QCOMPARE(interval.end(), 70);
-
- QCOMPARE(newInterval.ranges().size(), 1);
- QCOMPARE(newInterval.ranges()[0].start, 70);
- QCOMPARE(newInterval.ranges()[0].end, 71);
- QCOMPARE(newInterval.end(), 71);
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("8[++i][+++i]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
+ QTest::newRow("`a${1++}`") << QString("ReferenceError: Invalid left-hand side expression in postfix operation");
+ QTest::newRow("for (var f in ++!binaryMathg) ;") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
+ QTest::newRow("for (va() in obj) {}") << QString("ReferenceError: Invalid left-hand side expression for 'in' expression");
+ QTest::newRow("[1]=7[A=8=9]") << QString("ReferenceError: left-hand side of assignment operator is not an lvalue");
+ QTest::newRow("var asmvalsLen = asmvals{{{{{ngth}}}}};") << QString("SyntaxError: Expected token `;'");
+ QTest::newRow("T||9[---L6i]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
+ QTest::newRow("a?b:[---Hi]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
+ QTest::newRow("[``]=1") << QString("ReferenceError: Binding target is not a reference.");
}
-// split in the middle of a range
-void tst_v4misc::rangeSplitting_2()
+void tst_v4misc::parserMisc()
{
- LifeTimeInterval interval;
- interval.addRange(59, 59);
- interval.addRange(61, 64);
- interval.addRange(69, 71);
- interval.validate();
- QCOMPARE(interval.end(), 71);
-
- LifeTimeInterval newInterval = interval.split(62, 64);
- interval.validate();
- newInterval.validate();
- QVERIFY(newInterval.isSplitFromInterval());
-
- QCOMPARE(interval.ranges().size(), 2);
- QCOMPARE(interval.ranges()[0].start, 59);
- QCOMPARE(interval.ranges()[0].end, 59);
- QCOMPARE(interval.ranges()[1].start, 61);
- QCOMPARE(interval.ranges()[1].end, 62);
- QCOMPARE(interval.end(), 64);
-
- QCOMPARE(newInterval.ranges().size(), 2);
- QCOMPARE(newInterval.ranges()[0].start, 64);
- QCOMPARE(newInterval.ranges()[0].end, 64);
- QCOMPARE(newInterval.ranges()[1].start, 69);
- QCOMPARE(newInterval.ranges()[1].end, 71);
- QCOMPARE(newInterval.end(), 71);
+ QFETCH(QString, error);
+
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(QString::fromUtf8(QTest::currentDataTag()));
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), error);
}
-// split in the middle of a range, and let it never go back to active again
-void tst_v4misc::rangeSplitting_3()
+void tst_v4misc::subClassing_data()
{
- LifeTimeInterval interval;
- interval.addRange(59, 59);
- interval.addRange(61, 64);
- interval.addRange(69, 71);
- interval.validate();
- QCOMPARE(interval.end(), 71);
-
- LifeTimeInterval newInterval = interval.split(64, LifeTimeInterval::InvalidPosition);
- interval.validate();
- newInterval.validate();
- QVERIFY(!newInterval.isValid());
-
- QCOMPARE(interval.ranges().size(), 2);
- QCOMPARE(interval.ranges()[0].start, 59);
- QCOMPARE(interval.ranges()[0].end, 59);
- QCOMPARE(interval.ranges()[1].start, 61);
- QCOMPARE(interval.ranges()[1].end, 64);
- QCOMPARE(interval.end(), 71);
+ QTest::addColumn<QString>("script");
+
+ QString code(
+ "class Foo extends %1 {"
+ " constructor() { super(); this.reset(); }"
+ " reset() { }"
+ "}"
+ "new Foo();");
+
+
+ QTest::newRow("Array") << code.arg("Array");
+ QTest::newRow("Boolean") << code.arg("Boolean");
+ QTest::newRow("Date") << code.arg("Date");
+ QTest::newRow("Function") << code.arg("Function");
+ QTest::newRow("Number") << code.arg("Number");
+ QTest::newRow("Map") << code.arg("Map");
+ QTest::newRow("Promise") << QString(
+ "class Foo extends Promise {"
+ " constructor() { super(Function()); this.reset(); }"
+ " reset() { }"
+ "}"
+ "new Foo();");
+ QTest::newRow("RegExp") << code.arg("RegExp");
+ QTest::newRow("Set") << code.arg("Set");
+ QTest::newRow("String") << code.arg("String");
+ QTest::newRow("WeakMap") << code.arg("WeakMap");
+ QTest::newRow("WeakSet") << code.arg("WeakSet");
}
-void tst_v4misc::moveMapping_1()
+void tst_v4misc::subClassing()
{
- Temp fp2(DoubleType, Temp::PhysicalRegister, 2);
- Temp fp3(DoubleType, Temp::PhysicalRegister, 3);
- Temp fp4(DoubleType, Temp::PhysicalRegister, 4);
- Temp fp5(DoubleType, Temp::PhysicalRegister, 5);
-
- MoveMapping mapping;
- mapping.add(&fp2, &fp3);
- mapping.add(&fp2, &fp4);
- mapping.add(&fp2, &fp5);
- mapping.add(&fp3, &fp2);
-
- mapping.order();
-// mapping.dump();
-
- QCOMPARE(mapping._moves.size(), 3);
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp4, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp5, false)));
- QVERIFY(mapping._moves.last() == MoveMapping::Move(&fp2, &fp3, true) ||
- mapping._moves.last() == MoveMapping::Move(&fp3, &fp2, true));
+ QFETCH(QString, script);
+
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(script);
+ QVERIFY(!result.isError());
}
-void tst_v4misc::moveMapping_2()
+void tst_v4misc::nestingDepth()
{
- Temp fp1(DoubleType, Temp::PhysicalRegister, 1);
- Temp fp2(DoubleType, Temp::PhysicalRegister, 2);
- Temp fp3(DoubleType, Temp::PhysicalRegister, 3);
- Temp fp4(DoubleType, Temp::PhysicalRegister, 4);
- Temp fp5(DoubleType, Temp::PhysicalRegister, 5);
- Temp fp6(DoubleType, Temp::PhysicalRegister, 6);
- Temp fp7(DoubleType, Temp::PhysicalRegister, 7);
- Temp fp8(DoubleType, Temp::PhysicalRegister, 8);
- Temp fp9(DoubleType, Temp::PhysicalRegister, 9);
- Temp fp10(DoubleType, Temp::PhysicalRegister, 10);
- Temp fp11(DoubleType, Temp::PhysicalRegister, 11);
- Temp fp12(DoubleType, Temp::PhysicalRegister, 12);
- Temp fp13(DoubleType, Temp::PhysicalRegister, 13);
-
- MoveMapping mapping;
- mapping.add(&fp2, &fp1);
- mapping.add(&fp2, &fp3);
- mapping.add(&fp3, &fp2);
- mapping.add(&fp3, &fp4);
-
- mapping.add(&fp9, &fp8);
- mapping.add(&fp8, &fp7);
- mapping.add(&fp7, &fp6);
- mapping.add(&fp7, &fp5);
-
- mapping.add(&fp10, &fp11);
- mapping.add(&fp11, &fp12);
- mapping.add(&fp12, &fp13);
- mapping.add(&fp13, &fp10);
-
- mapping.order();
-// mapping.dump();
-
- QCOMPARE(mapping._moves.size(), 10);
-
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp1, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp3, &fp4, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp7, &fp6, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp7, &fp5, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp8, &fp7, false)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp9, &fp8, false)));
-
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp2, &fp3, true)) ||
- mapping._moves.contains(MoveMapping::Move(&fp3, &fp2, true)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp10, &fp13, true)) ||
- mapping._moves.contains(MoveMapping::Move(&fp13, &fp10, true)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp12, &fp13, true)) ||
- mapping._moves.contains(MoveMapping::Move(&fp13, &fp12, true)));
- QVERIFY(mapping._moves.contains(MoveMapping::Move(&fp12, &fp11, true)) ||
- mapping._moves.contains(MoveMapping::Move(&fp11, &fp12, true)));
-
- QVERIFY(!mapping._moves.at(0).needsSwap);
- QVERIFY(!mapping._moves.at(1).needsSwap);
- QVERIFY(!mapping._moves.at(2).needsSwap);
- QVERIFY(!mapping._moves.at(3).needsSwap);
- QVERIFY(!mapping._moves.at(4).needsSwap);
- QVERIFY(!mapping._moves.at(5).needsSwap);
- QVERIFY(mapping._moves.at(6).needsSwap);
- QVERIFY(mapping._moves.at(7).needsSwap);
- QVERIFY(mapping._moves.at(8).needsSwap);
- QVERIFY(mapping._moves.at(9).needsSwap);
+ { // left recursive
+ QString s(40000, '`');
+
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(s);
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), "SyntaxError: Maximum statement or expression depth exceeded");
+ }
+
+ { // right recursive
+ QString s(200000, '-');
+ s += "\nd";
+
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(s);
+ QVERIFY(result.isError());
+ QCOMPARE(result.toString(), "SyntaxError: Maximum statement or expression depth exceeded");
+ }
}
-QTEST_MAIN(tst_v4misc)
+QTEST_MAIN(tst_v4misc);
#include "tst_v4misc.moc"
diff --git a/tests/auto/qml/v4traced/tst_v4traced.cpp b/tests/auto/qml/v4traced/tst_v4traced.cpp
new file mode 100644
index 0000000000..f82cc0ed5e
--- /dev/null
+++ b/tests/auto/qml/v4traced/tst_v4traced.cpp
@@ -0,0 +1,325 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..cbc8f38046
--- /dev/null
+++ b/tests/auto/qml/v4traced/v4traced.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_v4traced
+macos:CONFIG -= app_bundle
+QT += core-private qml-private testlib
+SOURCES += tst_v4traced.cpp